Skip to main content
Reference

Credential sources

Each credential entry in gatekeeper.yaml includes a source block that determines where the credential value comes from.

Source types overview

TypeDescriptionRefresh
envRead from an environment variableNo
staticLiteral inline valueNo
processRun a host command, use its stdoutYes (auto-refresh; expiry read from credential_process-format JSON, else configurable ttl)
aws-secretsmanagerFetch from AWS Secrets ManagerNo
gcp-secretmanagerFetch from GCP Secret ManagerNo
gcp-service-accountMint GCP OAuth2 access token from a service account keyYes (auto-refresh before expiry)
github-appGenerate GitHub App installation tokenYes (auto-refresh before expiry)
token-exchangeRFC 8693 token exchangeYes (per-request, cached with TTL)

Sources marked Refresh: Yes have credentials that expire. process, github-app, and gcp-service-account implement background credential refresh — gatekeeper re-fetches at 75% of TTL (minimum 30 seconds) and hot-swaps without downtime. token-exchange uses per-request lazy caching: on cache miss, gatekeeper calls the STS and caches the result for the token’s TTL.


env

Read the credential value from an environment variable at startup.

credentials:
  - host: api.github.com
    source:
      type: env
      var: GITHUB_TOKEN

var

Name of the environment variable to read.

  • Type: string
  • Required: Yes
  • Default:

The variable must be set and non-empty at startup. If unset, gatekeeper exits with an error.


static

Use a literal value defined inline in the config file.

credentials:
  - host: api.example.com
    header: x-api-key
    source:
      type: static
      value: sk-xxxx

value

The credential value.

  • Type: string
  • Required: Yes
  • Default:

Note: Avoid committing secrets in config files. Prefer env or a secret manager source for production deployments.


process

Run a host command and use its stdout as the credential value. Any helper that prints a credential works: OS keychain CLIs, pass, 1Password’s op, or an AWS credential_process helper.

credentials:
  - host: api.example.com
    header: x-api-key
    source:
      type: process
      command: "op read op://vault/example/api-key"

command

Shell command to run with sh -c. Stdout (trimmed) becomes the credential value.

  • Type: string
  • Required: Yes
  • Default:

ttl

Refresh interval when the command output carries no expiry information, as a Go duration (90s, 30m, 12h). Must be positive.

  • Type: string
  • Required: No
  • Default: 5m

Like all refreshing sources, gatekeeper re-fetches at 75% of TTL (floor 30 seconds), so the default re-runs the command every 3m45s. Set a longer ttl for helpers that are expensive or interactive (biometric prompts, rate limits) and serve values that rarely change.

Behavior

  • Expiry-aware refresh. When stdout is AWS credential_process-format JSON — recognized by its exact-case Version, AccessKeyId, and Expiration (RFC 3339) keys — the credential refreshes on that expiry, and ttl is ignored. The JSON is passed through as the credential value; consumers that need the individual fields parse it themselves. Other JSON output is treated as an opaque credential and refreshes on ttl.
  • Expired output is an error. If the reported Expiration is already in the past, the fetch fails (with the timestamp in the error) instead of installing credentials that would be rejected upstream; the standard retry backoff applies.
  • Sanitization. Control characters that are invalid in HTTP header values (RFC 7230) are stripped. A warning is logged (count only — the value is never logged) when non-whitespace control bytes were present; trailing newlines and pretty-printed JSON are normal and do not warn.
  • Failures. A non-zero exit fails the fetch; stderr is included in the error (truncated) so helper failures such as an expired SSO session are diagnosable. Empty output is an error. Failed refreshes retry with the standard backoff.

Security: The command runs on the host with gatekeeper’s privileges. Only configure commands you trust, from config files you own. Embedding operators (like moat) must not accept this field from repository-controlled config.


aws-secretsmanager

Fetch the credential from AWS Secrets Manager at startup. Uses the AWS SDK default credential chain (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, IAM roles, etc.).

credentials:
  - host: api.example.com
    source:
      type: aws-secretsmanager
      secret: my-app/api-key
      region: us-east-1

secret

AWS Secrets Manager secret ID or ARN.

  • Type: string
  • Required: Yes
  • Default:

