diff --git a/guides/create-secret/dictionary.mdx b/guides/create-secret/dictionary.mdx index 7ae2fd0f..7958a924 100644 --- a/guides/create-secret/dictionary.mdx +++ b/guides/create-secret/dictionary.mdx @@ -258,6 +258,10 @@ This creates: - `/etc/config/DB_NAME` containing `myapp_production` - `/etc/config/DB_SSL_MODE` containing `require` + +A directory mount is refreshed when the secret changes, without a redeployment. See [Live Secret Updates](/reference/workload/volumes#live-secret-updates). + + --- ## Common Patterns diff --git a/llms.txt b/llms.txt index 7e4ee9cd..dd217cf5 100644 --- a/llms.txt +++ b/llms.txt @@ -147,6 +147,8 @@ Three steps are required for a workload to access a secret at runtime (this is t | `aws` | `cpln://secret/NAME.accessKey` / `.secretKey` / `.roleArn` | | `gcp` | `cpln://secret/NAME` (typically a volume mount — JSON file) | +**Secret updates need a redeploy, with one exception**: a `dictionary` secret mounted as a directory (`uri: cpln://secret/NAME`, no `.KEY`, `path` a directory) is refreshed in the running container within about 10 minutes, and the app must re-read the files. Env vars, single-key file mounts, and opaque secrets keep the old value until `cpln workload force-redeployment`. See https://docs.controlplane.com/reference/workload/volumes#live-secret-updates + Control Plane supports **12 secret types**: `opaque`, `dictionary`, `userpass`, `aws`, `gcp`, `azure-sdk`, `azure-connector`, `docker`, `ecr`, `tls`, `keypair`, `nats-account`. **`cpln secret create` does NOT exist** — use `create-opaque`, `create-aws`, `create-gcp`, etc. (12 type-specific variants). **Don't set `spec.identityLink` unless the workload actually needs secret access, credential-free cloud access, or private network access.** Empty identity assignments complicate debugging and audit traces. diff --git a/reference/secret.mdx b/reference/secret.mdx index 56160b4e..4898c6a4 100644 --- a/reference/secret.mdx +++ b/reference/secret.mdx @@ -624,7 +624,7 @@ For example, if the image assigned to a container belongs to a private Docker re ## Updating Secrets -If a secret value is updated, any workload referencing that secret will need to be redeployed. +If a secret value is updated, any workload referencing that secret will need to be redeployed. The exception is a [dictionary](#dictionary) secret mounted as a directory, which is refreshed in the running container. See [Live Secret Updates](/reference/workload/volumes#live-secret-updates). ## Access Report diff --git a/reference/workload/volumes.mdx b/reference/workload/volumes.mdx index 24eb60f3..25395b25 100644 --- a/reference/workload/volumes.mdx +++ b/reference/workload/volumes.mdx @@ -1,7 +1,7 @@ --- title: Volumes description: Mount cloud object storage, file storage, ephemeral scratch storage, and secrets to workload containers at runtime. -keywords: ['s3', 'gcs', 'azure blob', 'efs', 'nfs', 'tmpfs', 'volume mount path', 'object storage uri', 'mount secret', 'secret as file', 'shared volume', 'cpln volume'] +keywords: ['s3', 'gcs', 'azure blob', 'efs', 'nfs', 'tmpfs', 'volume mount path', 'object storage uri', 'mount secret', 'secret as file', 'shared volume', 'cpln volume', 'secret rotation', 'secret update', 'live reload'] --- ## Overview @@ -137,3 +137,22 @@ The Path must be a unique absolute path and, optionally, a file name (e.g., /sec A maximum of 15 volumes can be added. + +## Live Secret Updates + +A running workload picks up a new secret value without a redeployment when a [dictionary](/reference/secret#dictionary) secret is mounted as a directory. Reference the whole secret, not a key, and set `path` to a directory: + +```yaml +spec: + containers: + - name: app + volumes: + - uri: cpln://secret/app-config + path: /etc/app-config +``` + +Each key is mounted as a file in `/etc/app-config`. After you update the secret, the files are replaced in place. + +- **Propagation is not instant.** Allow up to about 10 minutes for the new value to appear. +- **The application must reload the file.** Control Plane does not restart or signal the container. The files are swapped atomically through a symlink, so watch the directory (not a single file) or re-read the file on a timer. +- **Other references are fixed at startup.** Environment variables, a single key mounted as a file (`cpln://secret/app-config.KEY`), and opaque secrets keep their old value until the workload is redeployed (`cpln workload force-redeployment WORKLOAD --gvc GVC`). diff --git a/skill.md b/skill.md index 65afd5f7..941b7635 100644 --- a/skill.md +++ b/skill.md @@ -259,6 +259,8 @@ Reference syntax in env vars / volumes: **Injection methods**: env var (`cpln://secret/NAME...`), volume mount (large/multi-file/GCP JSON), or **pull secret at GVC level** (`spec.pullSecretLinks` — `docker`, `ecr`, `gcp` types only). +**Updating a secret value**: only a `dictionary` secret mounted as a directory (`uri: cpln://secret/NAME`, no `.KEY`) refreshes in the running container (within about 10 minutes, and the app must re-read the files). Everything else needs `cpln workload force-redeployment`. + ## CLI essentials ### Setup