Secrets
Runix can resolve secret values from external sources, keeping sensitive data out of your config files.
Secret Configuration
Define secrets at the top level of runix.yaml:
secrets:
db_password:
type: env
value: DB_PASSWORD
api_key:
type: file
value: /run/secrets/api_key
vault_secret:
type: vault
value: secret/data/myapp#password
Secret Types
Environment Variable (env)
Reads the value from an environment variable on the host:
secrets:
db_password:
type: env
value: DB_PASSWORD
The environment variable must be set when Runix starts. If it's not set, the process fails to start with an error:
secret "db_password": environment variable "DB_PASSWORD" not set
File (file)
Reads the value from a file on disk:
secrets:
tls_cert:
type: file
value: /etc/tls/server.crt
The file contents are read and trimmed of leading/trailing whitespace. If the file doesn't exist or isn't readable, the process fails to start.
Vault (vault)
secrets:
db_password:
type: vault
value: secret/database#password
Runix reads Vault secrets using:
VAULT_ADDR: Vault base URL, for examplehttp://127.0.0.1:8200VAULT_TOKEN: token used for the request
The value format is path#key.
- logical KV v2 path:
secret/database#password - explicit KV v2 API path:
secret/data/database#password - KV v1 path:
secret/database#password
Runix tries KV v2 first, then falls back to KV v1. If the secret key is not present or Vault returns a non-200 response, process startup fails with an error.
Using Secrets in Processes
Secrets are injected into process environment variables:
secrets:
db_password:
type: env
value: DB_PASSWORD
processes:
api:
entrypoint: ./cmd/api
env:
DATABASE_URL: "postgres://user:${db_password}@localhost:5432/mydb"
Secret Masking
The secrets.MaskValue() function provides safe display of secret values:
| Input | Masked Output |
|---|---|
short | **** |
my-secret-key | my****ey |
abc | **** |
Values with 4 or fewer characters are fully masked. Longer values show the first 2 and last 2 characters.
Implementation
The resolver is at internal/secrets/resolver.go:
func Resolve(cfg map[string]types.SecretRef) (map[string]string, error)
func MaskValue(val string) string
func IsSecretEnv(key string, secretKeys map[string]bool) bool
Security Considerations
- Secret values are never written to log files
- The event store does not include secret values in payloads
- Socket permissions (
0o660) limit who can communicate with the daemon - File-based secrets should use restrictive permissions (e.g.,
0o600)
What's Next
- Configuration Reference — Full YAML schema
- Features: Secrets Resolution — How secrets are resolved at runtime