Skip to main content
Concepts

Credential Sources

Gatekeeper resolves credentials from pluggable backends called credential sources. Each source implements a single method — Fetch — that returns a credential value. Sources range from simple (read an environment variable) to complex (exchange tokens with an external STS).

The Source Interface

All credential sources implement CredentialSource:

type CredentialSource interface {
    Fetch(ctx context.Context) (string, error)
    Type() string
}

Fetch retrieves the current credential value. It accepts a context for cancellation and timeout — gatekeeper enforces a 10-second timeout on all startup fetches. Type returns a string identifier for logging (e.g., "env", "aws-secretsmanager").

Static vs Dynamic Sources

Static sources return the same value on every call. They are fetched once at startup and cached:

SourceConfigBehavior
envvar: GITHUB_TOKENReads the environment variable at startup
staticvalue: "sk-xxxx"Returns the literal value

Dynamic sources fetch from external systems and may return different values over time:

SourceConfigBehavior
aws-secretsmanagersecret: my-secret, region: us-east-1Fetches from AWS Secrets Manager
gcp-secretmanagersecret: my-secret, project: my-projectFetches from GCP Secret Manager
github-appapp_id, installation_id, private keyGenerates GitHub App installation tokens

RefreshingSource and Background Refresh

Sources whose credentials expire implement RefreshingSource:

type RefreshingSource interface {
    CredentialSource
    TTL() time.Duration
}

TTL returns the duration until the most recently fetched credential expires. Gatekeeper uses this to schedule background refresh:

  • Refresh interval. 75% of TTL, with a floor of 30 seconds. A token with a 60-minute TTL refreshes every 45 minutes.
  • Failure backoff. On fetch failure, gatekeeper retries with exponential backoff starting at 1 second, doubling each attempt, capped at 60 seconds. A random jitter (up to 25% of the backoff) is added to prevent thundering herds.
  • Hot-swap. Refreshed credentials are applied to the proxy immediately via SetCredentialWithGrant. In-flight requests use the previous value; subsequent requests use the new one.

The github-app source is a RefreshingSource. GitHub App installation tokens expire after one hour, so gatekeeper refreshes them every 45 minutes.

Source Deduplication

When multiple credential entries share the same SourceConfig (identical type, var, secret, etc.), gatekeeper fetches the credential once and applies it to all matching hosts. A single background refresh goroutine updates every host that shares the source.

credentials:
  - host: api.github.com
    grant: github
    source:
      type: github-app
      app_id: "12345"
      installation_id: "67890"
      private_key_path: ./key.pem
  - host: github.com
    grant: github
    format: basic
    prefix: x-access-token
    source:
      type: github-app
      app_id: "12345"
      installation_id: "67890"
      private_key_path: ./key.pem

Both entries share the same github-app source. Gatekeeper makes one API call to GitHub, generates one installation token, and applies it to both api.github.com (as Bearer) and github.com (as Basic x-access-token:token).

CredentialResolver for Dynamic Resolution

Some credential flows require per-request context — for example, RFC 8693 token exchange, where the proxy exchanges a caller’s identity token for a scoped access token. These flows use CredentialResolver instead of CredentialSource:

type CredentialResolver func(ctx context.Context, proxyReq, innerReq *http.Request, host string) ([]CredentialHeader, error)

Unlike static sources (fetched once at startup), resolvers are called on every request. They receive both the proxy-level request (proxyReq, carrying Proxy-Authorization) and the application-level request (innerReq, which the resolver may inspect and modify). This enables patterns like extracting a subject identity header from the request, exchanging it for an access token, and stripping the identity header before forwarding.

The token-exchange source type creates a CredentialResolver. All other source types create a CredentialSource.

Error Handling

Credential source errors at startup are fatal — gatekeeper refuses to start if any Fetch call fails. This fail-fast behavior prevents the proxy from running without required credentials.

During background refresh, errors are logged and retried with backoff. The previous credential value remains in use until a successful refresh replaces it.