auth

package
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package auth provides authentication and authorization interfaces and implementations for Kubernetes-based REST API services.

Authority: DD-AUTH-014 (Middleware-Based SAR Authentication)

This package implements a secure, testable authentication/authorization framework using dependency injection. The interfaces allow for: - Production: Real Kubernetes TokenReview + SubjectAccessReview (SAR) - Integration tests: Mock implementations (auth still enforced) - E2E tests: Real Kubernetes APIs in Kind clusters

Security: No runtime disable flags - auth is always enforced via interface implementations.

Index

Constants

This section is empty.

Variables

View Source
var ErrTokenInvalid = errors.New("token not authenticated")

ErrTokenInvalid indicates the token was presented but rejected by the authenticator (e.g., expired, malformed, or not recognized). This is distinct from API call failures. Middleware uses this to return 401 instead of 500.

Functions

func GetUserFromContext

func GetUserFromContext(ctx context.Context) string

GetUserFromContext extracts the authenticated user identity from the request context. Returns empty string if user is not in context.

Types

type AuthTransport

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

AuthTransport is an http.RoundTripper that handles authentication for DataStorage API calls.

Behavior: - Reads token from /var/run/secrets/kubernetes.io/serviceaccount/token - Used by: ALL services in production, E2E, and integration (with mounted tokens) - Injects: Authorization: Bearer <token> - Caching: 5-minute cache to avoid filesystem reads on every request - Graceful degradation: If token file missing, request proceeds without auth

Thread Safety: - RoundTrip() is thread-safe (clones request, no shared state mutation) - Token caching uses sync.RWMutex for concurrent access

DD-AUTH-005: This transport enables all 7 Go services to authenticate with DataStorage without modifying the OpenAPI-generated client code.

ZERO TEST LOGIC: This production code contains no test-specific modes. For integration tests (mock user headers), use internal/mocks.NewMockUserTransport().

func NewServiceAccountTransport

func NewServiceAccountTransport() *AuthTransport

NewServiceAccountTransport creates a transport that reads tokens from the ServiceAccount filesystem. Used by services in E2E/Production environments.

Token Path: /var/run/secrets/kubernetes.io/serviceaccount/token Caching: 5-minute cache to reduce filesystem reads Injects: Authorization: Bearer <token>

Usage:

transport := auth.NewServiceAccountTransport()
httpClient := &http.Client{Transport: transport}
dsClient := datastorage.NewClientWithResponses(url, datastorage.WithHTTPClient(httpClient))

DD-AUTH-005: This is the PRIMARY transport for production and E2E services. All 7 Go services use this via audit.NewOpenAPIClientAdapter().

func NewServiceAccountTransportWithBase

func NewServiceAccountTransportWithBase(base http.RoundTripper) *AuthTransport

NewServiceAccountTransportWithBase creates a ServiceAccount transport with custom base transport. Useful for testing or custom transport configuration (e.g., custom timeouts, TLS).

func (*AuthTransport) RoundTrip