region

AWS region for the Secrets Manager client.

  • Type: string
  • Required: No
  • Default: — (uses AWS_REGION or AWS_DEFAULT_REGION from the environment)

gcp-secretmanager

Fetch the credential from GCP Secret Manager at startup. Uses Application Default Credentials (GOOGLE_APPLICATION_CREDENTIALS, metadata server, etc.).

credentials:
  - host: api.example.com
    source:
      type: gcp-secretmanager
      project: my-gcp-project
      secret: api-key
      version: latest

project

GCP project ID containing the secret.

  • Type: string
  • Required: Yes
  • Default:

secret

Secret name within the project.

  • Type: string
  • Required: Yes
  • Default:

version

Secret version to access.

  • Type: string
  • Required: No
  • Default: "latest"

The underlying gRPC connection is closed on gatekeeper shutdown.


gcp-service-account

Mint short-lived GCP OAuth2 access tokens from a service account key (the JSON file format produced by gcloud iam service-accounts keys create). Gatekeeper signs a JWT with the key, exchanges it for an access token at Google’s OAuth2 token endpoint, and refreshes the token automatically in the background before expiry. Clients inside the sandbox never see the service account key — only the proxy holds it.

credentials:
  - host: storage.googleapis.com
    grant: gcs
    source:
      type: gcp-service-account
      project: my-gcp-project
      secret: gcs-uploader-key
      scopes: https://www.googleapis.com/auth/devstorage.read_write

The service account key JSON can come from one of three locations: GCP Secret Manager (secret + project), a file (private_key_path), or an environment variable (private_key_env). Exactly one must be set.

secret

GCP Secret Manager secret holding the service account key JSON. Reading the secret uses Application Default Credentials, same as the gcp-secretmanager source. If the token endpoint rejects an assertion (e.g., after the key is rotated and the old key revoked), gatekeeper drops the cached key and re-reads it from Secret Manager on the next refresh, so key rotation is picked up without a restart.

  • Type: string
  • Required: One of secret, private_key_path, or private_key_env is required
  • Default:

project

GCP project ID containing the secret.

  • Type: string
  • Required: Yes, when secret is set
  • Default:

version

Secret version to access.

  • Type: string
  • Required: No (only valid with secret)
  • Default: "latest"

private_key_path

File path to the service account key JSON.

  • Type: string
  • Required: One of secret, private_key_path, or private_key_env is required
  • Default:

private_key_env

Name of an environment variable containing the service account key JSON.

  • Type: string
  • Required: One of secret, private_key_path, or private_key_env is required
  • Default:

The environment variable must be set and non-empty at startup.

scopes

Space-separated list of OAuth scopes to request.

  • Type: string
  • Required: No
  • Default: "https://www.googleapis.com/auth/cloud-platform"

github-app

Generate short-lived GitHub App installation access tokens. Tokens refresh automatically in the background before expiry.

credentials:
  - host: api.github.com
    grant: github
    source:
      type: github-app
      app_id: "12345"
      installation_id: "67890"
      private_key_path: /etc/gatekeeper/github-app.pem

app_id

GitHub App ID.

  • Type: string
  • Required: Yes
  • Default:

installation_id

GitHub App installation ID.

  • Type: string
  • Required: Yes
  • Default:

private_key_path

File path to the PEM-encoded RSA private key for the GitHub App.

  • Type: string
  • Required: One of private_key_path or private_key_env is required
  • Default:

Mutually exclusive with private_key_env. Supports both PKCS#1 (RSA PRIVATE KEY) and PKCS#8 (PRIVATE KEY) PEM formats.

private_key_env

Name of an environment variable containing the PEM-encoded RSA private key.

  • Type: string
  • Required: One of private_key_path or private_key_env is required
  • Default:

Mutually exclusive with private_key_path. The environment variable must be set and non-empty at startup.

When multiple credentials share the same github-app source config (e.g., api.github.com and github.com), gatekeeper deduplicates them into a single token fetch and a single background refresh goroutine.


token-exchange

