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.example file in the repository documenting all required variables (without real values)
  • Never commit .env files 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:

  1. Generate a new secret: create the new credential in the secret manager
  2. Update the application: the application reads the new secret (ideally without a restart)
  3. Verify operation: confirm that everything works with the new secret
  4. 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

  1. Principle of least privilege: each service accesses only the secrets it needs
  2. Don’t log secrets: sanitize logs so they never expose credentials
  3. Encrypt in transit and at rest: TLS for communication, encryption at rest for storage
  4. Audit access: record who accesses which secrets and when
  5. Automate rotation: don’t rely on manual processes to rotate credentials
  6. 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.