External Configuration Store
Separate configuration from code: centralized config services (Consul, etcd, AWS Parameter Store), hot reloading, and secrets management.
Why Externalize Configuration?
The Twelve-Factor App methodology's third factor states: store config in the environment. Configuration that varies between environments (database connection strings, API keys, feature thresholds, third-party service URLs) must not be baked into application code or container images. Baked-in config means a different build for each environment — defeating the promise of immutable infrastructure.
Beyond the Twelve-Factor rationale, there are operational reasons to centralize configuration: auditability (who changed what config and when?), hot reloading (change config without restarting), access control (not every engineer should see database passwords), and consistency (one source of truth for config shared across a fleet of 1000 instances).
Configuration Tiers
Not all config is the same. A useful mental model is three tiers:
| Tier | Type | Examples | Store In |
|---|---|---|---|
| Non-sensitive config | Tunable parameters, URLs, timeouts | DB_HOST, CACHE_TTL, API_URL | Environment variables, ConfigMap, Parameter Store |
| Secrets | Credentials, private keys, tokens | DB_PASSWORD, API_SECRET_KEY | AWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets (encrypted) |
| Feature config | Runtime behavior flags, thresholds | MAX_RETRY_COUNT, CIRCUIT_BREAKER_THRESHOLD | External config store with hot reload |
Popular External Configuration Stores
| Service | Type | Key Features | Best For |
|---|---|---|---|
| AWS Parameter Store (SSM) | Managed cloud service | Hierarchical paths, IAM access control, free tier | Simple config + light secrets in AWS |
| AWS Secrets Manager | Managed secrets service | Auto-rotation, cross-account access, deep AWS integration | Database credentials, API keys in AWS |
| HashiCorp Consul | Distributed KV + service mesh | Watch-based change notification, health checks, multi-DC | On-prem + multi-cloud, service discovery combined |
| etcd | Distributed KV store | Watch API, strong consistency (Raft), used by Kubernetes internally | Kubernetes config, strongly-consistent needs |
| HashiCorp Vault | Secrets management | Dynamic secrets, PKI, lease-based secrets, audit logs | Enterprise secrets, compliance requirements |
| GCP Secret Manager / Azure Key Vault | Managed cloud secrets | Native cloud IAM, versioning, audit logs | GCP or Azure workloads |
Hot Reloading: Changing Config Without Restarts
A key advantage of external config stores over environment variables is hot reloading: the application can pick up config changes without a restart or redeployment. This is critical for operational toggles — you want to change a timeout or circuit breaker threshold in an emergency without triggering a deploy.
Hot reload is typically implemented via one of two patterns:
- Polling: The application periodically fetches the config from the store (e.g., every 30 seconds). Simple to implement, slightly stale config (up to the poll interval).
- Watch / Push: The config store pushes changes to the application via long-polling, SSE, or gRPC streams. Consul's watch API, etcd's Watch API, and AWS AppConfig's deployment strategies support this. Near-instant propagation.
// AWS AppConfig with hot reload — Node.js example
import { AppConfigDataClient, StartConfigurationSessionCommand, GetLatestConfigurationCommand } from '@aws-sdk/client-appconfigdata';
class ConfigManager {
private client = new AppConfigDataClient({ region: 'us-east-1' });
private sessionToken: string | undefined;
private config: Record<string, unknown> = {};
async init() {
const session = await this.client.send(new StartConfigurationSessionCommand({
ApplicationIdentifier: 'my-app',
EnvironmentIdentifier: process.env.ENV,
ConfigurationProfileIdentifier: 'app-config',
}));
this.sessionToken = session.InitialConfigurationToken;
await this.poll(); // initial fetch
setInterval(() => this.poll(), 30_000); // poll every 30s
}
private async poll() {
const result = await this.client.send(new GetLatestConfigurationCommand({
ConfigurationToken: this.sessionToken,
}));
this.sessionToken = result.NextPollConfigurationToken;
if (result.Configuration?.length) {
this.config = JSON.parse(Buffer.from(result.Configuration).toString());
}
}
get<T>(key: string, defaultVal: T): T {
return (this.config[key] as T) ?? defaultVal;
}
}
const cfg = new ConfigManager();
await cfg.init();
// In request handler — reads current config value without restart
const timeout = cfg.get<number>('upstream_timeout_ms', 5000);Secrets Management Best Practices
Secrets require additional controls beyond plain config values:
- Never commit secrets to version control. Even if you delete them later, git history retains them. Use `git-secrets` or pre-commit hooks to prevent accidental commits.
- Use dynamic secrets where possible. AWS Secrets Manager and Vault can generate short-lived database credentials on demand. An application gets a credential valid for 1 hour. Even if leaked, it expires quickly.
- Rotate secrets regularly. Automated rotation (AWS Secrets Manager supports Lambda-based auto-rotation) eliminates manual rotation risk.
- Scope access with IAM / policies. An instance only has permission to read the secrets it needs. Principle of least privilege applied to config.
- Audit secret access. AWS CloudTrail and Vault audit logs record every read. If credentials are leaked, you can see who accessed them and when.
Kubernetes Secrets Are Not Encrypted by Default
Kubernetes Secrets are base64-encoded, not encrypted. Anyone with etcd access can read them. In production, enable etcd encryption at rest and use a KMS provider. Better yet, use an external secrets operator (External Secrets Operator + AWS Secrets Manager) so secrets are never stored in etcd at all.
Config in Kubernetes: ConfigMaps and Beyond
Kubernetes provides `ConfigMap` for non-sensitive config and `Secret` for credentials. Both can be mounted as files or injected as environment variables. However, ConfigMaps and Secrets do not hot-reload automatically into environment variables — you need to restart pods for environment variable changes.
For hot-reload in Kubernetes, use one of these approaches: mount configs as files (Kubernetes updates mounted files automatically within ~1 minute of a ConfigMap update) and have your application watch the file for changes, or use an operator like Reloader that automatically rolls deployments when referenced ConfigMaps/Secrets change.
Interview Tip
When discussing external config stores, differentiate between config (non-sensitive, can be logged, can be committed to version control with environment-specific overrides) and secrets (never logged, never committed, minimum access). Mention dynamic secrets as the gold standard for databases — it's a concept that impresses interviewers. And always note the Kubernetes Secrets gotcha: base64 is not encryption.