Running PostgreSQL in FIPS-Compliant Mode
PostgreSQL stores sensitive data and transmits it across networks. FIPS compliance requires that all cryptographic operations use validated modules. This document covers configuring PostgreSQL with FIPS-approved TLS, encryption, and authentication.
Prerequisites
You will need PostgreSQL version 13 or later, as earlier versions have limited FIPS support. You'll also need OpenSSL 3.0 or later with the FIPS module (CMVP #4949). Finally, you should have either a FIPS-enabled operating system or the ability to configure FIPS on your system.
PostgreSQL with FIPS OpenSSL
Build PostgreSQL Against FIPS OpenSSL
# Install FIPS-validated OpenSSLsudo apt-get install libssl3-fips openssl-fips # Download PostgreSQL sourcewget https://ftp.postgresql.org/pub/source/v15.4/postgresql-15.4.tar.gztar xzf postgresql-15.4.tar.gzcd postgresql-15.4 # Configure against FIPS OpenSSL./configure \ --prefix=/usr/lib/postgresql \ --with-openssl \ LDFLAGS="-L/usr/lib/fips" \ CPPFLAGS="-I/usr/include/fips" # Build and installmakesudo make install # Verify FIPS module/usr/lib/postgresql/bin/postgres --versionldd /usr/lib/postgresql/bin/postgres | grep libssl# Should show FIPS-enabled libssl pathDocker Build with FIPS
# Dockerfile: FIPS PostgreSQLFROM ubuntu:24.04-fips # Install FIPS OpenSSL and build toolsRUN apt-get update && apt-get install -y \ libssl3-fips \ openssl-fips \ postgresql-contrib=15.4-1 # Verify FIPS moduleRUN openssl version | grep -i fips || exit 1 # PostgreSQL configurationCOPY postgresql.conf /etc/postgresql/15/main/postgresql.confCOPY pg_hba.conf /etc/postgresql/15/main/pg_hba.conf EXPOSE 5432CMD ["/usr/lib/postgresql/bin/postgres", "-D", "/var/lib/postgresql/15/main"]TLS Configuration
Enable TLS with FIPS-Approved Ciphers
# postgresql.conf # Enable SSL/TLSssl = onssl_cert_file = '/etc/postgresql/15/main/server.crt'ssl_key_file = '/etc/postgresql/15/main/server.key'ssl_protocols = 'TLSv1.2,TLSv1.3' # Use only FIPS-approved ciphers# TLS 1.3 ciphers (FIPS-approved)# - TLS_AES_256_GCM_SHA384# - TLS_AES_128_GCM_SHA256# - TLS_CHACHA20_POLY1305_SHA256 (not FIPS, excluded) # TLS 1.2 ciphers (FIPS-approved)# - ECDHE-RSA-AES256-GCM-SHA384# - ECDHE-RSA-AES128-GCM-SHA256# - DHE-RSA-AES256-GCM-SHA384# - DHE-RSA-AES128-GCM-SHA256 # OpenSSL will automatically filter to FIPS-approved ciphers# when FIPS module is activeGenerate FIPS-Compliant Certificates
# Generate 2048-bit RSA key (FIPS-approved minimum)openssl genrsa -out server.key 2048 # Generate CSRopenssl req -new \ -key server.key \ -out server.csr \ -subj "/CN=postgres.example.com" # Self-sign certificate (for testing)openssl x509 -req \ -in server.csr \ -signkey server.key \ -out server.crt \ -days 365 \ -sha256 # FIPS-approved hash algorithm # Set permissions (required by PostgreSQL)chmod 600 server.key server.crtchown postgres:postgres server.key server.crtClient Certificate Authentication (FIPS)
# postgresql.conf # Enable client certificate verificationssl_ca_file = '/etc/postgresql/15/main/ca.crt' # pg_hba.conf - Client certificate auth with TLShostssl mydb myuser 0.0.0.0/0 cert# Create CA key and certificateopenssl genrsa -out ca.key 2048openssl req -new -x509 \ -key ca.key \ -out ca.crt \ -days 3650 \ -subj "/CN=PostgreSQL-CA" # Create client certificateopenssl genrsa -out client.key 2048openssl req -new \ -key client.key \ -out client.csr \ -subj "/CN=myuser" # Sign with CAopenssl x509 -req \ -in client.csr \ -CA ca.crt \ -CAkey ca.key \ -CAcreateserial \ -out client.crt \ -days 365 \ -sha256 # Client connectionpsql -h postgres.example.com \ -U myuser \ -d mydb \ --cert=client.crt \ --key=client.key \ --ca-cert=ca.crtEncryption at Rest
PostgreSQL has limited built-in encryption. Use one of the following approaches:
1. Transparent Data Encryption (TDE)
# Install pgcrypto extension (uses OpenSSL FIPS)psql -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;" # Encrypt sensitive columnsCREATE TABLE users ( id SERIAL PRIMARY KEY, email TEXT, password_hash TEXT); -- Store hashed passwords (pgcrypto uses OpenSSL FIPS)INSERT INTO users (email, password_hash) VALUES ('alice@example.com', crypt('SecurePassword123', gen_salt('bf'))); -- Verify with FIPS moduleSELECT crypt('SecurePassword123', password_hash) = password_hashFROM users WHERE email = 'alice@example.com';2. LUKS Disk Encryption
Encrypt PostgreSQL data directory at the operating system level:
# Create LUKS-encrypted volumesudo cryptsetup luksFormat /dev/sdb1# Enter passphrase (FIPS-compliant crypto) # Open encrypted volumesudo cryptsetup luksOpen /dev/sdb1 postgres-data # Format and mountsudo mkfs.ext4 /dev/mapper/postgres-datasudo mount /dev/mapper/postgres-data /var/lib/postgresql # Move PostgreSQL data directorysudo mv /var/lib/postgresql/* /var/lib/postgresql/15/main # Start PostgreSQL (reads from encrypted volume)sudo systemctl start postgresql3. Block Device Encryption
# Dockerfile: PostgreSQL with encrypted storageFROM ubuntu:24.04-fips RUN apt-get update && apt-get install -y \ postgresql-15 \ cryptsetup \ openssl-fips # Setup scriptCOPY setup-encryption.sh /RUN chmod +x /setup-encryption.sh ENTRYPOINT ["/setup-encryption.sh"]FIPS-Compliant Authentication
SCRAM-SHA-256
PostgreSQL's default password authentication is FIPS-compliant:
-- PostgreSQL 10+ uses SCRAM-SHA-256 by default-- Hash is computed with FIPS-approved SHA-256 -- Verify in postgresql.conf-- password_encryption = 'scram-sha256' (default) -- Create user with SCRAM-SHA-256CREATE USER alice WITH PASSWORD 'SecurePassword123';-- Password is hashed with SHA-256 (FIPS-approved)FIPS-Compliant LDAP Integration
# pg_hba.conf - LDAP with TLS (FIPS)hostssl mydb @admins 0.0.0.0/0 ldap \ ldapserver=ldap.example.com \ ldapport=636 \ ldaptls=1 \ ldapscheme=ldapsLDAPS uses TLS with FIPS-approved ciphers.
FIPS Verification
Verify PostgreSQL Uses FIPS Module
# Check OpenSSL linkageldd $(which postgres) | grep ssl# libssl.so => /usr/lib/fips/libssl.so (FIPS)# libcrypto.so => /usr/lib/fips/libcrypto.so (FIPS) # Check TLS configurationpsql -c "SHOW ssl_protocols;"# Result: TLSv1.2,TLSv1.3 (FIPS-approved) # Test TLS connectionpsql -h postgres.example.com \ -U postgres \ -d postgres \ -c "SHOW ssl_version;"# Result: TLSv1.3 (or TLSv1.2)Automated FIPS Verification
# CleanStart FIPS verificationcleanimg-init --fips-verifier --image mypostgres:15 # Output:# ✓ PostgreSQL 15.4 uses FIPS OpenSSL# ✓ TLS 1.2/1.3 enabled with FIPS ciphers# ✓ Client certificate auth is FIPS-compliant# ✓ Password hashing uses SCRAM-SHA-256# ✓ Encryption uses OpenSSL FIPS module# ✓ No non-FIPS cryptography detectedCommon Issues and Solutions
Issue: SSL Certificate Error
ERROR: certificate verify failedSOLUTION:1. Ensure certificate is signed with FIPS-approved algorithm (SHA-256)2. Check certificate CN matches hostname3. Verify CA certificate is in trusted storeIssue: Unsupported Cipher Suite
SSL: SSLV3_ALERT_HANDSHAKE_FAILURESOLUTION:This usually means:1. Client is using non-FIPS cipher2. FIPS module is properly filtering (working as expected)3. Client must use FIPS-approved ciphersIssue: LDAP TLS Connection Fails
ERROR: LDAP bind failed with FIPSSOLUTION:1. Ensure LDAP server supports TLS 1.2+2. Verify FIPS module is active (not disabled)3. Test TLS connection outside PostgreSQL: openssl s_client -connect ldap.example.com:636Performance Considerations
FIPS operations have minimal overhead, typically around 2-5% for TLS operations, which is acceptable for most workloads. A 2048-bit RSA key is the standard size, though larger keys will increase latency slightly. GCM cipher modes are both fast and FIPS-approved.
Compliance Mapping
Requirement | Implementation |
|---|---|
FIPS 140-3 | OpenSSL 3.0 module #4949 |
NIST 800-171 SC-13 | SCRAM-SHA-256, TLS 1.3, RSA-2048 |
PCI DSS 3.4 | TLS 1.2+, AES-256-GCM |
HIPAA § 164.312(a)(2)(i) | Encryption in transit (TLS) and at rest (LUKS) |
SOC 2 CC6.2 | Strong cryptography (FIPS-approved algorithms) |
See Also
FIPS Overview: fips-140-overview.md — FIPS concepts and validation. FIPS Traces: fips-traces.md — Runtime cryptographic audit. FIPS Verifier: fips-verifier.md — Automated compliance checking.
