Repository navigation
fix(security)!: require JWT authentication for admin APIs - #144
alexlovelltroy wants to merge 5 commits into
Conversation
Signed-off-by: Alex Lovell-Troy <alovelltroy@lanl.gov>
Signed-off-by: Alex Lovell-Troy <alovelltroy@lanl.gov>
Signed-off-by: Alex Lovell-Troy <alovelltroy@lanl.gov>
Signed-off-by: Alex Lovell-Troy <alovelltroy@lanl.gov>
synackd
left a comment
There was a problem hiding this comment.
Reviewed the authentication boundary, failure behavior, documentation, and dependency changes. The middleware placement and WireGuard private-key log removal look correct. The comments below cover the remaining security policy question and client/documentation gaps.
Upstream CI passes, including race tests and vulnerability checks. Local tests passed for the packages that ran, including pkg/wgtunnel, but the full suite could not complete because the FlatBuffers dependency download failed, including after retrying with network access.
| return func(next http.Handler) http.Handler { | ||
| // Administrative APIs accept bearer headers, not ambient browser cookies. | ||
| return jwtauth.Verify(keyset, jwtauth.TokenFromHeader)( | ||
| openchami_authenticator.AuthenticatorWithRequiredClaims(keyset, []string{"sub", "iss", "aud"})(next), |
There was a problem hiding this comment.
This middleware verifies the signature and requires claim presence, but does not check expected issuer/audience values, require an admin role or scope, or require expiration. When the configured JWKS is shared with ordinary users or other services, their tokens can therefore authorize all admin operations, including configuration writes and impersonation.
The new test explicitly expects success after setting aud = "another-service" and deleting exp. The documentation acknowledges this, but safe deployment remains dependent on keys/issuance policy dedicated to administrative authority.
Would it be appropriate to include an explicit admin token policy in this PR? My read is that this PR focuses first and foremost on protecting the endpoints (which is definitely the priority), but we should have a follow-up issue/PR to do this if not here. To address this, we would need to configure and enforce the expected issuer and audience, require expiration, and define the admin role/scope policy, with rejection tests for unrelated-service and non-admin tokens.
|
|
||
| ```bash | ||
| curl -X POST http://localhost:27777/cloud-init/admin/groups/ \ | ||
| -H "Authorization: Bearer ${CLOUD_INIT_ADMIN_TOKEN}" \ |
There was a problem hiding this comment.
This example now sends a bearer token, but the bundled demo scripts and demo documentation still send anonymous admin requests. For example, demo/set_cluster_defaults.sh omits the Authorization header, as do the other admin scripts and examples in demo/Demo.md. Those requests now return 401 when verification is configured, or 503 when JWKS is unavailable. Plain curl can still exit successfully for either HTTP error, making a failed demo setup easy to miss.
Could we update those scripts and examples with bearer headers, document the JWKS/token setup, and use --fail-with-body so failed administration produces a failing command? For example:
curl --fail-with-body -X POST "$CLOUD_INIT_URL/admin/cluster-defaults/" \
-H "Authorization: Bearer ${CLOUD_INIT_ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
--data-binary @cluster-defaults.json| func initCiAdminRouter(router chi.Router, handler *CiHandler, keyset *jwtauth.JWTAuth) { | ||
| // admin API subrouter | ||
| router.Route("/admin/", func(r chi.Router) { | ||
| r.Use(adminJWTMiddleware(keyset)) |
There was a problem hiding this comment.
This line applies JWT authentication to all registered admin operations, but the admin handler annotations and generated Swagger still omit authentication and the new 401/503 responses. Consumers of /openapi.json, including generated clients, therefore have no machine-readable indication that these operations require a bearer token.
Could we define an Authorization-header security scheme, apply it to the admin operations, document 401/503, and regenerate the checked-in Swagger files, while keeping node bootstrap operations outside that security requirement?
| For upgrade qualification, check anonymous/invalid admin requests return 401, valid | ||
| administrative reads and a disposable write succeed, impersonation remains gated, | ||
| and actual node bootstrap still works. If JWKS is unavailable, expect 503 for admin | ||
| and normal existing bootstrap behavior. The release endpoint validator can use a |
There was a problem hiding this comment.
This passage directs operators to "the release endpoint validator" and a jwt: required site policy, but identifies no tool, schema, command, or link. I could not find an implementation of that policy in this repository, so an operator cannot act on this guidance without context from the original plan.
The instructions about how "this patch must not be described", the statement about qualifying a released ochami binary, and the test comment beginning "This PR requires" also describe review scope instead of lasting behavior.
Could we replace that wording with concrete behavior and operator checks, and either remove the validator/policy reference or link and explain the external tooling if that guidance is intentional?
Signed-off-by: Alex Lovell-Troy <alovelltroy@lanl.gov>
Description
This pull request introduces strict JWT-based authentication for all
/admin/API routes, ensuring that administrative operations are protected and unavailable if JWT verification cannot be configured or fails. Node bootstrap and non-admin endpoints remain accessible without tokens. The PR also updates documentation and adds comprehensive tests to validate the new authentication boundary and failure modes.Admin authentication and API protection:
/admin/APIs now require a bearer JWT, enforced via a middleware (adminJWTMiddleware). If the JWT verifier is unavailable or misconfigured (e.g., missing or empty JWKS), admin endpoints return HTTP 503, but non-admin endpoints (e.g., node bootstrap) remain accessible. [1] [2] [3] [4]sub,iss,aud) and only accepts tokens from theAuthorizationheader (not cookies or query parameters), preventing ambient credential use. [1] [2]Testing and validation:
Documentation and usage guidance:
README.mdto document the new requirement for bearer JWTs on all/admin/endpoints, including examplecurlcommands with theAuthorizationheader and a pointer to detailed admin authentication and upgrade guidance. [1] [2] [3] [4] [5]Other improvements:
These changes collectively harden the security boundary for administrative operations, provide clear operator guidance, and ensure robust, test-driven enforcement of the new authentication requirements.
Checklist
make test(or equivalent) locally and all tests passgit commit -s) with my real name and email<filename>.licensesidecarLICENSES/directoryType of Change