Exchange a per-request subject token for an access token via RFC 8693 (OAuth 2.0 Token Exchange). Unlike other sources, token-exchange resolves credentials dynamically per request rather than at startup.

credentials:
  - host: api.github.com
    grant: github
    source:
      type: token-exchange
      endpoint: https://sts.example.com/token
      client_id: gatekeeper
      client_secret_env: STS_CLIENT_SECRET
      subject_header: X-Subject-Token
      resource: https://api.github.com

endpoint

STS token endpoint URL.

  • Type: string
  • Required: Yes
  • Default:

client_id

OAuth client ID for authenticating to the STS via HTTP Basic auth.

  • Type: string
  • Required: Yes
  • Default:

client_secret

OAuth client secret. Sent as the Basic auth password to the STS endpoint.

  • Type: string
  • Required: One of client_secret or client_secret_env is required
  • Default:

Mutually exclusive with client_secret_env.

client_secret_env

Name of an environment variable containing the OAuth client secret.

  • Type: string
  • Required: One of client_secret or client_secret_env is required
  • Default:

Mutually exclusive with client_secret. The environment variable must be set and non-empty at startup.

subject_header

HTTP request header containing the subject token. The header is stripped from the request before forwarding.

  • Type: string
  • Required: One of subject_header or subject_from is required
  • Default:

Mutually exclusive with subject_from.

subject_from

Alternative subject token extraction method.

  • Type: string
  • Required: One of subject_header or subject_from is required
  • Default:
  • Valid values: "proxy-auth"

When set to "proxy-auth", the subject token is extracted from the username in the Proxy-Authorization Basic auth header.

Mutually exclusive with subject_header.

subject_token_type

OAuth token type URI for the subject token.

  • Type: string
  • Required: No
  • Default: "urn:ietf:params:oauth:token-type:access_token"

resource

Target resource URI included in the token exchange request.

  • Type: string
  • Required: No
  • Default:

actor_token_from

Source for the optional RFC 8693 actor token.

  • Type: string
  • Required: No
  • Default: — (no actor token)
  • Valid values: "proxy-auth-password"

When set to "proxy-auth-password", the actor token is extracted from the password in the Proxy-Authorization Basic auth header. Requires subject_from: proxy-auth.

When actor_token_from is configured, gatekeeper sets delegate auth mode — the static auth_token check is skipped and each caller’s identity is validated by the STS instead.

actor_token_type

OAuth token type URI for the actor token.

  • Type: string
  • Required: No
  • Default: "urn:ietf:params:oauth:token-type:access_token"

Exchanged tokens are cached per subject (and actor, if present) using the TTL from the STS expires_in response field, but the cached TTL is always capped at 1 minute regardless of what the STS advertises — a longer expires_in only means the token may remain valid that long, not that it stays valid, since the upstream credential behind the exchange can be revoked or rotated without gatekeeper’s knowledge. If the STS does not return expires_in (or returns a non-positive value), the same 1-minute cap is used as the TTL. Concurrent requests for the same subject are coalesced into a single STS call via singleflight, so the 1-minute cap does not translate into an STS call per request.

See Credential invalidation below for how gatekeeper evicts a cached token before its TTL expires.

Credential invalidation

When the upstream server rejects a forwarded request with 401 Unauthorized or 403 Forbidden, gatekeeper invalidates every credential that was injected into that request, so the next request re-resolves rather than replaying a credential the destination has already refused. This applies to any credential source that supports invalidation, not just token-exchange. Statuses other than 401/403 are left alone — a 5xx says nothing about the credential’s validity, and a 401/403 also covers cases unrelated to a stale credential (rate limits, missing repo access), not only rotation.

For token-exchange, invalidation evicts the cached token for that subject (and actor) so the next request performs a fresh exchange. Evictions are rate-limited per subject/actor key to a 10-second cooldown: repeated 401/403 responses for the same key within 10 seconds are no-ops after the first eviction. This bounds how often a client that is looping on a failing, non-idempotent request (e.g., a repeated git push) can force STS calls; the trade-off is that a genuinely rotated credential can take up to 10 seconds to be picked up after the first eviction.

Invalidation is evict-only — the request that triggered it is not retried by gatekeeper.