ADR-0404: Inventory HTTP API authentication¶
When the optional HTTP API is enabled, authenticate with Kubernetes TokenReview + SubjectAccessReview; oauth2-proxy is an optional browser sidecar.
Theme: 04 · Export & sinks · Status: Current
Context¶
The read-only inventory HTTP API (ADR-0103) exposes aggregated collection data for portals and automation. Production deployments require authentication and authorization without forcing every consumer to run inside the cluster network.
Options considered:
| Approach | Pros | Cons |
|---|---|---|
| Kubernetes API auth delegation | Native SA tokens; TokenReview + SAR; no extra identity stack | Callers need a valid K8s token; RBAC must grant inventory read |
| oauth2-proxy sidecar | OIDC/login flows for human browsers; familiar ingress pattern | Extra container; not primary for service-to-service |
| Static API keys in operator | Simple | Secret rotation burden; not K8s-native |
| mTLS only | Strong transport identity | Certificate lifecycle; awkward for portal browsers |
Early design notes mentioned oauth2-proxy as a possible auth layer. User feedback : oauth2-proxy remains a well-documented optional sidecar, not the primary auth mechanism.
Decision¶
- Primary auth: Kubernetes-native delegation. When inventory HTTP is enabled, the operator validates callers using the Kubernetes API:
TokenReview— verify the bearer token (Authorization: Bearer <token>) and resolve the authenticated user (typically aServiceAccountor user subject).-
SubjectAccessReview— authorize the subject for inventory read:getonkollectinventoriesin the caller's namespace for a single inventory;listonkollectinventoriesfor the namespace index endpoint. Same RBAC markers askubectl get kinv/kubectl get kinv -A(namespace-scoped list). Hub ingest (Phase 2):create/updateonkollectremoteclustersor subresourcekollectremoteclusters/ingest— pick one in chart RBAC docs (ADR-0503).
-
Default auth mode: manager flag
--inventory-auth-mode=kubernetes(default). Modes: kubernetes— TokenReview + SAR (production default).-
disabled— no auth (local dev / CI only; must log a startup warning). -
Caller contract: standard
Authorization: Bearerheader with a Kubernetes service account token (bound or legacy) or other token accepted by the apiserver's TokenReview. No custom Kollect API-key header in the core path. -
Optional oauth2-proxy sidecar (Helm): for human/browser access via OIDC, document an optional Helm subchart or sidecar pattern:
oauth2Proxy.enabled: falseby default incharts/kollect/values.yaml.- When enabled, oauth2-proxy terminates OIDC login and forwards to the operator inventory port; service-to-service callers should still use K8s bearer tokens directly (bypass sidecar or use internal Service without oauth2-proxy).
- Document in
charts/kollect/README.md— not implemented until HTTP API ships; values reserved. -
Kollect UI MVP (ADR-0408, ADR-0409): the SPA ships without a login shell — assume cluster-network or port-forward; oauth2-proxy at ingress is post-MVP (v0.3+) auth offload, not a blocker for UI development.
-
RBAC: chart and docs ship ClusterRole/Role rules for inventory HTTP consumers; SAR checks align with least-privilege read of inventory data in the caller's permitted namespaces.
-
Auth result cache: in-memory cache of TokenReview + SAR decisions keyed by
(token hash, verb, resource)with 30s TTL (configurable;disabledfor local dev). -
HTTP paths (when inventory HTTP enabled):
GET /v1alpha1/inventory; optionalGET /v1alpha1/inventory/{namespace}/{name}. OpenAPI schema:openapi/v1alpha1/inventory.yamlshipped beside the handler (ADR-0103).
Auth flow (reference)¶
sequenceDiagram
participant Client as Client (SA token)
participant HTTP as Inventory HTTP
participant TR as TokenReview API
participant SAR as SubjectAccessReview API
participant Store as In-memory store
Client->>HTTP: GET /v1alpha1/inventory<br/>Authorization: Bearer token
HTTP->>TR: TokenReview(token)
TR-->>HTTP: authenticated user
HTTP->>SAR: SubjectAccessReview(user, resource)
SAR-->>HTTP: allowed / denied
alt allowed
HTTP->>Store: read aggregate
Store-->>HTTP: JSON body
HTTP-->>Client: 200 OK
else denied
HTTP-->>Client: 403 Forbidden
end
Optional oauth2-proxy (browser path)¶
flowchart LR
Browser[Browser user] -->|OIDC login| O2P[oauth2-proxy sidecar<br/>optional]
O2P -->|authenticated session| HTTP[Inventory HTTP<br/>auth-mode=kubernetes or disabled behind sidecar]
SA[ServiceAccount client] -->|Bearer token direct| HTTP
When oauth2-proxy is enabled, configure it in front of the inventory port for ingress-facing browser traffic. Automated clients with service account tokens connect directly to the operator Service on the inventory port — no oauth2-proxy hop.
Consequences¶
Positive¶
- Reuses cluster identity — no parallel user database or API-key store.
- SAR enforces namespace/tenant boundaries consistent with
KollectScope(ADR-0203). - oauth2-proxy available for OIDC/browser UX without blocking service-to-service auth.
disabledmode keeps local kind smoke and unit tests simple.
Negative¶
- External callers outside the cluster need a valid K8s token (e.g. projected SA token, exec credential).
- TokenReview + SAR adds apiserver round-trips per request — cache short-lived auth decisions if hot path.
- oauth2-proxy sidecar not implemented in Phase 1 — documented pattern only until HTTP ships.
Open questions¶
- RESOLVED : SAR —
get/listonkollectinventoriesin caller namespace(s); hub ingest SAR shape deferred to Phase 2 (ADR-0503). - RESOLVED : TokenReview/SAR cache 30s TTL per
(token hash, verb, resource). - RESOLVED : HTTP paths
GET /v1alpha1/inventory(+ optional{namespace}/{name}); OpenAPIopenapi/v1alpha1/inventory.yaml— ADR-0103.
See also¶
- ADR-0103: Data storage and etcd limit — HTTP API scope
- charts/kollect/README.md — Helm auth configuration