Skip to content
Navigation

Type at least two characters. Search covers page titles, headings, tags and database names.

↑ ↓ to navigateEnter to openEsc to close0 pages
Production Best Practicesintermediate

Security Hardening

The baseline every production database needs — network isolation, authentication, least privilege, secret handling and encryption.

3 min readIntermediateUpdated Edit this page

Database defaults are chosen to make the first connection succeed, not to make the deployment safe. Hardening is the work of undoing that.

Network first

The most effective control is that unauthorised parties cannot reach the port at all.

  • Bind to a private interface; no database port reachable from the public internet.
  • Restrict by source range at both the security-group and the engine level (pg_hba.conf, MySQL host-based grants, Redis bind plus protected-mode).
  • Put administrative access behind a bastion or an identity-aware proxy, and log those sessions.

Authentication

  • Remove or rename default accounts, and never leave a default password in place.
  • Prefer certificate or identity-provider authentication over passwords for human access.
  • Use per-service accounts, not one shared application account, so access can be revoked and attributed individually.
  • Require TLS for client connections and for replication, and verify the certificate chain on the client — encryption without verification does not prevent interception.

Least privilege

The application account should own no schema and should have only the statements it runs.

-- PostgreSQL: an application role that can use the data but not reshape it.
CREATE ROLE app_service LOGIN PASSWORD :'password';
GRANT CONNECT ON DATABASE shop TO app_service;
GRANT USAGE ON SCHEMA public TO app_service;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_service;
 
-- Cover tables created later by the migration role.
ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_service;

Migrations run as a separate role that owns the objects. Analysts get a read-only role. See Authorization.

Secrets Management

  • Store credentials in a secret manager and inject them at runtime. Not in code, not in a container image, not in a repository — including its history.
  • Prefer short-lived, dynamically issued credentials where the platform supports them; a credential that expires in an hour limits the value of leaking it.
  • Keep secrets out of logs and error messages. Connection strings with embedded passwords end up in stack traces and monitoring systems.
  • Rotate on a schedule and immediately when someone with access leaves. Rotation must be a practised procedure, not a theoretical capability — see Secret Rotation.

Encryption

Three separate concerns, often confused:

  • In transit. TLS between clients and the database, and between cluster nodes. Replication traffic frequently carries the same data as client traffic and is more often left unencrypted.
  • At rest. Volume-level or engine-level encryption. It protects against disk theft and improperly decommissioned storage. It does not protect against a compromised database account, because the engine decrypts transparently for anyone who can log in.
  • Backups. Encrypt them, and store the key somewhere recoverable independently of the database. A backup you cannot decrypt is not a backup. See Backup Encryption.

Application-level encryption for specific sensitive columns is the only form that protects against a compromised database account, at the cost of losing the ability to index or search those columns.

Auditing

Log authentication failures, privilege changes, DDL and administrative connections, and ship them somewhere the database administrators cannot silently alter. Retain them long enough to investigate something discovered weeks later. See Audit Logs.