Menu
Course/Deployment & Operations Patterns/External Configuration Store

External Configuration Store

Separate configuration from code: centralized config services (Consul, etcd, AWS Parameter Store), hot reloading, and secrets management.

10 min read

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:

TierTypeExamplesStore In
Non-sensitive configTunable parameters, URLs, timeoutsDB_HOST, CACHE_TTL, API_URLEnvironment variables, ConfigMap, Parameter Store
SecretsCredentials, private keys, tokensDB_PASSWORD, API_SECRET_KEYAWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets (encrypted)
Feature configRuntime behavior flags, thresholdsMAX_RETRY_COUNT, CIRCUIT_BREAKER_THRESHOLDExternal config store with hot reload

Popular External Configuration Stores

ServiceTypeKey FeaturesBest For
AWS Parameter Store (SSM)Managed cloud serviceHierarchical paths, IAM access control, free tierSimple config + light secrets in AWS
AWS Secrets ManagerManaged secrets serviceAuto-rotation, cross-account access, deep AWS integrationDatabase credentials, API keys in AWS
HashiCorp ConsulDistributed KV + service meshWatch-based change notification, health checks, multi-DCOn-prem + multi-cloud, service discovery combined
etcdDistributed KV storeWatch API, strong consistency (Raft), used by Kubernetes internallyKubernetes config, strongly-consistent needs
HashiCorp VaultSecrets managementDynamic secrets, PKI, lease-based secrets, audit logsEnterprise secrets, compliance requirements
GCP Secret Manager / Azure Key VaultManaged cloud secretsNative cloud IAM, versioning, audit logsGCP 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.
typescript
// 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.

📝

Knowledge Check

5 questions

Test your understanding of this lesson. Score 70% or higher to complete.

Ask about this lesson

Ask anything about External Configuration Store