Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 293 additions & 0 deletions content/docs/guides/secrets.mdx

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions content/docs/reference/metrics.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,27 @@ Identity manager metrics have a `pomerium_identity_manager` prefix.
| user_refresh_success | Counter | User refresh success counter. |
| user_refresh_success_timestamp | Gauge | Timestamp of last successful user refresh. |

### Secrets \{#secrets}

These metrics cover [secret injection](/docs/reference/secrets): reading credentials from a backend and substituting them into request headers. They have a `pomerium_secrets` prefix and are exported by the Authorize service.

| Name | Type | Labels | Description |
| --- | --- | --- | --- |
| fetches_total | Counter | `provider`, `outcome` | Reads of a secret backend. `outcome` is `success`, `error`, or `not_found`. |
| fetch_duration | Histogram | `provider`, `outcome` | Duration of a read, in milliseconds. |
| refs_registered | Gauge | `provider` | Number of configured secret bindings. |
| cache_state | Gauge | `ref_label`, `state` | One series per binding, reporting its current state: `fresh`, `stale`, `expired`, or `failed`. |
| serving_stale_total | Counter | `ref_label` | Failed re-reads that left a binding serving its last good value. Counts read attempts, not requests. |
| negative_cache_hits_total | Counter | `ref_label` | Read attempts skipped because the backend recently reported the secret as missing. |
| singleflight_collapsed_total | Counter | `provider` | Concurrent reads of the same backend collapsed into one. |
| header_inject_total | Counter | `route_id`, `outcome` | Header injection attempts, counted once per header that carries a secret reference. `outcome` is `injected` or `rejected`. |

`ref_label` is the binding ID.

Header injection runs during authorization, before the allow or deny decision is applied, so `header_inject_total` also counts requests the policy then denies or redirects to sign-in. A `rejected` outcome means the header could not be built; the request is answered with `503 Service Unavailable` only if the policy allowed it.

For alerting, `cache_state` is the clearest signal: `state="expired"` means a value was dropped after its grace window, and `state="failed"` means a binding has never been read successfully. `header_inject_total{outcome="rejected"}` shows the request-level effect, including values that were read but cannot be used as a header.

#### Envoy Proxy Metrics

As of `v0.9`, Pomerium uses [Envoy](https://www.envoyproxy.io/) for the data plane. As such, proxy related metrics are sourced from Envoy, and use Envoy's internal [stats data model](https://www.envoyproxy.io/docs/envoy/latest/operations/stats_overview). Please see Envoy's documentation for information about specific metrics.
Expand Down
53 changes: 53 additions & 0 deletions content/docs/reference/reference.json
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,59 @@
"title": "Secondary Color (Dark Mode)",
"type": "string"
},
"secrets": {
"description": "Read credentials from a file outside the Pomerium configuration and inject them into upstream request headers, with live rotation and fail-closed behavior.",
"id": "secrets",
"path": "/secrets",
"services": ["authorize"],
"short_description": "",
"title": "Secrets"
},
"secrets-binding-refresh": {
"description": "How often Pomerium re-reads a secret binding's backend. Minimum one second.",
"id": "secrets-binding-refresh",
"path": "/secrets#bindings",
"services": ["authorize"],
"short_description": "",
"title": "Secrets Binding Refresh",
"type": "duration"
},
"secrets-binding-stale-grace": {
"description": "How long a secret binding's last good value is still used while re-reading keeps failing. After this window the value is dropped and requests that need it are rejected with 503.",
"id": "secrets-binding-stale-grace",
"path": "/secrets#bindings",
"services": ["authorize"],
"short_description": "",
"title": "Secrets Binding Stale Grace",
"type": "duration"
},
"secrets-binding-url": {
"description": "The backend a secret binding reads from. Supports file:// URLs with an absolute path, and an optional dotted-path fragment selecting one field of a JSON payload.",
"id": "secrets-binding-url",
"path": "/secrets#binding-urls",
"services": ["authorize"],
"short_description": "",
"title": "Secrets Binding URL",
"type": "string"
},
"secrets-bindings": {
"description": "The secret binding table. Each key is a binding ID referenced from a route as ${secret.ID}, and each value describes the backend URL and how often to re-read it.",
"id": "secrets-bindings",
"path": "/secrets#bindings",
"services": ["authorize"],
"short_description": "",
"title": "Secrets Bindings",
"type": "map of objects"
},
"secrets-defaults": {
"description": "Tuning values applied to secret bindings that leave a field unset: refresh, stale_grace, and negative_ttl.",
"id": "secrets-defaults",
"path": "/secrets#defaults",
"services": ["authorize"],
"short_description": "",
"title": "Secrets Defaults",
"type": "object"
},
"service-account-description": {
"description": "A customizable description that identifies this service account.",
"id": "service-account-description",
Expand Down
30 changes: 29 additions & 1 deletion content/docs/reference/routes/headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ remove_request_headers:

The dynamic values enable you to pass ID and Access tokens from your identity provider to upstream applications.

To pass dynamic values from the user's OIDC claim to an upstream service, see [JWT Claim Headers](../jwt-claim-headers).
To pass dynamic values from the user's OIDC claim to an upstream service, see [JWT Claim Headers](../jwt-claim-headers). To inject a credential that Pomerium reads from a file outside its own configuration, see [Inject Secrets](#inject-secrets).

:::caution

Expand Down Expand Up @@ -240,6 +240,32 @@ Be very careful when passing access tokens to an upstream application. This may

:::

### Inject Secrets \{#inject-secrets}

A header value can also carry a `${secret.ID}` reference. `ID` names an entry in the [`secrets.bindings`](/docs/reference/secrets#bindings) table, which tells Pomerium where to read the credential from:

```yaml
secrets:
bindings:
upstream-api-token:
url: 'file:///etc/pomerium/secrets/upstream-api-token'

routes:
- from: https://api.corp.example.com
to: https://api.internal
set_request_headers:
Authorization: 'Bearer ${secret.upstream-api-token}'
policy:
- allow:
or:
- email:
is: user@example.com
```

Unlike a static header value, the credential is not part of your Pomerium configuration. Pomerium re-reads the file in the background, so you can rotate the credential without a configuration change or a restart. If the credential cannot be read, Pomerium rejects the request with `503 Service Unavailable` instead of sending it without the header.

Secret references work only in `set_request_headers`. For the full behavior, including rotation, failure handling, and monitoring, see the [Secrets](/docs/reference/secrets) reference.

### Rewrite Request Headers \{#rewrite-request-headers}

In addition to token substitutions, request headers can be rewritten using `${pomerium.request.headers["HEADER-NAME"]}`. For example if a request had a header `X-Jwt: JWT` and you would like to send it as `Authorization: Bearer JWT`, you could do so using:
Expand Down Expand Up @@ -306,6 +332,8 @@ ingress.pomerium.io/remove_request_headers: |

**Set Response Headers** allows you to set static values for the given response headers. These headers will take precedence over the global [`set_response_headers`](/docs/reference/set-response-headers).

Response header values are static text. `${pomerium.*}` and [`${secret.ID}`](/docs/reference/secrets) references are not substituted here, and a secret reference in a response header is a configuration error.

### How to Configure \{#how-to-configure-set-response-headers}

<Tabs>
Expand Down
Loading