auth

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package auth provides SSH challenge-response authentication for Kitchen operators. Operators register SSH public keys (like authorized_keys), then prove identity by signing a random challenge with their private key (via SSH agent).

Index

Constants

View Source
const (
	EventAuthFailure       = "auth_failure"
	EventAuthzFailure      = "authz_failure"
	EventStagerNotFound    = "stager_not_found"
	EventStagerExpired     = "stager_expired"
	EventAgentTokenInvalid = "agent_token_invalid"
	EventSessionMismatch   = "session_mismatch"

	PrincipalOperator = "operator"
	PrincipalAgent    = "agent"
	PrincipalStager   = "stager"
	PrincipalUnknown  = "unknown"
)
View Source
const (
	// PrefixAgent is the prefix for agent tokens.
	PrefixAgent = "agt_"
	// PrefixStager is the prefix for stager IDs.
	PrefixStager = "stg_"
)

Variables

View Source
var (
	// ErrInvalidToken indicates the session token is invalid or expired.
	ErrInvalidToken = errors.New("invalid or expired token")

	// ErrOperatorNotFound indicates the operator is not in authorized_keys.
	ErrOperatorNotFound = errors.New("operator not found")

	// ErrInvalidChallenge indicates the challenge is invalid or expired.
	ErrInvalidChallenge = errors.New("invalid or expired challenge")

	// ErrInvalidSignature indicates the signature verification failed.
	ErrInvalidSignature = errors.New("invalid signature")

	// ErrKeyMismatch indicates the public key fingerprint doesn't match.
	ErrKeyMismatch = errors.New("public key fingerprint mismatch")

	// ErrInvalidAgentToken indicates the agent token is invalid or expired.
	ErrInvalidAgentToken = errors.New("invalid or expired agent token")
)

Functions

func GenerateSecureID

func GenerateSecureID(prefix string) (string, error)

GenerateSecureID generates a secure random ID with the given prefix. Format: prefix + 11 alphanumeric chars (~65 bits of entropy).

func RequireAgentAuth

func RequireAgentAuth(auth *Auth, audit AuditLogger) func(http.Handler) http.Handler

RequireAgentAuth validates agent token via X-Agent-Token header.

func RequireOperatorAuth

func RequireOperatorAuth(auth *Auth, audit AuditLogger) func(http.Handler) http.Handler

RequireOperatorAuth validates operator JWT and logs failures to audit.

func RequireStagerAuth

func RequireStagerAuth(validator StagerValidator, audit AuditLogger) func(http.Handler) http.Handler

RequireStagerAuth validates stager ID from URL path. Returns opaque 401 for all failures to prevent information leakage.

Types

type AgentClaims

type AgentClaims struct {
	AgentID   string `json:"agent_id"`
	SessionID string `json:"session_id"`
}

AgentClaims represents the authenticated agent context.

type AgentToken

type AgentToken struct {
	Token     string
	AgentID   string
	SessionID string
	CreatedAt time.Time
	ExpiresAt time.Time
}

AgentToken represents an active agent authentication token.

type AuditLogger

type AuditLogger interface {
	LogSecurityEvent(event SecurityEvent)
}

type Auth

type Auth struct {
	// contains filtered or unexported fields
}

Auth manages operator authentication via SSH challenge-response or static token.

func New

func New(config Config) (*Auth, error)

New creates a new Auth instance.

func (*Auth) AddOperator

func (a *Auth) AddOperator(name string, publicKey []byte) error

AddOperator adds a new operator with the given name and public key.

func (*Auth) CleanupExpired

func (a *Auth) CleanupExpired() int

CleanupExpired removes expired challenges, tokens, and agent tokens.

func (*Auth) CreateChallenge

func (a *Auth) CreateChallenge(operatorID, fingerprint string) ([]byte, error)

CreateChallenge creates a new authentication challenge for an operator.

func (*Auth) GenerateAgentToken

func (a *Auth) GenerateAgentToken(agentID, sessionID string) (string, error)

GenerateAgentToken creates a new agent authentication token.

func (*Auth) GenerateToken

func (a *Auth) GenerateToken(operatorID, sessionID string) (string, error)

GenerateToken generates a session token for an operator (for testing).

func (*Auth) GetOperator

func (a *Auth) GetOperator(name string) (*Operator, error)

GetOperator returns an operator by name.

func (*Auth) GetOperatorByFingerprint

func (a *Auth) GetOperatorByFingerprint(fingerprint string) (*Operator, error)

GetOperatorByFingerprint returns an operator by their public key fingerprint.

func (*Auth) ListOperators

func (a *Auth) ListOperators() []*Operator

ListOperators returns all registered operators.

func (*Auth) LoadAuthorizedKeys

func (a *Auth) LoadAuthorizedKeys(r io.Reader) error

LoadAuthorizedKeys loads operators from a reader. Format: <operator_name> <key_type> <public_key> <comment> Example: alice ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... alice@laptop

func (*Auth) LoadAuthorizedKeysFile

