
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Securing sensitive data requires implementing database encryption at rest and in transit as a non-negotiable baseline for any production system handling PII, financial records, or health information. While many teams enable TLS on the application layer, they frequently leave the database connection unencrypted or storage volumes unprotected, creating critical gaps that fail SOC 2 and ISO 27001 audits. This guide provides the exact configurations and architectural patterns needed to close those gaps without sacrificing performance or operational visibility.
How do you configure database encryption at rest and in transit for PostgreSQL?
PostgreSQL requires explicit configuration for both encryption layers; neither is enabled by default in most distributions. For database encryption at rest and in transit, you must address filesystem-level protection separately from network transport security. In practice, I recommend combining Transparent Data Encryption (TDE) via extensions like pg_tde for column/table-level granularity with full-disk encryption (LUKS or EBS encryption) as a defense-in-depth measure. For transit, enforce TLS 1.3 minimum and disable older protocol versions explicitly.
Enforcing TLS 1.3 connections
Edit your postgresql.conf to require SSL and specify strong ciphers. Never rely on client-side defaults:
# postgresql.conf
ssl = on
ssl_cert_file = '/etc/ssl/certs/server.crt'
ssl_key_file = '/etc/ssl/private/server.key'
ssl_ca_file = '/etc/ssl/certs/ca.crt'
ssl_min_protocol_version = 'TLSv1.3'
ssl_ciphers = 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256' Then restrict pg_hba.conf to reject non-SSL connections entirely. Use hostssl instead of host for all remote entries:
# pg_hba.conf - Reject plaintext connections
hostssl all all 0.0.0.0/0 scram-sha-256
hostssl replication replicator 10.0.0.0/24 scram-sha-256
# Explicitly deny non-SSL (optional but recommended for audit clarity)
host all all 0.0.0.0/0 reject Verify enforcement by connecting with psql "sslmode=require" and checking SELECT * FROM pg_stat_ssl;. Any connection showing ssl = false indicates a misconfiguration. For deeper context on securing PostgreSQL deployments, see the PostgreSQL administration essentials guide which covers complementary hardening steps.
Implementing storage encryption
For self-managed instances, use LUKS2 with AES-XTS-PLAIN64:
# Create encrypted volume (destructive - backup first!)
cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 \
--key-size 512 --hash sha512 /dev/sdb
cryptsetup open /dev/sdb pgdata_encrypted
mkfs.ext4 /dev/mapper/pgdata_encrypted
mount /dev/mapper/pgdata_encrypted /var/lib/postgresql/data On AWS RDS/Aurora, enable encryption at creation time using AWS KMS customer-managed keys (CMK). Note that you cannot encrypt an existing unencrypted RDS instance in-place; you must create an encrypted snapshot and restore from it. Always enable automated key rotation in KMS and restrict key policies to the RDS service principal only.
What is the difference between TDE and application-level encryption?
Understanding this distinction prevents costly architectural mistakes during database encryption at rest and in transit implementations. Transparent Data Encryption operates below the database engine, encrypting entire tablespaces or files automatically without schema changes. Application-level encryption encrypts specific fields before they reach the database, requiring code modifications but providing finer-grained control over what gets protected and who holds decryption keys.
| Criteria | Transparent Data Encryption (TDE) | Application-Level Encryption |
|---|---|---|
| Implementation Effort | Low — config change or volume flag | High — code changes, key management integration |
| Query Performance | Near-zero overhead (hardware AES-NI) | Significant — prevents indexing on encrypted columns |
| Search Capability | Full — DB sees plaintext after decryption | Limited — requires blind indexing or deterministic encryption |
| Key Separation | DB admin can access decrypted data | App holds keys; DB stores only ciphertext |
| Compliance Fit | SOC 2, ISO 27001 baseline | HIPAA, PCI-DSS field-level requirements |
| Backup Protection | Encrypted backups automatic | Backups contain ciphertext regardless |
In my experience helping Nepal-based fintech companies achieve compliance, TDE satisfies most audit requirements for general data protection. Reserve application-level encryption for highly regulated fields (credit card numbers, national IDs) where even DBA access must be prevented. Combining both approaches—TDE for bulk protection plus app-level for sensitive columns—provides the strongest posture but increases operational complexity significantly.
How do you manage encryption keys for SOC 2 and ISO 27001 compliance?
Key management separates compliant database encryption at rest and in transit implementations from checkbox exercises. Auditors scrutinize key lifecycle controls more than the encryption algorithm itself. You must demonstrate separation of duties, automated rotation, and tamper-evident logging. Never store encryption keys on the same server as the database or in application config files.
- Use managed KMS services (AWS KMS, Azure Key Vault, GCP Cloud KMS) for cloud workloads. These provide HSM-backed key storage, automatic rotation schedules, and CloudTrail/Audit Log integration out of the box.
- Implement envelope encryption: KMS encrypts data encryption keys (DEKs), and DEKs encrypt actual data. This limits KMS API calls and allows efficient key rotation without re-encrypting terabytes of data.
- Restrict key policies to least privilege. The database service should only have
kms:Decryptandkms:GenerateDataKeypermissions, neverkms:CreateKeyorkms:DisableKey. - Automate rotation every 90 days minimum for SOC 2 Type II. Configure alerts for rotation failures—missed rotations are common audit findings.
- Log all key usage and ship logs to immutable storage. Enable KMS key policy conditions requiring secure transport (
aws:SecureTransport) to prevent accidental plaintext API calls.
For on-premises or hybrid environments in Nepal where cloud KMS isn't viable, HashiCorp Vault provides equivalent capabilities with self-hosted HSM integration. See the secrets management with HashiCorp Vault guide for deployment patterns that satisfy audit requirements without cloud vendor lock-in.
What are common mistakes when implementing database encryption at rest and in transit?
After reviewing dozens of production setups across AWS, Azure, and self-managed infrastructure, these errors appear repeatedly in database encryption at rest and in transit projects:
- Assuming cloud defaults are sufficient. AWS RDS encryption is opt-in at creation. Azure SQL TDE uses Microsoft-managed keys by default, which some auditors reject for high-sensitivity data. Always verify and document your key ownership model.
- Leaving localhost connections unencrypted. Many configs enforce TLS for remote hosts but allow plaintext on
127.0.0.1. Containerized apps connecting via localhost bypass transit encryption entirely. Use Unix sockets with proper permissions or enforce TLS even for loopback. - Ignoring backup encryption. Your database may be encrypted, but if
pg_dumpor native backups write plaintext to S3/GCS, you've defeated the purpose. Configure backup encryption explicitly and test restoration quarterly. - Certificate expiry causing outages. TLS certificates expire. Set up monitoring for certificate validity windows (alert at 30, 14, and 7 days). Automate renewal with cert-manager for Kubernetes or ACM for AWS. Manual certificate management doesn't scale.
- Performance testing only after go-live. Encryption adds CPU overhead. Benchmark with realistic loads before production. Modern CPUs with AES-NI handle TDE with <5% overhead, but application-level encryption on indexed columns can cause 10-50x query slowdowns. Test early.
A frequent oversight in Nepal's growing tech sector is neglecting data residency implications when using cloud KMS. If your data must remain within national borders per local regulations, ensure the KMS region matches your database region and document this in your compliance evidence. Cross-region key access can violate residency requirements even if the data itself never leaves the country.
How do you verify database encryption at rest and in transit is working correctly?
Configuration alone isn't proof. Auditors and penetration testers demand evidence that database encryption at rest and in transit functions as designed under real conditions. Build verification into your CI/CD pipeline and operational runbooks rather than treating it as a pre-audit scramble.
Transit verification commands
For PostgreSQL, query the SSL status view directly:
-- Check all active connections for encryption status
SELECT pid, usename, client_addr, ssl, version, cipher
FROM pg_stat_ssl
JOIN pg_stat_activity USING (pid)
WHERE ssl = false AND client_addr IS NOT NULL; Any rows returned indicate unencrypted remote connections. Integrate this as a failing check in your Prometheus monitoring fundamentals setup by exporting it as a gauge metric. Alert immediately when the count exceeds zero.
For MySQL/MariaDB, run SHOW STATUS LIKE 'Ssl_cipher'; on each connection or query performance_schema.tls_channel_status in MySQL 8.0+. On the network level, use sshd -T | grep ciphers and nmap --script ssl-enum-ciphers -p 5432 db-host to validate that weak protocols are truly disabled.
At-rest verification
Confirm volume encryption with cloud CLI tools:
# AWS RDS
aws rds describe-db-instances \
--db-instance-identifier mydb \
--query 'DBInstances[0].{Encrypted:StorageEncrypted,KMS:KmsKeyId}'
# Verify EBS volume encryption for self-managed
aws ec2 describe-volumes \
--volume-ids vol-0abc123 \
--query 'Volumes[0].Encrypted' For LUKS-encrypted self-managed volumes, run cryptsetup status pgdata_encrypted and verify the cipher matches your policy. Document these checks in your compliance evidence repository and automate execution weekly. Manual verification drifts; automated checks don't.
Implementing Database Encryption at Rest and In Transit Securely
Effective database encryption at rest and in transit combines correct technical configuration with disciplined key management and continuous verification. Start with TDE and TLS 1.3 as your baseline, add application-level encryption only where threat models demand it, and automate evidence collection from day one. Compliance isn't a feature you bolt on—it's an outcome of engineering rigor applied consistently.
If your team needs help designing encryption architecture that passes audits without slowing development, or if you're preparing for SOC 2 certification and want to avoid common encryption pitfalls, reach out to discuss your specific infrastructure. I've helped organizations across Nepal and globally implement encryption strategies that satisfy both auditors and performance requirements.