Configuration and Secrets
Environment variables, config maps, secure secret management, and tools like Vault to protect sensitive data.
The principle: separate configuration from code
One of the fundamental rules of modern deployment is that configuration should not live in the code. The same artifact (Docker image, binary, bundle) must be able to run in any environment — the only thing that changes is the configuration.
This includes:
- Database and external service URLs
- Credentials and access tokens
- Feature flags and behavior parameters
- Logging levels and timeouts
- Third-party API keys
Environment variables
Environment variables are the most basic and universal mechanism for injecting configuration into an application.
Advantages
- Supported by every language and platform
- Easy to configure in containers, CI/CD, and cloud providers
- No additional libraries required
Best practices
# Nombres descriptivos en UPPER_SNAKE_CASE
DATABASE_URL=postgres://user:pass@host:5432/db
REDIS_URL=redis://localhost:6379
LOG_LEVEL=info
API_TIMEOUT_MS=5000
FEATURE_NEW_CHECKOUT=true
- Use a
.env.examplefile in the repository documenting all required variables (without real values) - Never commit
.envfiles with real values - Validate the variables at application startup — fail fast if a required one is missing
Startup validation
function validateEnv() {
const required = ['DATABASE_URL', 'REDIS_URL', 'JWT_SECRET'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing env vars: ${missing.join(', ')}`);
}
}
ConfigMaps in Kubernetes
In Kubernetes, ConfigMaps let you store non-sensitive configuration as key-value pairs and mount them into pods.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
API_TIMEOUT: "30s"
MAX_CONNECTIONS: "100"
FEATURE_FLAGS: |
{
"newCheckout": true,
"darkMode": false
}
Inject as environment variables
spec:
containers:
- name: my-app
envFrom:
- configMapRef:
name: app-config
Mount as a file
spec:
containers:
- name: my-app
volumeMounts:
- name: config-volume
mountPath: /app/config
volumes:
- name: config-volume
configMap:
name: app-config
Secret management
Secrets (passwords, tokens, private keys) require special handling. They should never be in:
- The source code
- Committed configuration files
- Application logs
- Docker images
Kubernetes Secrets
Kubernetes provides a Secret resource for sensitive data:
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
stringData:
DATABASE_PASSWORD: "mi-password-seguro"
JWT_SECRET: "mi-jwt-secret"
API_KEY: "mi-api-key"
Important limitation: Kubernetes Secrets are stored in etcd base64-encoded, but they are not encrypted by default. For greater security, enable encryption at rest or use an external secret manager.
HashiCorp Vault
Vault is the most popular tool for centralized secret management:
- Secure storage: secrets are encrypted at rest
- Controlled access: granular policies for who can read which secrets
- Automatic rotation: secrets can be rotated without redeploying
- Auditing: complete record of who accessed which secret and when
- Dynamic secrets: generates temporary credentials on demand (e.g., DB credentials that expire in 1 hour)
Other tools
- AWS Secrets Manager: native secret management in AWS with automatic rotation
- Google Secret Manager: the GCP equivalent
- Azure Key Vault: the Azure equivalent
- SOPS: encrypts configuration files that can be committed safely
Secret rotation
Secrets should be rotated periodically to minimize the impact of a leak:
- Generate a new secret: create the new credential in the secret manager
- Update the application: the application reads the new secret (ideally without a restart)
- Verify operation: confirm that everything works with the new secret
- Revoke the old secret: delete the old credential
Zero-downtime rotation
To rotate secrets without downtime, the application must temporarily support dual credentials:
- Accept both the old and the new secret during a transition period
- Once everything is confirmed working, revoke the old one
General best practices
- Principle of least privilege: each service accesses only the secrets it needs
- Don’t log secrets: sanitize logs so they never expose credentials
- Encrypt in transit and at rest: TLS for communication, encryption at rest for storage
- Audit access: record who accesses which secrets and when
- Automate rotation: don’t rely on manual processes to rotate credentials
- Separate configuration from secrets: non-sensitive configuration goes in ConfigMaps, secrets go in a dedicated manager
Summary
Configuration and secrets are critical aspects of deployment. Environment variables and ConfigMaps handle non-sensitive configuration, while tools like Vault, AWS Secrets Manager, or Kubernetes Secrets protect sensitive data. The key is to separate configuration from code, validate at startup, and rotate secrets periodically.