func (a *Auth) LoadAuthorizedKeysFile(path string) error

LoadAuthorizedKeysFile loads operators from an authorized_keys file.

func (*Auth) ReloadAuthorizedKeys

func (a *Auth) ReloadAuthorizedKeys() error

ReloadAuthorizedKeys reloads operators from the authorized_keys file.

func (*Auth) RevokeAgentToken

func (a *Auth) RevokeAgentToken(token string) bool

RevokeAgentToken revokes an agent token.

func (*Auth) RevokeToken

func (a *Auth) RevokeToken(token string) bool

RevokeToken revokes a session token.

func (*Auth) StartAutoReload

func (a *Auth) StartAutoReload(interval time.Duration)

StartAutoReload starts a goroutine that reloads authorized_keys periodically. Polls at fastInterval when no operators are loaded, then switches to interval.

func (*Auth) StopAutoReload

func (a *Auth) StopAutoReload()

StopAutoReload stops the auto-reload goroutine.

func (*Auth) ValidateAgentToken

func (a *Auth) ValidateAgentToken(token string) (*AgentClaims, error)

ValidateAgentToken validates an agent token and returns claims.

func (*Auth) ValidateToken

func (a *Auth) ValidateToken(tokenValue string) (*Claims, error)

ValidateToken validates a session token and returns claims. Accepts either a dynamic session token (smk_...) or a static shared secret.

func (*Auth) VerifyChallenge

func (a *Auth) VerifyChallenge(nonce, signature []byte) (string, error)

VerifyChallenge verifies a signed challenge and returns a session token.

type Challenge

type Challenge struct {
	Nonce       []byte
	OperatorID  string
	Fingerprint string
	CreatedAt   time.Time
	ExpiresAt   time.Time
}

Challenge represents a pending authentication challenge.

type Claims

type Claims struct {
	OperatorID string `json:"operator_id"`
	SessionID  string `json:"session_id,omitempty"`
}

Claims represents the authenticated operator context. Compatible with existing middleware.

type Config

type Config struct {
	// AuthorizedKeysPath is the path to the authorized_keys file.
	// Format: <operator_name> <key_type> <public_key> <comment>
	AuthorizedKeysPath string

	// AuthorizedKeysData is the raw authorized_keys content (alternative to path).
	AuthorizedKeysData string

	// StaticToken is an optional shared secret token for quickstart/E2E mode.
	// When set, operators can authenticate with this token directly via Bearer auth.
	// Must be 64 hex characters (256 bits of entropy).
	StaticToken string

	// TokenExpiry is how long operator session tokens are valid. Default: 24 hours.
	TokenExpiry time.Duration

	// AgentTokenExpiry is how long agent tokens are valid. Default: 24 hours.
	AgentTokenExpiry time.Duration

	// ChallengeExpiry is how long challenges are valid. Default: 5 minutes.
	ChallengeExpiry time.Duration
}

Config holds authentication configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

type ContextKey

type ContextKey string

ContextKey is the type for context keys.

const (
	// ClaimsKey is the context key for JWT claims.
	ClaimsKey ContextKey = "claims"
	// AgentClaimsKey is the context key for agent claims.
	AgentClaimsKey ContextKey = "agent_claims"
	// AgentTokenHeader is the HTTP header for agent authentication.
	AgentTokenHeader = "X-Agent-Token"
)

type Operator

type Operator struct {
	Name        string
	PublicKey   ssh.PublicKey
	Fingerprint string // SHA256 fingerprint
	Comment     string
}

Operator represents an authorized operator with their SSH public key.

type SecurityEvent

type SecurityEvent struct {
	Timestamp   time.Time `json:"timestamp"`
	EventType   string    `json:"event_type"`
	ClientIP    string    `json:"client_ip"`
	Path        string    `json:"path"`
	Method      string    `json:"method"`
	Principal   string    `json:"principal"`
	PrincipalID string    `json:"principal_id,omitempty"`
	SessionID   string    `json:"session_id,omitempty"`
	Reason      string    `json:"reason"`
	UserAgent   string    `json:"user_agent,omitempty"`
}

func NewSecurityEventFromRequest

func NewSecurityEventFromRequest(r *http.Request, eventType, principal, reason string) SecurityEvent

type StagerValidator

type StagerValidator interface {
	ValidateStager(id string) (sessionID string, expired bool, exists bool)
}

StagerValidator validates stager IDs. Implemented by StagerStore.

type StructuredAuditLogger

type StructuredAuditLogger struct {
	// contains filtered or unexported fields
}

func NewStructuredAuditLogger

func NewStructuredAuditLogger(logger *slog.Logger) *StructuredAuditLogger

func (*StructuredAuditLogger) LogSecurityEvent

func (l *StructuredAuditLogger) LogSecurityEvent(event SecurityEvent)

type Token

type Token struct {
	Value      string
	OperatorID string
	CreatedAt  time.Time
	ExpiresAt  time.Time
}

Token represents an active session token.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL