---
title: "Secrets and rotation"
url: "/docs/security/secrets-and-rotation/"
kind: "feature"
summary: "Name TLS certificates and CAs as secrets, reference them from listeners and clusters, and rotate them over xDS without a restart."
---

> Arion site index: [/llms.txt](/llms.txt)

# Secrets and rotation

Name TLS certificates and CAs as secrets, reference them from listeners and clusters, and rotate them over xDS without a restart.

A secret is a named TLS asset — a certificate with its private key, or a CA used to validate peers — that transport sockets reference by name instead of embedding inline. Use secrets when several filter chains or clusters share the same material, or when a control plane should be able to rotate certificates while Arion is running.

## Define and reference a secret

Declare secrets under `static_resources.secrets` and point a transport socket at them with `tls_certificate_sds_secret_configs`:

```yaml,name=arion.yaml,arion=fragment
envoy_bootstrap:
  static_resources:
    secrets:
      - name: example_com_server
        tls_certificate:
          certificate_chain: { filename: certs/example.com.cert.pem }
          private_key: { filename: certs/example.com.key.pem }
    listeners:
      - name: https
        # ...
        filter_chains:
          - name: https_chain
            # filters ...
            transport_socket:
              name: envoy.transport_sockets.tls
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
                common_tls_context:
                  tls_certificate_sds_secret_configs:
                    - name: example_com_server
```

Each secret is either a `tls_certificate` or a `validation_context` (a `trusted_ca` for verifying peers). A validation context is referenced with `validation_context_sds_secret_config: { name: ... }`, and a cluster's `UpstreamTlsContext` references its client certificate the same way. Certificate material comes from a `filename`, `inline_string`, `inline_bytes` or `environment_variable` data source.

Inline certificates (`tls_certificates` directly in the transport socket) remain fine for small setups; named secrets and inline certificates cannot be mixed in one `common_tls_context`.

## Rotation

{% <variant mode="standalone" label="Standalone"> %}
With a static configuration file, secrets are loaded once at startup. To rotate a certificate, update the files the secrets point at and restart Arion; there is no file watching (`watched_directory` is not supported).
{% </variant> %}

{% <variant mode="kubernetes" label="Kubernetes"> %}
Secrets referenced by `filename` are read when the pod starts. After updating the mounted certificate files, roll the Deployment to pick them up — or run an xDS control plane and let SDS push the new material with no restart.
{% </variant> %}

{% <variant mode="xds" label="xDS"> %}
Over xDS, Arion subscribes to the Secret Discovery Service (SDS) for every name referenced by a transport socket. When the control plane pushes an updated `envoy.extensions.transport_sockets.tls.v3.Secret`, Arion rebuilds the affected TLS contexts in place: listeners serve the new certificate and clusters use the new material for new connections. No restart, no dropped listener.
{% </variant> %}

The `envoy_bootstrap` shape is the same in a file and over xDS — a control plane delivers exactly the resource shown above as an SDS response. SDS secrets arrive over the bootstrap ADS connection; a per-secret `sds_config` source is not supported.

## Keep keys out of the config file

`environment_variable` reads the value from the process environment at load time, which keeps private keys out of files you check in:

```yaml,arion=fragment
tls_certificate:
  certificate_chain: { filename: certs/example.com.cert.pem }
  private_key: { environment_variable: EXAMPLE_COM_KEY }
```

Arion never prints private key material: debug output for a certificate censors everything except a file path.

## Verify

```bash
curl -s http://127.0.0.1:9901/certs
```

The admin endpoint reports every loaded certificate and CA with serial number, SANs, validity window and `days_until_expiration` — after a rotation, the expiration date should move.

## Limits

- Secret types are `tls_certificate` and `validation_context`; Envoy's `generic_secret` and `session_ticket_keys` are refused.
- No file watching: changing a file on disk does not trigger a reload. Rotation without restart requires SDS.
- A referenced SDS secret that the control plane has not delivered yet is logged as missing; the handshake cannot complete until it arrives.
- `environment_variable` sources are read when the secret loads, not per handshake.

See [resource reference: secrets](@/reference/resources/secrets.md) for the full field list, and [xDS control planes](@/docs/operate/xds-control-planes.md) for wiring up discovery.
