# Choose a secret backend
Source: https://docs.chain.link/ccip/ccv-starter-kit/how-to/choose-a-secret-backend
Last Updated: 2026-09-27

> For the complete documentation index, see [llms.txt](/llms.txt).

A CCV cell is one aggregator plus one verifier. Both read their credentials from secrets you provide when you
install the chart. This page explains what those secrets contain, which backends the chart supports for
delivering them, and how to choose. The verifier and aggregator workloads behave the same whichever backend
you pick, so the choice is about how your cluster already stores and pulls secrets. The off-chain kit's
[Secrets](https://github.com/smartcontractkit/chainlink-ccv-starter-kit/blob/main/RUNBOOK.md#secrets)
documentation has the full mount map.

## What the cell needs as secrets

A secret here is a `secrets.toml` file (or the equivalent Kubernetes `Secret`) that a component reads at
startup. The chart injects up to four per cell, keyed on the values below. The Postgres connection strings in
them point at the cell's [logical databases](/ccip/ccv-starter-kit/prerequisites#postgres-databases).

`aggregator.secrets.app` holds the aggregator's application secret: its Postgres storage connection string,
an optional Redis password for the rate limiter, and one HMAC credential pair per client that connects to it.
The `api_key` is a UUID and the `secret_key` is hex-encoded; you generate both.

```toml
[storage]
url = "postgres://user:password@localhost:5432/aggregator?sslmode=disable"

[[clients]]
client_id = "client-1"
api_key = "<uuid>"
secret_key = "<hex>"
```

`verifier.secrets.app` holds the verifier's application secret: its own Postgres connection string, one HMAC
credential pair per aggregator it talks to, and an optional credential for a policy-hook endpoint.

```toml
[db]
url = "postgres://user:password@localhost:5432/verifier?sslmode=disable"

[[aggregators]]
secret_name = "aggregator_1"
api_key = "<uuid>"
secret_key = "<hex>"
```

`verifier.secrets.bootstrap` holds the `[keystore]` block that decides where the verifier's signing key lives,
a Postgres-held key or a cloud KMS key referenced by id, plus the bootstrapper's own Postgres connection
string. See [Signer key custody and KMS](/ccip/ccv-starter-kit/how-to/signer-key-custody-and-kms) for the
key-custody decision.

`verifier.secrets.evm` is optional. Use it when an RPC endpoint URL carries an API key, so the keyed URL
becomes a secret instead of plain configuration.

The per-peer `api_key` and `secret_key` pairs are how committee members authenticate to each other. Exchanging
them across cells is covered in the runbook's
[Peer information and credential exchange](https://github.com/smartcontractkit/chainlink-ccv-starter-kit/blob/main/RUNBOOK.md#8-peer-information-and-credential-exchange).

## Supported backends

Set `type` on each of `aggregator.secrets.app`, `verifier.secrets.app`, `verifier.secrets.bootstrap`, and
optionally `verifier.secrets.evm`. The chart supports five backends.

| Backend                    | How the secret is delivered                                                                                                                                 | Typical cluster                               |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| `externalSecret` (default) | The chart creates an `ExternalSecret`; External Secrets Operator pulls each field from your `SecretStoreRef` via `*RemoteRef` keys and assembles the secret | Any cluster running External Secrets Operator |
| `gcpSecretStore`           | The Secrets Store CSI Driver mounts one pre-built `secrets.toml` from GCP Secret Manager                                                                    | GKE with the Secret Manager CSI add-on        |
| `awsSecretStore`           | The CSI Driver (AWS ASCP) mounts one pre-built `secrets.toml` from AWS Secrets Manager                                                                      | EKS with IRSA or Pod Identity                 |
| `azureKeyVault`            | The CSI Driver (Azure provider) mounts one pre-built `secrets.toml` from Azure Key Vault                                                                    | AKS with Workload Identity or Pod Identity    |
| `existingSecret`           | The chart mounts a Kubernetes `Secret` you create and manage                                                                                                | Any cluster, including on-premises            |

## When to use each

Use `externalSecret`, the default, when you already run External Secrets Operator or want the chart to build
the secret for you. It templates the secret from your remote references, and it is the only backend that
writes the `[keystore]` block on your behalf from `verifier.secrets.bootstrap.keystoreBackend` and
`verifier.secrets.bootstrap.kms.*`.

Use `gcpSecretStore`, `awsSecretStore`, or `azureKeyVault` on a managed cloud when you want the pod to pull
the secret keylessly through workload identity. The chart creates a `SecretProviderClass` and the Secrets
Store CSI Driver mounts one pre-built `secrets.toml` that you store in the cloud's secret manager. Each needs
the matching identity wiring: GKE Workload Identity Federation on the ServiceAccount for `gcpSecretStore`,
EKS IRSA or Pod Identity for `awsSecretStore`, and Azure Workload Identity or Pod Identity for `azureKeyVault`.

Use `existingSecret` when you manage the Kubernetes `Secret` yourself, on-premises or on any cluster. The
chart only mounts it.

## Providing the secrets

How the secret gets created depends on the backend. On `externalSecret` the chart assembles it for you from
your values and remote references. On the other four (`gcpSecretStore`, `awsSecretStore`, `azureKeyVault`, and
`existingSecret`) you provide a ready-made `secrets.toml` and the chart only mounts it. In that case you write
the files shown in [What the cell needs as secrets](#what-the-cell-needs-as-secrets), one per component you
enable: the aggregator app secret, the verifier app secret, the verifier bootstrap secret, and the verifier EVM
secret when an RPC URL carries an API key. On a cloud backend you store each file as a secret in that cloud's
secret manager; on `existingSecret` you create the Kubernetes `Secret`. The off-chain kit's
[Secrets](https://github.com/smartcontractkit/chainlink-ccv-starter-kit/blob/main/RUNBOOK.md#secrets)
documentation lists the mount path each file lands at, and the
[chart values reference](https://github.com/smartcontractkit/chainlink-ccv-starter-kit/blob/main/charts/ccv-cell/README.md)
has every field.

> **CAUTION: When you provide secrets.toml yourself**
>
> RPC URLs that carry an API key go in the verifier EVM secret, not in values. Config rendered from values lands in
> a ConfigMap, which cannot hold a credential.
>
> `keystoreBackend` and `kms.*` in values are ignored on these backends. Put the `[keystore]` block inside the
> `secrets.toml` you mount. See [Signer key custody and
> KMS](/ccip/ccv-starter-kit/how-to/signer-key-custody-and-kms).