You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
HeaderContentGuard stores the expected secret in header_value on the guard record. When the shared secret is managed outside Pulp (injected by a reverse proxy, Kubernetes secret → pod env var, etc.), rotating it requires updating every guard that references that secret.
HeaderContentGuard also expects the request header to be base64-encoded and compares against the decoded value. Deployments that pass the secret as a raw header (common for simple shared-key proxies) cannot use the guard without encoding at the proxy.
We have a concrete need for content access protected by a header whose expected value is read from os.environ at request time, so rotation is a deployment/config change rather than a bulk API update across guard records.
Proposed solution
Add an EnvVarHeaderContentGuard content guard type to pulpcore (alongside HeaderContentGuard):
Field
Purpose
header_name
Request header to inspect (operator-configured)
env_var
Name of the environment variable holding the expected secret
permit() behavior:
Read request.headers[header_name]; deny if missing.
Read os.environ[env_var]; deny if unset or empty (after strip).
Compare header value to env value with hmac.compare_digest on stripped strings.
Deny on mismatch; allow otherwise.
API: New viewset at /pulp/api/v3/contentguards/core/envvar_header/ (or equivalent TYPE = "envvar_header" naming), with RBAC/access policy matching HeaderContentGuard.
v1 scope (suggested):
Raw header compare (no base64 requirement).
No jq_filter (can be added later if needed).
No allowlist fields.
Use case
Any deployment where:
A trusted edge component injects a shared secret header on authorized requests.
The secret is provisioned via environment variables (K8s env, Clowder, etc.).
Operators want rotation without touching guard records in the database.
Alternatives considered
Extend HeaderContentGuard with an optional env_var field instead of a new type — fewer models, but mixes DB-stored and env-sourced secrets in one guard; harder to document and permission separately.
Continue using HeaderContentGuard + DB updates — rotation requires updating every guard instance; does not scale for shared secrets across many distributions.
Acceptance criteria
EnvVarHeaderContentGuard model, migration, serializer, viewset registered in pulpcore
permit() validates header against os.environ[env_var] at request time
Missing header, unset/empty env var, and wrong value → deny (403 on content app)
Correct header value → allow
Unit tests for permit() edge cases (missing header, wrong value, env unset/empty, trailing newline in env)
Functional test: guarded distribution denies without header, allows with matching header when env is set
Access policy registered for the new viewset (same pattern as HeaderContentGuard)
Problem
HeaderContentGuardstores the expected secret inheader_valueon the guard record. When the shared secret is managed outside Pulp (injected by a reverse proxy, Kubernetes secret → pod env var, etc.), rotating it requires updating every guard that references that secret.HeaderContentGuardalso expects the request header to be base64-encoded and compares against the decoded value. Deployments that pass the secret as a raw header (common for simple shared-key proxies) cannot use the guard without encoding at the proxy.We have a concrete need for content access protected by a header whose expected value is read from
os.environat request time, so rotation is a deployment/config change rather than a bulk API update across guard records.Proposed solution
Add an
EnvVarHeaderContentGuardcontent guard type to pulpcore (alongsideHeaderContentGuard):header_nameenv_varpermit()behavior:request.headers[header_name]; deny if missing.os.environ[env_var]; deny if unset or empty (after strip).hmac.compare_digeston stripped strings.API: New viewset at
/pulp/api/v3/contentguards/core/envvar_header/(or equivalentTYPE = "envvar_header"naming), with RBAC/access policy matchingHeaderContentGuard.v1 scope (suggested):
jq_filter(can be added later if needed).Use case
Any deployment where:
env, Clowder, etc.).Alternatives considered
HeaderContentGuardwith an optionalenv_varfield instead of a new type — fewer models, but mixes DB-stored and env-sourced secrets in one guard; harder to document and permission separately.pulp-service(PULP-2257: Add EnvVarHeaderContentGuard for env-backed header validation pulp-service#1420); workable but duplicates a generic content-guard primitive that belongs in core.HeaderContentGuard+ DB updates — rotation requires updating every guard instance; does not scale for shared secrets across many distributions.Acceptance criteria
EnvVarHeaderContentGuardmodel, migration, serializer, viewset registered in pulpcorepermit()validates header againstos.environ[env_var]at request timepermit()edge cases (missing header, wrong value, env unset/empty, trailing newline in env)HeaderContentGuard)Related
HeaderContentGuard—pulpcore/app/models/publication.py