Use secrets & configmaps
Mount sensitive credentials and non-sensitive config into a service, two different ways.
You usually need both. Database passwords go in a secret. Log levels and feature flags go in a configmap. Both mount into the same service.
1. Create the data
rune create secret db-credentials \
--from-literal=username=appuser \
--from-literal=password=s3cret
rune create config app-settings \
--from-literal=log-level=info \
--from-literal=feature-x=enabled
Or via YAML:
secrets:
- name: db-credentials
namespace: default
data:
- { key: username, value: appuser }
- { key: password, value: s3cret }
configmaps:
- name: app-settings
namespace: default
data:
- { key: log-level, value: info }
- { key: feature-x, value: enabled }
rune cast data.yaml
2. Mount as files
service:
name: api
image: ghcr.io/example/api:1.0.0
scale: 1
secretMounts:
- name: db-secret
secretName: db-credentials
mountPath: /etc/secrets/db
configmapMounts:
- name: app-config
configmapName: app-settings
mountPath: /etc/config
Inside the container:
/etc/secrets/db/username → appuser
/etc/secrets/db/password → s3cret
/etc/config/log-level → info
/etc/config/feature-x → enabled
3. Or mount as environment variables
service:
name: api
image: ghcr.io/example/api:1.0.0
scale: 1
envFrom:
- secret: db-credentials
- configmap: app-settings
env:
LOG_FORMAT: json # explicit env still works alongside
The container sees:
USERNAME=appuser
PASSWORD=s3cret
LOG_LEVEL=info
FEATURE_X=enabled
LOG_FORMAT=json
4. Update a value
Configmap — replace the whole thing
rune create config app-settings \
--from-literal=log-level=debug \
--from-literal=feature-x=enabled \
--replace
Secret — rotate one key without wiping the others
If a secret holds several keys, use rune secret set to update just one. The
server reads the existing data, merges your change, and writes a new version
atomically — you never have to re-supply (or even know) the values of the
other keys.
# Rotate one key in a multi-key secret
rune secret set gateway-secrets -n prod \
INFRA_ENCRYPTION_PASSPHRASE=new-passphrase
# Rotate several at once
rune secret set gateway-secrets -n prod \
INFRA_JWT_SECRET=jwt-v2 INFRA_ENCRYPTION_PASSPHRASE=pass-v2
# Load a binary/PEM value from a file
rune secret set tls-secret -n prod --from-file=cert=./cert.pem
# Remove a key that's no longer needed
rune secret unset gateway-secrets -n prod LEGACY_TOKEN
set and unset only require the secrets:update RBAC verb — not
secrets:reveal. A CI bot that rotates a JWT secret never gains the ability
to read the other secrets sitting next to it. Each operation creates a new
version that's visible in rune secret versions and rollback-able with
rune secret rollback.
If you genuinely want to replace the entire data map (e.g. from a script
that owns the full secret), use rune secret update instead — that wipes
any keys you don't include.
Tell the service to pick up the new value
Mounted values do not hot-reload. Restart the service to pick up the new value:
rune restart api
5. Inspect — but secrets stay opaque
rune get configs
rune get config app-settings -o yaml # values visible
rune get secrets
rune get secret db-credentials -o yaml # values NOT printed
There's no API to read secret plaintext from outside. The only path is to mount it into a service and read it from inside the container.
6. Delete
rune delete config app-settings
rune delete secret db-credentials
If a service still references the resource, deletion will refuse unless you pass --force.
Common mistakes
- Forgetting to restart after updating a mounted secret/config. Files don't hot-reload.
- Putting credentials in a configmap. Configmaps are plaintext. Use a secret.
- Cross-namespace mounts. Not supported — the service and the secret must share a namespace.
- DNS-1123 names. Names must be lowercase alphanumeric + dashes, starting and ending with alphanumeric.
See also
- Secrets & ConfigMaps concept — encryption details.
- Security hardening — KEK rotation.