Secrets & ConfigMaps
How Rune stores configuration data — encrypted secrets and plaintext configmaps — and how services consume them.
Both secrets and configmaps are namespaced key-value resources you mount into services. They differ in one important way: secrets are encrypted at rest.
Secrets
A secret holds sensitive material — API keys, tokens, certificates, passwords.
secret:
name: db-credentials
namespace: default
data:
username: admin
password: hunter2
data: also accepts a list of {key, value} pairs, and multiple secrets can be declared as a secrets: list — both forms parse to the same thing. Apply with rune cast. Or imperatively:
rune create secret db-credentials \
--from-literal=username=admin \
--from-literal=password=hunter2
rune create secret tls-cert \
--from-file=tls.crt=./certs/server.crt \
--from-file=tls.key=./certs/server.key
How secrets are encrypted
Rune uses envelope encryption:
plaintext ──▶ AES-256-GCM (DEK) ──▶ ciphertext ─┐
│ stored together
DEK ──▶ AES-256-GCM (KEK) ──▶ wrapped DEK ─┘
- A 32-byte KEK (Key Encryption Key) is loaded once on server start from a file, env var, or generated and persisted with mode
0600. - A fresh DEK (Data Encryption Key) is generated for every secret version.
- Associated data binds the ciphertext to
(namespace, name, version)— moving bytes around the database breaks decryption.
Consequence: lose the KEK, lose every secret. Back it up.
See Security hardening for KEK rotation guidance.
ConfigMaps
ConfigMaps are the same shape as secrets — namespaced key-value pairs — but stored in plaintext. Use them for non-sensitive config (log levels, feature flags, service URLs).
configmap:
name: app-settings
namespace: default
data:
log-level: info
feature-x: enabled
rune create config app-settings \
--from-literal=log-level=info \
--from-file=app.toml=./config/app.toml
Consuming from a service
Mount as files
service:
name: api
image: ghcr.io/example/api:1.0.0
secretMounts:
- name: db-secret
secretName: db-credentials
mountPath: /etc/secrets/db
configmapMounts:
- name: app-config
configmapName: app-settings
mountPath: /etc/config
Each key becomes a file: /etc/secrets/db/username, /etc/config/log-level, etc.
Mount as environment variables
service:
name: api
image: ghcr.io/example/api:1.0.0
envFrom:
- secret: db-credentials
- configmap: app-settings
env:
LOG_FORMAT: json # plain env vars still work alongside
Each key becomes an env var. Conflicts: explicit env: wins over envFrom:.
Updating values
Re-apply with rune cast. The secret/configmap version increments. Services that mount it pick up the new value on the next instance restart — Rune does not hot-reload mounted files.
To roll services after a config change:
rune restart api
Listing and inspecting
rune get secrets
rune get secret db-credentials -o yaml # values are NOT printed
rune get configs
rune get config app-settings -o yaml
For secrets, only metadata comes back. There's no API to read plaintext — the only way out is to mount it into a service.
Referencing a secret from another resource
A few places outside a service spec (notably StorageClass parameters)
accept a string-form secret reference instead of a literal value.
Two forms:
| Form | Syntax | Namespace resolution |
|---|---|---|
| Shorthand | secret:<name>/<key> | Same namespace as the consuming resource. |
| FQDN | secret:<name>.<namespace>.rune/<key> | Explicit namespace — independent of the consumer. |
Reach for the FQDN form whenever the consuming resource is cluster-scoped (e.g. a StorageClass shared across namespaces) or when you want one secret to serve many namespaces. Shorthand is fine inside a namespaced resource that already has its own namespace (a Volume override, for example).
Naming and limits
- Names must match DNS-1123 (
[a-z0-9]([-a-z0-9]*[a-z0-9])?). - Per-secret data limits are enforced server-side (configurable in the runefile).
- Total number of versions kept per secret is also configurable — older versions are garbage-collected.