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
- Variables
- func GenerateSecureID(prefix string) (string, error)
- func RequireAgentAuth(auth *Auth, audit AuditLogger) func(http.Handler) http.Handler
- func RequireOperatorAuth(auth *Auth, audit AuditLogger) func(http.Handler) http.Handler
- func RequireStagerAuth(validator StagerValidator, audit AuditLogger) func(http.Handler) http.Handler
- type AgentClaims
- type AgentToken
- type AuditLogger
- type Auth
- func (a *Auth) AddOperator(name string, publicKey []byte) error
- func (a *Auth) CleanupExpired() int
- func (a *Auth) CreateChallenge(operatorID, fingerprint string) ([]byte, error)
- func (a *Auth) GenerateAgentToken(agentID, sessionID string) (string, error)
- func (a *Auth) GenerateToken(operatorID, sessionID string) (string, error)
- func (a *Auth) GetOperator(name string) (*Operator, error)
- func (a *Auth) GetOperatorByFingerprint(fingerprint string) (*Operator, error)
- func (a *Auth) ListOperators() []*Operator
- func (a *Auth) LoadAuthorizedKeys(r io.Reader) error
- func (a *Auth) LoadAuthorizedKeysFile(path string) error
- func (a *Auth) ReloadAuthorizedKeys() error
- func (a *Auth) RevokeAgentToken(token string) bool
- func (a *Auth) RevokeToken(token string) bool
- func (a *Auth) StartAutoReload(interval time.Duration)
- func (a *Auth) StopAutoReload()
- func (a *Auth) ValidateAgentToken(token string) (*AgentClaims, error)
- func (a *Auth) ValidateToken(tokenValue string) (*Claims, error)
- func (a *Auth) VerifyChallenge(nonce, signature []byte) (string, error)
- type Challenge
- type Claims
- type Config
- type ContextKey
- type Operator
- type SecurityEvent
- type StagerValidator
- type StructuredAuditLogger
- type Token
Constants ¶
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" )
const ( // PrefixAgent is the prefix for agent tokens. PrefixAgent = "agt_" // PrefixStager is the prefix for stager IDs. PrefixStager = "stg_" )
Variables ¶
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 ¶
GenerateSecureID generates a secure random ID with the given prefix. Format: prefix + 11 alphanumeric chars (~65 bits of entropy).
func RequireAgentAuth ¶
RequireAgentAuth validates agent token via X-Agent-Token header.
func RequireOperatorAuth ¶
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 ¶
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 (*Auth) AddOperator ¶
AddOperator adds a new operator with the given name and public key.
func (*Auth) CleanupExpired ¶
CleanupExpired removes expired challenges, tokens, and agent tokens.
func (*Auth) CreateChallenge ¶
CreateChallenge creates a new authentication challenge for an operator.
func (*Auth) GenerateAgentToken ¶
GenerateAgentToken creates a new agent authentication token.
func (*Auth) GenerateToken ¶
GenerateToken generates a session token for an operator (for testing).
func (*Auth) GetOperator ¶
GetOperator returns an operator by name.
func (*Auth) GetOperatorByFingerprint ¶
GetOperatorByFingerprint returns an operator by their public key fingerprint.
func (*Auth) ListOperators ¶
ListOperators returns all registered operators.
func (*Auth) LoadAuthorizedKeys ¶
LoadAuthorizedKeys loads operators from a reader. Format: <operator_name> <key_type> <public_key> <comment> Example: alice ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... alice@laptop
func (*Auth) LoadAuthorizedKeysFile ¶
LoadAuthorizedKeysFile loads operators from an authorized_keys file.
func (*Auth) ReloadAuthorizedKeys ¶
ReloadAuthorizedKeys reloads operators from the authorized_keys file.
func (*Auth) RevokeAgentToken ¶
RevokeAgentToken revokes an agent token.
func (*Auth) RevokeToken ¶
RevokeToken revokes a session token.
func (*Auth) StartAutoReload ¶
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 ¶
ValidateToken validates a session token and returns claims. Accepts either a dynamic session token (smk_...) or a static shared secret.
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)