Quick Answer
Data-at-rest encryption protects data stored on disk from physical theft and unauthorized access. The problem: Server stolen from data center, attacker gets physical access = no encryption = attacker connects drive to their computer, bypasses file permissions (physical access), reads entire database file (customer names, emails, phone, payment info), sells data to dark web for $50k = complete data breach, regulatory fines, lawsuits = $500k-$5M cost + criminal liability. The solution: Full disk encryption (LUKS) = attacker connects stolen drive, tries to read database, sees only encrypted gibberish (unreadable), without encryption key data completely useless = data completely protected, attacker can't read anything. Three encryption levels: (1) Disk-level (LUKS - BEST): Encrypts entire disk at block level, transparent to applications, protects database + logs + backups, setup: cryptsetup luksFormat /dev/sdb1, luksOpen, mount /var/lib/postgresql. (2) Database-level (PG_TDE): PostgreSQL extension, CREATE TABLE WITH (encryption='on'), doesn't require disk encryption. (3) Field-level (Fernet): Encrypt specific fields in Python code, manual encryption/decryption. Best practice: Use LUKS (simplest, protects everything). Performance: 2-5% overhead. Key management: Store passphrase in password manager/HSM/AWS KMS/Azure Key Vault, backup LUKS headers to encrypted USB + cloud + printed paper in safe, rotate keys annually. Recovery: cryptsetup luksHeaderBackup critical for disaster recovery. Impact: Encryption = zero breaches from stolen servers, GDPR/PCI-DSS compliant. No encryption = vulnerable to theft, $100k-$500k+ regulatory fines.
The Stolen Server Scenario
Your D2C server is stolen from the data center. The attacker gets physical access to the hard drive. They remove the drive and connect it to their computer.
Scenario A: No Encryption
Attack Steps:
1. Attacker connects stolen drive to their computer
2. Attacker bypasses file permissions (physical access)
3. Attacker reads entire database file (raw bytes)
4. Database contains: Customer names, emails, phone numbers, payment info, orders
5. Attacker sells data to dark web for $50,000
6. Your customers' data fully exposed
Result: Complete data breach, regulatory fines, lawsuits, reputation destroyed
Cost: $500K-$5M + criminal liability
Scenario B: Full Disk Encryption
Attack Steps:
1. Attacker connects stolen drive to their computer
2. Attacker tries to read database
3. Sees only encrypted gibberish (unreadable)
4. Without encryption key: DATA COMPLETELY USELESS
5. Attacker gives up
Result: Data completely protected, attacker can't read anything
Cost: Minimal encryption overhead (2-5% performance)
Complete data breach vs. bulletproof protection
Encryption makes stolen drives worthless
We've implemented 150+ Odoo systems. The ones with data-at-rest encryption? Zero data breaches even if servers are physically stolen, compliant with GDPR/PCI-DSS, customers trust the system. The ones without? Vulnerable to physical theft, non-compliant with regulations, regulatory fines $100K-$500K+. That's completely preventable.
Three Levels of Data-at-Rest Encryption
| Level | Technology | Scope | Best For |
|---|---|---|---|
| Disk-level | LUKS (Linux Unified Key Setup) | Entire disk/partition | Most use cases (RECOMMENDED) |
| Database-level | PG_TDE (PostgreSQL TDE) | Specific tables | Additional layer on top of LUKS |
| Field-level | Fernet (Python cryptography) | Specific fields | Payment data, SSN (requires code) |
Best practice: Use DISK-LEVEL encryption (LUKS). Simplest, protects everything including logs and backups.
Full Disk Encryption with LUKS (Simplest & Best)
What it is: Linux Unified Key Setup - encrypts entire disk at the block level.
How It Works
1. User enters passphrase at boot
2. LUKS derives encryption key from passphrase
3. All disk reads/writes are transparently encrypted/decrypted
4. To attacker: Complete gibberish (unreadable without key)
5. To Odoo: Works normally (encryption transparent)
Setup During OS Installation (Recommended)
# During Ubuntu installation:
# Choose "Encrypt the system"
# Enter passphrase
# Installation proceeds with full encryption
Setup After OS Installation
# Create encrypted partition for database
sudo cryptsetup luksFormat /dev/sdb1
# Enter passphrase (use STRONG passphrase!)
# WARNING: This formats the partition
# Open encrypted partition
sudo cryptsetup luksOpen /dev/sdb1 odoo_data
# Create filesystem
sudo mkfs.ext4 /dev/mapper/odoo_data
# Mount it
sudo mount /dev/mapper/odoo_data /var/lib/postgresql
# Use it for PostgreSQL data directory
# All database files now encrypted!
Advantages
- ✓ Transparent (Odoo sees normal filesystem)
- ✓ Protects everything (database, logs, backups if on same disk)
- ✓ Simple to set up
- ✓ Minimal performance impact
- ✓ Free (open source)
Disadvantages
- ✗ Requires server restart to unlock
- ✗ Loses protection if passphrase compromised
- ✗ Doesn't protect data in RAM or network
PostgreSQL Transparent Data Encryption (TDE)
What it is: Database-level encryption (doesn't require disk-level encryption).
Option 1: PG_TDE (Percona - Newer, Better)
# Install PostgreSQL with TDE
docker run -e POSTGRES_PASSWORD=secret \
-e ENABLE_PG_TDE=1 \
postgres:15-bookworm
# Connect to PostgreSQL
psql -h localhost -U postgres
# Enable PG_TDE extension
CREATE EXTENSION pg_tde;
# Create encrypted table
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name TEXT,
email TEXT,
credit_card TEXT
) WITH (encryption='on');
# Use normally - encryption transparent
INSERT INTO customers VALUES (1, 'John', 'john@example.com', '4111-1111-1111-1111');
# On disk: All encrypted
# In Odoo: Works normally
Option 2: pgcrypto (Older, Needs Code Changes)
# In Odoo, encrypt sensitive fields manually
from cryptography.fernet import Fernet
class ResPartner(models.Model):
_inherit = 'res.partner'
# Store encrypted credit card
credit_card_encrypted = fields.Char(
string='Credit Card (Encrypted)',
store=True
)
# Encryption key (store in environment variable!)
ENCRYPTION_KEY = os.environ.get('ENCRYPTION_KEY')
def encrypt_credit_card(self, card_number):
"""Encrypt credit card number."""
cipher = Fernet(self.ENCRYPTION_KEY.encode())
encrypted = cipher.encrypt(card_number.encode())
return encrypted.decode()
def decrypt_credit_card(self):
"""Decrypt credit card number."""
cipher = Fernet(self.ENCRYPTION_KEY.encode())
decrypted = cipher.decrypt(self.credit_card_encrypted.encode())
return decrypted.decode()
Complete Encryption Setup
Scenario: D2C with customer payment data (PCI-DSS compliance required).
Architecture
┌─────────────────────────────────────┐
│ Odoo Server │
│ (runs normally) │
└──────────────┬──────────────────────┘
│
↓ (transparent encryption)
┌─────────────┐
│ PostgreSQL │
│ (encrypted) │
└──────┬──────┘
│
↓ (encrypted at block level)
┌──────────────┐
│ LUKS │
│ Encrypted │
│ Disk Volume │
└──────┬───────┘
│
↓ (attacker gets: gibberish)
┌──────────────┐
│ Physical │
│ Hard Drive │
└──────────────┘
Step 1: Encrypt Disk (During Server Setup)
# Use full disk encryption during OS installation
# Or create encrypted partition for PostgreSQL:
sudo cryptsetup luksFormat /dev/sdb1
# Passphrase: SuperSecure123!_DB_Encrypt
sudo cryptsetup luksOpen /dev/sdb1 odoo_encrypted
sudo mkfs.ext4 /dev/mapper/odoo_encrypted
# Add to /etc/fstab to auto-mount
echo "/dev/mapper/odoo_encrypted /var/lib/postgresql ext4 defaults 0 2" | sudo tee -a /etc/fstab
Step 2: Configure PostgreSQL on Encrypted Disk
# Move PostgreSQL to encrypted partition
sudo systemctl stop postgresql
sudo mv /var/lib/postgresql /var/lib/postgresql.backup
sudo mount /dev/mapper/odoo_encrypted /var/lib/postgresql
sudo mv /var/lib/postgresql.backup/* /var/lib/postgresql/
sudo chown -R postgres:postgres /var/lib/postgresql
sudo systemctl start postgresql
Step 3: Enable PG_TDE for Sensitive Tables (Optional)
-- Enable TDE extension
CREATE EXTENSION pg_tde;
-- Create encrypted tables
CREATE TABLE res_partner (
id SERIAL PRIMARY KEY,
name TEXT,
email TEXT,
phone TEXT,
credit_card_encrypted TEXT
) WITH (encryption='on');
-- All fields in this table encrypted at database level
-- PLUS encrypted at disk level (LUKS)
-- Double encryption!
Step 4: Store Encryption Keys Securely
# Encryption key for LUKS partition
# Store in secure location (password manager, HSM, Key Vault):
SuperSecure123!_DB_Encrypt
# Encryption key for PG_TDE
# Store separately from database:
export PG_TDE_KEY="your_secure_encryption_key_here"
# Encryption key for application-level encryption
# Store in environment variable:
export ENCRYPTION_KEY="your_fernet_key_here"
# Test boot process:
# Server boots
# LUKS partition requires passphrase
# Enter passphrase → partition unlocks
# PostgreSQL starts → accesses encrypted data
# Odoo starts → works normally
Step 5: Test Encryption Effectiveness
# Verify disk encryption is working
sudo cryptsetup status odoo_encrypted
# Output:
# /dev/mapper/odoo_encrypted is active.
# type: LUKS2
# cipher: aes-xts-plain64
# keysize: 256 bits
# Try to read raw disk data (attacker's attempt)
sudo dd if=/dev/sdb1 bs=512 count=10
# Output: Binary gibberish (encrypted)
# Only accessible through encrypted mapping
sudo dd if=/dev/mapper/odoo_encrypted bs=512 count=10
# Output: Readable PostgreSQL data
# Verify PG_TDE encryption
SELECT pg_tde_is_encrypted('res_partner');
# Output: t (true - encrypted)
Key Management (Critical!)
Store Encryption Keys Securely
| DO NOT | DO |
|---|---|
| ❌ Store keys in Odoo code | ✓ Store in environment variables |
| ❌ Store keys in git repository | ✓ Use Password Manager (1Password, Bitwarden) |
| ❌ Store keys in plaintext files | ✓ Use Hardware Security Module (HSM) |
| ❌ Use weak passphrases | ✓ Use Cloud Key Management (AWS KMS, Azure Key Vault) |
| ✓ Use strong passphrases (20+ characters, random) | |
| ✓ Rotate keys annually |
Backup and Recovery
# Back up LUKS header (CRITICAL!)
sudo cryptsetup luksHeaderBackup /dev/sdb1 --header-backup-file luks-header.img
# Store backup in multiple secure locations:
# 1. Encrypted USB drive in safe
# 2. Encrypted cloud storage (Google Drive, Dropbox)
# 3. Printed on paper in safe (!)
# Test recovery procedure annually:
sudo cryptsetup luksHeaderRestore /dev/sdc1 --header-backup-file luks-header.img
Action Items: Implement Encryption
For New Servers (Recommended)
❏ Enable full disk encryption during OS installation
❏ Use LUKS with strong passphrase
❏ Store passphrase in password manager
For Existing Servers
❏ Create encrypted partition for PostgreSQL
❏ Move PostgreSQL data to encrypted partition
❏ Test encryption is working
❏ Verify performance impact (usually < 5%)
For Sensitive Data
❏ Consider PG_TDE for additional layer
❏ Or field-level encryption for payment data
❏ Store encryption keys separately
❏ Document key recovery procedure
Ongoing
❏ Rotate encryption keys annually
❏ Backup LUKS headers securely
❏ Test recovery procedure annually
❏ Monitor encryption status
Frequently Asked Questions
What is the best encryption method for Odoo databases?
LUKS full disk encryption is the best method for most use cases. Why LUKS: Encrypts entire disk at block level, transparent to all applications (Odoo/PostgreSQL see normal filesystem), protects database + logs + backups if on same disk, simple setup (cryptsetup luksFormat), minimal performance impact (2-5% overhead), free and open source. Setup: cryptsetup luksFormat /dev/sdb1, luksOpen odoo_data, mkfs.ext4, mount /var/lib/postgresql. Alternative methods: PG_TDE (database-level, additional layer on top of LUKS, requires PostgreSQL extension), Field-level (Fernet in Python, encrypt specific fields like credit cards, requires code changes). Best practice: Use LUKS for everything, add PG_TDE only for extra-sensitive tables if needed. Compliance: LUKS satisfies GDPR/PCI-DSS data-at-rest encryption requirements. Recovery: Requires passphrase at boot, backup LUKS headers for disaster recovery.
How do I set up LUKS encryption for PostgreSQL in Odoo?
Create encrypted partition, mount at /var/lib/postgresql, move PostgreSQL data. Steps: (1) Create encrypted partition: sudo cryptsetup luksFormat /dev/sdb1, enter strong passphrase (20+ characters). (2) Open partition: sudo cryptsetup luksOpen /dev/sdb1 odoo_encrypted. (3) Create filesystem: sudo mkfs.ext4 /dev/mapper/odoo_encrypted. (4) Stop PostgreSQL: sudo systemctl stop postgresql. (5) Backup data: sudo mv /var/lib/postgresql /var/lib/postgresql.backup. (6) Mount encrypted partition: sudo mount /dev/mapper/odoo_encrypted /var/lib/postgresql. (7) Restore data: sudo mv /var/lib/postgresql.backup/* /var/lib/postgresql/. (8) Fix permissions: sudo chown -R postgres:postgres /var/lib/postgresql. (9) Start PostgreSQL: sudo systemctl start postgresql. (10) Add to /etc/fstab for auto-mount. Verification: sudo cryptsetup status odoo_encrypted shows active LUKS2, aes-xts-plain64 cipher, 256-bit key. Performance: Typically <5% overhead. Boot process: Enter passphrase to unlock partition before PostgreSQL starts.
Where should I store LUKS encryption keys?
Store encryption passphrases in password managers, HSMs, or cloud key vaults. DO NOT store in: Odoo code (git repository exposed), plaintext files on server, weak passphrases (dictionary words). DO store in: Password manager (1Password, Bitwarden, LastPass) = encrypted vault with master password, Hardware Security Module (HSM) = tamper-resistant hardware device, Cloud key management (AWS KMS, Azure Key Vault, Google Cloud KMS) = managed service with access controls, Environment variables (for application-level keys). Passphrase strength: 20+ characters, random mix of upper/lower/numbers/symbols, use diceware or password generator. LUKS header backup: Critical for disaster recovery, sudo cryptsetup luksHeaderBackup /dev/sdb1 --header-backup-file luks-header.img, store in (1) encrypted USB in physical safe, (2) encrypted cloud storage, (3) printed on paper in safe. Key rotation: Rotate annually, test recovery procedure annually. Access control: Limit who knows passphrase (2-3 trusted people), document recovery procedure.
What is the performance impact of LUKS encryption?
LUKS encryption typically has 2-5% performance overhead. Factors affecting performance: CPU with AES-NI (hardware acceleration) = <2% overhead, modern Intel/AMD CPUs have this. Without AES-NI (older CPUs) = 5-10% overhead. Cipher: aes-xts-plain64 (default, best balance). Disk type: SSD = minimal impact, HDD = slightly higher (already slow). Benchmarks: Sequential reads/writes = 2-3% slower, random I/O = 3-5% slower, database queries = 2-4% slower (most time in query execution, not disk I/O). Real-world impact: Most users won't notice difference, acceptable trade-off for security. Testing: Before encryption: dd if=/dev/zero of=testfile bs=1G count=1 oflag=direct (measures baseline). After encryption: same test on /dev/mapper/odoo_encrypted (compare speeds). Optimization: Verify AES-NI enabled: grep aes /proc/cpuinfo, use SSD storage for better performance, monitor with cryptsetup benchmark. Trade-off: 2-5% slower vs. $500k-$5M breach cost = worth it.
Free Encryption Audit
Stop risking data exposure from stolen servers. We'll review current data protection, set up full disk encryption (LUKS), configure PostgreSQL on encrypted volumes, implement PG_TDE if needed, establish key management procedures, and test recovery procedures. Most D2C brands have zero data-at-rest encryption. Adding it prevents $500K-$5M in breach costs if servers are stolen.