func (t *AuthTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper. Injects authentication headers based on the transport mode before forwarding the request.

Thread Safety: Safe for concurrent use (clones request to avoid mutation).

DD-AUTH-005: This method is called automatically by the http.Client for every request. Services using the OpenAPI-generated client don't need to know about authentication.

type Authenticator

type Authenticator interface {
	// ValidateToken checks if the token is valid and returns the user identity.
	//
	// Parameters:
	//   - ctx: Request context (may include timeout)
	//   - token: Bearer token string (without "Bearer " prefix)
	//
	// Returns:
	//   - string: User identity (e.g., "system:serviceaccount:namespace:sa-name")
	//   - error: Token validation failure
	//
	// Errors:
	//   - Token is invalid or expired
	//   - Token cannot be authenticated
	//   - Kubernetes API call fails
	ValidateToken(ctx context.Context, token string) (string, error)
}

Authenticator validates tokens and returns user identity.

Implementations:

  • K8sAuthenticator: Uses Kubernetes TokenReview API (production/E2E)
  • MockAuthenticator: Test double for integration tests

Example usage:

authenticator := auth.NewK8sAuthenticator(k8sClient)
user, err := authenticator.ValidateToken(ctx, "Bearer eyJhbGc...")
if err != nil {
    // Return 401 Unauthorized
}

type Authorizer

type Authorizer interface {
	// CheckAccess verifies if the user has the required permissions.
	//
	// This method performs a Kubernetes SubjectAccessReview (SAR) check to determine
	// if the specified user can perform the given verb on the specified resource.
	//
	// Parameters:
	//   - ctx: Request context (may include timeout)
	//   - user: User identity from token validation (e.g., "system:serviceaccount:ns:sa")
	//   - namespace: Kubernetes namespace for the resource
	//   - resource: Resource type (e.g., "services", "pods", "deployments")
	//   - resourceName: Specific resource name (e.g., "data-storage-service")
	//   - verb: RBAC verb (e.g., "create", "get", "list", "update", "delete")
	//
	// Returns:
	//   - bool: true if access is allowed, false if denied
	//   - error: SAR API call failure (not authorization denial)
	//
	// Errors:
	//   - Kubernetes API call fails
	//   - Invalid parameters
	//   - Network timeout
	//
	// Note: Authorization denial (user lacks permissions) returns (false, nil), not an error.
	CheckAccess(ctx context.Context, user, namespace, resource, resourceName, verb string) (bool, error)
}

Authorizer checks if a user has permission to perform an action on a resource.

Implementations:

  • K8sAuthorizer: Uses Kubernetes SubjectAccessReview (SAR) API (production/E2E)
  • MockAuthorizer: Test double for integration tests

Example usage:

authorizer := auth.NewK8sAuthorizer(k8sClient)
allowed, err := authorizer.CheckAccess(
    ctx,
    "system:serviceaccount:kubernaut-system:datastorage",
    "kubernaut-system",     // namespace
    "services",             // resource
    "data-storage-service", // resourceName
    "create",               // verb
)
if err != nil || !allowed {
    // Return 403 Forbidden
}

type ContextKey

type ContextKey string

ContextKey is the type for context keys used in the auth middleware.

const (
	// UserContextKey is the context key for the authenticated user identity.
	UserContextKey ContextKey = "user"
)

type K8sAuthenticator

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

K8sAuthenticator implements Authenticator using Kubernetes TokenReview API.

This implementation validates ServiceAccount tokens by making TokenReview API calls to the Kubernetes API server. It is suitable for production and E2E environments.

Authority: DD-AUTH-014

func NewK8sAuthenticator

func NewK8sAuthenticator(client kubernetes.Interface) *K8sAuthenticator

NewK8sAuthenticator creates a new Kubernetes-based authenticator.

Example:

config, _ := rest.InClusterConfig()
clientset, _ := kubernetes.NewForConfig(config)
authenticator := auth.NewK8sAuthenticator(clientset)

func (*K8sAuthenticator) ValidateToken

func (a *K8sAuthenticator) ValidateToken(ctx context.Context, token string) (string, error)

ValidateToken validates a ServiceAccount token using Kubernetes TokenReview API.

This method: 1. Creates a TokenReview request with the provided token 2. Sends the request to the Kubernetes API server 3. Returns the authenticated user identity if valid

Authority: https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-review-v1/

type K8sAuthorizer

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

K8sAuthorizer implements Authorizer using Kubernetes SubjectAccessReview (SAR) API.

This implementation checks RBAC permissions by making SAR API calls to the Kubernetes API server. It is suitable for production and E2E environments.

Authority: DD-AUTH-014

func NewK8sAuthorizer

func NewK8sAuthorizer(client kubernetes.Interface) *K8sAuthorizer

NewK8sAuthorizer creates a new Kubernetes-based authorizer.

Example:

config, _ := rest.InClusterConfig()
clientset, _ := kubernetes.NewForConfig(config)
authorizer := auth.NewK8sAuthorizer(clientset)

func (*K8sAuthorizer) CheckAccess

func (a *K8sAuthorizer) CheckAccess(ctx context.Context, user, namespace, resource, resourceName, verb string) (bool, error)

CheckAccess checks if a user has permission using Kubernetes SubjectAccessReview API.

This method: 1. Creates a SubjectAccessReview request with the provided parameters 2. Sends the request to the Kubernetes API server 3. Returns true if the user is allowed, false if denied

Authority: https://kubernetes.io/docs/reference/kubernetes-api/authorization-resources/subject-access-review-v1/

type Middleware

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

Middleware provides authentication and authorization for HTTP requests.

Authority: DD-AUTH-014 (Middleware-Based SAR Authentication)

This middleware implements a secure, testable auth framework using dependency injection: 1. Extracts Bearer token from Authorization header 2. Validates token using Authenticator interface (TokenReview) 3. Checks authorization using Authorizer interface (SAR) 4. Injects user identity into request context (for audit logging) 5. Injects X-Auth-Request-User header (for SOC2 user attribution)

Security: No runtime disable flags — auth is always enforced via interface implementations.

Used by: DataStorage service (BR-DS-*), Gateway service (BR-GATEWAY-036/037)

func NewMiddleware

func NewMiddleware(
	authenticator Authenticator,
	authorizer Authorizer,
	config MiddlewareConfig,
	logger logr.Logger,
) *Middleware

NewMiddleware creates a new authentication middleware with dependency injection.

Example (Production):

k8sClient, _ := kubernetes.NewForConfig(config)
authenticator := auth.NewK8sAuthenticator(k8sClient)
authorizer := auth.NewK8sAuthorizer(k8sClient)
mw := auth.NewMiddleware(
    authenticator,
    authorizer,
    auth.MiddlewareConfig{
        Namespace:    "kubernaut-system",
        Resource:     "services",
        ResourceName: "gateway-service",
        Verb:         "create",
    },
    logger,
)

func (*Middleware) Handler

func (m *Middleware) Handler(next http.Handler) http.Handler

Handler returns a chi-compatible middleware handler.

HTTP Status Codes (Authority: DD-AUTH-013): - 401 Unauthorized: Missing/invalid/expired token - 403 Forbidden: Valid token but insufficient RBAC permissions - 500 Internal Server Error: TokenReview/SAR API call failures

type MiddlewareConfig

type MiddlewareConfig struct {
	// Namespace is the Kubernetes namespace for the SAR check
	Namespace string

	// Resource is the Kubernetes resource type (e.g., "services", "pods")
	Resource string

	// ResourceName is the specific resource name (e.g., "data-storage-service", "gateway-service")
	ResourceName string

	// Verb is the RBAC verb to check (e.g., "create", "get", "list", "update", "delete")
	// Authority: DD-AUTH-011 (Granular RBAC with SAR verb mapping)
	Verb string
}

MiddlewareConfig contains the SAR configuration for authorization checks.

type MockAuthenticator

type MockAuthenticator struct {
	// ValidUsers maps tokens to user identities.
	// Key: token string
	// Value: user identity (e.g., "system:serviceaccount:namespace:sa-name")
	ValidUsers map[string]string

	// ErrorToReturn allows tests to simulate TokenReview API failures.
	// If set, ValidateToken will return this error instead of checking ValidUsers.
	ErrorToReturn error

	// CallCount tracks how many times ValidateToken was called.
	// Useful for verifying caching behavior.
	CallCount int
}

MockAuthenticator is a test double implementation of Authenticator.

This mock is intended for integration tests where we want to validate authentication flow without making real Kubernetes API calls. The mock allows tests to control which tokens are valid and which users they map to.

Authority: DD-AUTH-014

Security Note: This mock is ONLY for testing purposes. Production code (cmd/) always uses K8sAuthenticator with real Kubernetes APIs.

Example usage in integration tests:

authenticator := &auth.MockAuthenticator{
    ValidUsers: map[string]string{
        "test-token-authorized": "system:serviceaccount:test:authorized-sa",
        "test-token-readonly":   "system:serviceaccount:test:readonly-sa",
    },
}

// Test with valid token
user, err := authenticator.ValidateToken(ctx, "test-token-authorized")
// Returns: "system:serviceaccount:test:authorized-sa", nil

// Test with invalid token
user, err := authenticator.ValidateToken(ctx, "invalid-token")
// Returns: "", error

func (*MockAuthenticator) ValidateToken

func (a *MockAuthenticator) ValidateToken(ctx context.Context, token string) (string, error)

ValidateToken implements the Authenticator interface for testing.

type MockAuthorizer

type MockAuthorizer struct {
	// AllowedUsers maps user identities to authorization decisions.
	// Key: user identity (e.g., "system:serviceaccount:namespace:sa-name")
	// Value: true if allowed, false if denied
	//
	// If a user is not in the map, access is denied by default (secure default).
	AllowedUsers map[string]bool

	// PerResourceDecisions allows fine-grained control for tests that need
	// different authorization results based on the resource being accessed.
	// Key: "namespace/resource/resourceName/verb" (e.g., "kubernaut-system/services/data-storage-service/create")
	// Value: map of user -> allowed
	//
	// If set, PerResourceDecisions takes precedence over AllowedUsers.
	PerResourceDecisions map[string]map[string]bool

	// ErrorToReturn allows tests to simulate SAR API failures.
	// If set, CheckAccess will return this error instead of checking AllowedUsers.
	ErrorToReturn error

	// CallCount tracks how many times CheckAccess was called.
	// Useful for verifying caching behavior.
	CallCount int
}

MockAuthorizer is a test double implementation of Authorizer.

This mock is intended for integration tests where we want to validate authorization flow without making real Kubernetes SAR API calls. The mock allows tests to control which users are allowed access.

Authority: DD-AUTH-014

Security Note: This mock is ONLY for testing purposes. Production code (cmd/) always uses K8sAuthorizer with real Kubernetes APIs.

Example usage in integration tests:

authorizer := &auth.MockAuthorizer{
    AllowedUsers: map[string]bool{
        "system:serviceaccount:test:authorized-sa": true,
        "system:serviceaccount:test:readonly-sa":   false,
    },
}

// Test with authorized user
allowed, err := authorizer.CheckAccess(
    ctx,
    "system:serviceaccount:test:authorized-sa",
    "kubernaut-system",
    "services",
    "data-storage-service",
    "create",
)
// Returns: true, nil

// Test with unauthorized user
allowed, err := authorizer.CheckAccess(
    ctx,
    "system:serviceaccount:test:readonly-sa",
    "kubernaut-system",
    "services",
    "data-storage-service",
    "create",
)
// Returns: false, nil

func (*MockAuthorizer) CheckAccess

func (a *MockAuthorizer) CheckAccess(ctx context.Context, user, namespace, resource, resourceName, verb string) (bool, error)

CheckAccess implements the Authorizer interface for testing.

Jump to

Keyboard shortcuts

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