Data Encryption at Rest: Complete Implementation Guide
Introduction
Data encryption at rest is a fundamental security control that protects stored data from unauthorized access in the event of physical theft, unauthorized system access, or improper disposal of storage media. In today's regulatory environment, with frameworks like GDPR, HIPAA, PCI-DSS, and SOC 2 mandating strong data protection measures, encryption at rest has evolved from a best practice to a compliance requirement for organizations handling sensitive information.
This comprehensive guide provides Linux system administrators with practical, in-depth knowledge of implementing encryption at rest across various storage layers—from full disk encryption to database-level encryption, file system encryption, and application-level encryption. Whether you're protecting customer data, financial information, healthcare records, or intellectual property, this guide covers the technical implementations, key management strategies, and operational procedures necessary to secure data at rest effectively.
Why Data Encryption at Rest Matters
Traditional perimeter security—firewalls, intrusion detection systems, and access controls—cannot protect data once an attacker bypasses these defenses or when storage media is physically compromised. Encryption at rest ensures that even if an attacker gains access to storage devices, backup tapes, or database files, the data remains cryptographically protected and unusable without the proper encryption keys.
Common Threat Scenarios Mitigated by Encryption at Rest:
- Physical Device Theft: Laptops, servers, or backup drives stolen from data centers, offices, or during transport
- Insider Threats: Malicious or negligent employees with physical access to storage systems
- Improper Disposal: Hard drives, SSDs, or backup media discarded without secure wiping
- Cloud Storage Breaches: Unauthorized access to cloud storage buckets or volumes
- Database File Exposure: Direct access to database files bypassing application-level access controls
- Backup Media Compromise: Lost or stolen backup tapes, external drives, or cloud backup credentials
- Forensic Analysis: Protection against forensic examination of seized equipment
Encryption at Rest vs. Encryption in Transit
It's critical to understand that encryption at rest and encryption in transit serve different purposes and must both be implemented for comprehensive data protection:
- Encryption at Rest: Protects data stored on disk, in databases, or in backups when the system is powered off or when files are not actively being accessed
- Encryption in Transit: Protects data as it moves across networks using protocols like TLS/SSL, SSH, or VPNs
A complete security strategy requires both. This guide focuses exclusively on encryption at rest.
Encryption Approaches Overview
There are multiple layers where encryption at rest can be implemented, each with different use cases, performance implications, and management requirements:
- Full Disk Encryption (FDE): Encrypts entire disk partitions or volumes at the block level
- File System Encryption: Encrypts individual files or directories within a file system
- Database Encryption: Built-in encryption features provided by database management systems
- Application-Level Encryption: Encryption implemented within applications before data is written to storage
- Hardware-Based Encryption: Self-encrypting drives (SEDs) that handle encryption at the hardware level
This guide covers all these approaches with practical implementation examples for Linux systems.
Understanding Encryption Technologies
Encryption Algorithms and Standards
Modern encryption at rest primarily uses symmetric encryption algorithms due to their performance characteristics:
AES (Advanced Encryption Standard)
- Most widely used symmetric encryption algorithm
- Key sizes: 128-bit, 192-bit, 256-bit (AES-256 recommended for sensitive data)
- NIST-approved standard (FIPS 140-2 compliant)
- Excellent performance with hardware acceleration (AES-NI)
- Used in: LUKS, dm-crypt, BitLocker, FileVault, most database encryption
Modes of Operation
- AES-CBC (Cipher Block Chaining): Traditional mode, requires IV management
- AES-XTS: Designed specifically for disk encryption, IEEE standard
- AES-GCM (Galois/Counter Mode): Provides both encryption and authentication
Other Algorithms
- Blowfish/Twofish: Legacy algorithms, less commonly used today
- ChaCha20: Modern stream cipher, good for systems without AES-NI
- Serpent: Alternative to AES, considered highly secure but slower
Key Management Fundamentals
The security of encrypted data ultimately depends on proper key management. Compromised encryption keys render encryption useless.
Key Management Principles:
- Key Generation: Use cryptographically secure random number generators
- Key Storage: Store keys separately from encrypted data
- Key Rotation: Periodically change encryption keys
- Key Backup: Securely backup keys to prevent data loss
- Key Destruction: Securely destroy old keys when no longer needed
- Access Control: Restrict key access to authorized systems/personnel only
Key Storage Options:
- Hardware Security Modules (HSM): Dedicated hardware for key storage and cryptographic operations
- Key Management Services (KMS): Cloud-based key management (AWS KMS, Azure Key Vault, Google Cloud KMS)
- TPM (Trusted Platform Module): Hardware chip for storing encryption keys on endpoints
- File-Based Keys: Keys stored in protected files (requires careful permission management)
- Passphrase-Based Keys: Keys derived from user passphrases using KDFs
Full Disk Encryption with LUKS
LUKS (Linux Unified Key Setup) is the standard for disk encryption on Linux systems, providing a platform-independent format specification and comprehensive key management.
Installing LUKS
# Install cryptsetup (LUKS implementation)
sudo apt-get update
sudo apt-get install -y cryptsetup cryptsetup-bin # Debian/Ubuntu
sudo yum install -y cryptsetup-luks # RHEL/CentOS
# Verify installation
cryptsetup --version
Creating Encrypted Partitions
Important: Encrypting a partition destroys all existing data. Always backup first.
# Identify the target partition or disk
lsblk -f
sudo fdisk -l
# Create LUKS encrypted partition
# WARNING: This will erase all data on /dev/sdb1
sudo cryptsetup luksFormat /dev/sdb1
# You will be prompted to confirm and set a passphrase
# Choose a strong passphrase (minimum 20 characters recommended)
# Verify LUKS header
sudo cryptsetup luksDump /dev/sdb1
Opening and Using Encrypted Volumes
# Open the encrypted partition
sudo cryptsetup luksOpen /dev/sdb1 encrypted_volume
# The decrypted volume is now available at /dev/mapper/encrypted_volume
# Create a file system on the encrypted volume
sudo mkfs.ext4 /dev/mapper/encrypted_volume
# Create mount point and mount
sudo mkdir -p /mnt/encrypted
sudo mount /dev/mapper/encrypted_volume /mnt/encrypted
# Verify mount
df -h | grep encrypted
# Use the encrypted volume normally
sudo chown -R user:user /mnt/encrypted
echo "Sensitive data" | sudo tee /mnt/encrypted/test.txt
# Unmount and close when done
sudo umount /mnt/encrypted
sudo cryptsetup luksClose encrypted_volume
Automatic Mounting with Key Files
For servers that need automatic mounting without user interaction, use key files instead of passphrases:
# Generate a random key file
sudo dd if=/dev/urandom of=/root/luks-keys/data-volume.key bs=4096 count=1
# Secure the key file
sudo chmod 400 /root/luks-keys/data-volume.key
sudo chown root:root /root/luks-keys/data-volume.key
# Add key file to LUKS header (allows multiple keys)
sudo cryptsetup luksAddKey /dev/sdb1 /root/luks-keys/data-volume.key
# Verify key slots
sudo cryptsetup luksDump /dev/sdb1 | grep "Key Slot"
# Test opening with key file
sudo cryptsetup luksOpen /dev/sdb1 encrypted_volume --key-file=/root/luks-keys/data-volume.key
# Configure automatic mounting via /etc/crypttab
echo "encrypted_volume /dev/sdb1 /root/luks-keys/data-volume.key luks" | sudo tee -a /etc/crypttab
# Configure mount point in /etc/fstab
echo "/dev/mapper/encrypted_volume /mnt/encrypted ext4 defaults 0 2" | sudo tee -a /etc/fstab
# Test configuration
sudo mount -a
df -h | grep encrypted
LUKS Key Management
# View current key slots
sudo cryptsetup luksDump /dev/sdb1
# Add additional passphrase/key (up to 8 key slots)
sudo cryptsetup luksAddKey /dev/sdb1
# Remove a key slot (requires another valid key)
sudo cryptsetup luksRemoveKey /dev/sdb1
# Change passphrase
sudo cryptsetup luksChangeKey /dev/sdb1
# Kill a specific key slot (if you know which slot)
sudo cryptsetup luksKillSlot /dev/sdb1 1
# Backup LUKS header (critical for recovery)
sudo cryptsetup luksHeaderBackup /dev/sdb1 --header-backup-file /secure/backup/sdb1-luks-header.img
# Restore LUKS header (if corrupted)
# sudo cryptsetup luksHeaderRestore /dev/sdb1 --header-backup-file /secure/backup/sdb1-luks-header.img
Performance Tuning for LUKS
# Check current cipher and key size
sudo cryptsetup luksDump /dev/sdb1 | grep -E "Cipher|Key"
# Benchmark different ciphers
cryptsetup benchmark
# Create LUKS volume with specific cipher and key size
sudo cryptsetup luksFormat /dev/sdb1 \
--cipher aes-xts-plain64 \
--key-size 512 \
--hash sha256 \
--iter-time 2000
# Check if AES-NI hardware acceleration is available
grep -m1 -o aes /proc/cpuinfo
# Monitor encryption performance
sudo cryptsetup luksDump /dev/sdb1
sudo dmsetup table encrypted_volume
LUKS Encryption for LVM
Encrypting LVM (Logical Volume Manager) volumes provides flexibility for dynamic volume management:
# Create encrypted partition first
sudo cryptsetup luksFormat /dev/sdb1
sudo cryptsetup luksOpen /dev/sdb1 encrypted_pv
# Create LVM physical volume on encrypted device
sudo pvcreate /dev/mapper/encrypted_pv
# Create volume group
sudo vgcreate encrypted_vg /dev/mapper/encrypted_pv
# Create logical volumes
sudo lvcreate -L 50G -n data encrypted_vg
sudo lvcreate -L 30G -n backups encrypted_vg
# Create file systems
sudo mkfs.ext4 /dev/encrypted_vg/data
sudo mkfs.ext4 /dev/encrypted_vg/backups
# Mount volumes
sudo mkdir -p /mnt/data /mnt/backups
sudo mount /dev/encrypted_vg/data /mnt/data
sudo mount /dev/encrypted_vg/backups /mnt/backups
# Add to /etc/crypttab and /etc/fstab for automatic mounting
echo "encrypted_pv /dev/sdb1 /root/luks-keys/lvm.key luks" | sudo tee -a /etc/crypttab
echo "/dev/encrypted_vg/data /mnt/data ext4 defaults 0 2" | sudo tee -a /etc/fstab
echo "/dev/encrypted_vg/backups /mnt/backups ext4 defaults 0 2" | sudo tee -a /etc/fstab
File System Level Encryption
eCryptfs - Stacked File System Encryption
eCryptfs encrypts individual files and directories without requiring dedicated partitions:
# Install eCryptfs
sudo apt-get install -y ecryptfs-utils # Debian/Ubuntu
sudo yum install -y ecryptfs-utils # RHEL/CentOS
# Create directories
sudo mkdir -p /encrypted-data
sudo mkdir -p /mnt/decrypted
# Mount encrypted directory
sudo mount -t ecryptfs /encrypted-data /mnt/decrypted
# You will be prompted for:
# - Passphrase
# - Cipher (aes recommended)
# - Key bytes (16 = 128-bit, 32 = 256-bit)
# - Enable plaintext passthrough (no)
# - Enable filename encryption (yes for maximum security)
# Save the mount options shown for future use
# Use the decrypted mount point normally
echo "Sensitive file content" | sudo tee /mnt/decrypted/secret.txt
# Files are encrypted in /encrypted-data
sudo ls -la /encrypted-data # Shows encrypted filenames
cat /encrypted-data/* # Shows encrypted content
# Files are readable in /mnt/decrypted
cat /mnt/decrypted/secret.txt # Shows plaintext
# Unmount when done
sudo umount /mnt/decrypted
# Automate mounting via /etc/fstab
echo "/encrypted-data /mnt/decrypted ecryptfs defaults 0 0" | sudo tee -a /etc/fstab
# Note: Still requires interactive passphrase unless using key file
FSCRYPT - Native File System Encryption
FSCRYPT provides native encryption for ext4, F2FS, and UBIFS file systems:
# Install fscrypt
sudo apt-get install -y fscrypt libpam-fscrypt # Debian/Ubuntu
# Setup fscrypt on file system
sudo fscrypt setup
# Setup fscrypt on specific mount point
sudo fscrypt setup /home
# Create encrypted directory
sudo mkdir /home/encrypted_project
sudo fscrypt encrypt /home/encrypted_project
# Choose encryption policy:
# 1. Your login passphrase
# 2. A custom passphrase
# 3. A raw key file
# Use the encrypted directory
echo "secret data" | sudo tee /home/encrypted_project/data.txt
# View encryption status
sudo fscrypt status /home/encrypted_project
# Lock directory (makes it inaccessible)
sudo fscrypt lock /home/encrypted_project
# Unlock directory
sudo fscrypt unlock /home/encrypted_project
# Change passphrase
sudo fscrypt metadata change-passphrase --protector=/home
EncFS - Userspace Encrypted File System
EncFS provides encryption in userspace, useful for cloud storage scenarios:
# Install EncFS
sudo apt-get install -y encfs # Debian/Ubuntu
sudo yum install -y encfs # RHEL/CentOS
# Create directories
mkdir -p ~/encrypted-source
mkdir -p ~/encrypted-mount
# Create encrypted file system
encfs ~/encrypted-source ~/encrypted-mount
# Choose configuration:
# - x (expert mode) for custom settings
# - p (paranoid mode) for maximum security
# - Standard configuration for defaults
# Set encryption password
# Use mounted directory
echo "secret" > ~/encrypted-mount/file.txt
# Data is encrypted in source directory
cat ~/encrypted-source/* # Encrypted content
# Unmount
fusermount -u ~/encrypted-mount
# Remount with saved configuration
encfs ~/encrypted-source ~/encrypted-mount
# Automount on login (add to ~/.bashrc)
echo "encfs ~/encrypted-source ~/encrypted-mount" >> ~/.bashrc
Database Encryption at Rest
MySQL/MariaDB Encryption
Table-Level Encryption
# Enable encryption plugin
sudo tee -a /etc/mysql/mariadb.conf.d/50-server.cnf << 'EOF'
[mysqld]
# Encryption plugin
plugin_load_add = file_key_management
file_key_management_filename = /etc/mysql/encryption/keyfile.enc
file_key_management_filekey = FILE:/etc/mysql/encryption/keyfile.key
file_key_management_encryption_algorithm = AES_CTR
# Enable encryption features
innodb_encrypt_tables = ON
innodb_encrypt_log = ON
innodb_encryption_threads = 4
encrypt_binlog = ON
encrypt_tmp_files = ON
EOF
# Create encryption key directory
sudo mkdir -p /etc/mysql/encryption
sudo chmod 750 /etc/mysql/encryption
sudo chown mysql:mysql /etc/mysql/encryption
# Generate encryption keys
# Master key
sudo openssl rand -hex 32 > /etc/mysql/encryption/keyfile.key
sudo chmod 600 /etc/mysql/encryption/keyfile.key
sudo chown mysql:mysql /etc/mysql/encryption/keyfile.key
# Data encryption keys file
cat | sudo tee /etc/mysql/encryption/keyfile.enc << 'EOF'
1;0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
2;FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210
EOF
sudo chmod 600 /etc/mysql/encryption/keyfile.enc
sudo chown mysql:mysql /etc/mysql/encryption/keyfile.enc
# Restart MySQL
sudo systemctl restart mysql
# Verify encryption status
mysql -u root -p -e "SHOW VARIABLES LIKE '%encrypt%';"
# Create encrypted table
mysql -u root -p << 'EOF'
CREATE DATABASE encrypted_db;
USE encrypted_db;
CREATE TABLE sensitive_data (
id INT PRIMARY KEY AUTO_INCREMENT,
customer_name VARCHAR(255),
credit_card VARBINARY(256),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
-- Verify table encryption
SELECT
TABLE_SCHEMA,
TABLE_NAME,
CREATE_OPTIONS
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_SCHEMA = 'encrypted_db';
EOF
# Encrypt existing unencrypted tables
mysql -u root -p << 'EOF'
USE your_database;
ALTER TABLE existing_table ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
EOF
Tablespace Encryption
# Enable general tablespace encryption
mysql -u root -p << 'EOF'
-- Set default encryption for new tables
SET GLOBAL default_table_encryption=ON;
-- Encrypt system tablespace
ALTER INSTANCE ROTATE INNODB MASTER KEY;
-- Create encrypted tablespace
CREATE TABLESPACE encrypted_space
ADD DATAFILE 'encrypted_space.ibd'
ENCRYPTION='Y';
-- Create table in encrypted tablespace
CREATE TABLE secure_data (
id INT PRIMARY KEY,
data TEXT
) TABLESPACE=encrypted_space;
-- Check encryption status
SELECT
SPACE,
NAME,
SPACE_TYPE,
ENCRYPTION
FROM
INFORMATION_SCHEMA.INNODB_TABLESPACES
WHERE
ENCRYPTION='Y';
EOF
Key Rotation
# Create key rotation script
cat > /root/scripts/mysql_key_rotation.sh << 'EOF'
#!/bin/bash
# MySQL Encryption Key Rotation
LOG_FILE="/var/log/mysql/key_rotation.log"
echo "$(date): Starting MySQL encryption key rotation" | tee -a "$LOG_FILE"
# Backup current keys
cp /etc/mysql/encryption/keyfile.enc /etc/mysql/encryption/keyfile.enc.backup.$(date +%Y%m%d)
# Generate new key
NEW_KEY=$(openssl rand -hex 32)
NEW_KEY_ID=$(($(tail -1 /etc/mysql/encryption/keyfile.enc | cut -d';' -f1) + 1))
# Add new key to keyfile
echo "${NEW_KEY_ID};${NEW_KEY}" | sudo tee -a /etc/mysql/encryption/keyfile.enc
# Rotate master key
mysql -u root -p -e "ALTER INSTANCE ROTATE INNODB MASTER KEY;" 2>&1 | tee -a "$LOG_FILE"
echo "$(date): Key rotation completed. New key ID: ${NEW_KEY_ID}" | tee -a "$LOG_FILE"
echo "Remember to re-encrypt tables with new key ID if needed." | tee -a "$LOG_FILE"
EOF
chmod +x /root/scripts/mysql_key_rotation.sh
# Schedule annual key rotation
echo "0 2 1 1 * /root/scripts/mysql_key_rotation.sh" | sudo crontab -
PostgreSQL Encryption
PostgreSQL doesn't have native table-level encryption, but offers several encryption options:
pgcrypto Extension
# Enable pgcrypto extension
sudo -u postgres psql -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
# Create table with encrypted columns
sudo -u postgres psql << 'EOF'
CREATE DATABASE encrypted_db;
\c encrypted_db
-- Create table with encryption
CREATE TABLE sensitive_users (
id SERIAL PRIMARY KEY,
username VARCHAR(50),
email_encrypted BYTEA,
ssn_encrypted BYTEA,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert encrypted data
INSERT INTO sensitive_users (username, email_encrypted, ssn_encrypted)
VALUES (
'john_doe',
pgp_sym_encrypt('[email protected]', 'encryption_passphrase'),
pgp_sym_encrypt('123-45-6789', 'encryption_passphrase')
);
-- Query encrypted data
SELECT
id,
username,
pgp_sym_decrypt(email_encrypted, 'encryption_passphrase') AS email,
pgp_sym_decrypt(ssn_encrypted, 'encryption_passphrase') AS ssn
FROM
sensitive_users;
-- Create functions for encryption/decryption
CREATE OR REPLACE FUNCTION encrypt_data(plaintext TEXT, key TEXT)
RETURNS BYTEA AS $$
BEGIN
RETURN pgp_sym_encrypt(plaintext, key);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION decrypt_data(ciphertext BYTEA, key TEXT)
RETURNS TEXT AS $$
BEGIN
RETURN pgp_sym_decrypt(ciphertext, key);
END;
$$ LANGUAGE plpgsql;
EOF
File System Level Encryption for PostgreSQL
Since PostgreSQL lacks native transparent data encryption, use file system or disk encryption:
# Stop PostgreSQL
sudo systemctl stop postgresql
# Backup current data directory
sudo rsync -av /var/lib/postgresql/ /backup/postgresql/
# Create encrypted volume for PostgreSQL data
sudo cryptsetup luksFormat /dev/sdc1
sudo cryptsetup luksOpen /dev/sdc1 postgres_encrypted
sudo mkfs.ext4 /dev/mapper/postgres_encrypted
# Mount encrypted volume
sudo mount /dev/mapper/postgres_encrypted /var/lib/postgresql
# Restore data
sudo rsync -av /backup/postgresql/ /var/lib/postgresql/
sudo chown -R postgres:postgres /var/lib/postgresql
# Configure automatic mounting
echo "postgres_encrypted /dev/sdc1 /root/luks-keys/postgres.key luks" | sudo tee -a /etc/crypttab
echo "/dev/mapper/postgres_encrypted /var/lib/postgresql ext4 defaults 0 2" | sudo tee -a /etc/fstab
# Start PostgreSQL
sudo systemctl start postgresql
MongoDB Encryption
MongoDB Enterprise supports encryption at rest natively:
# Configure MongoDB encryption (Enterprise only)
sudo tee -a /etc/mongod.conf << 'EOF'
security:
enableEncryption: true
encryptionKeyFile: /etc/mongodb/encryption/mongodb.key
EOF
# Generate encryption key
sudo mkdir -p /etc/mongodb/encryption
sudo openssl rand -base64 32 > /etc/mongodb/encryption/mongodb.key
sudo chmod 600 /etc/mongodb/encryption/mongodb.key
sudo chown mongodb:mongodb /etc/mongodb/encryption/mongodb.key
# Restart MongoDB
sudo systemctl restart mongod
# For MongoDB Community Edition, use LUKS disk encryption
# Follow same process as PostgreSQL example above
Application-Level Encryption
Application-level encryption provides fine-grained control over what data is encrypted and how keys are managed.
Python Example
#!/usr/bin/env python3
# Application-level encryption example
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2
from cryptography.hazmat.backends import default_backend
import base64
import os
class DataEncryption:
def __init__(self, passphrase=None, key_file=None):
if key_file and os.path.exists(key_file):
with open(key_file, 'rb') as f:
self.key = f.read()
elif passphrase:
# Derive key from passphrase
salt = b'static_salt_replace_with_random' # In production, use random salt stored separately
kdf = PBKDF2(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(passphrase.encode()))
self.key = key
else:
# Generate new key
self.key = Fernet.generate_key()
self.cipher = Fernet(self.key)
def save_key(self, key_file):
"""Save encryption key to file"""
with open(key_file, 'wb') as f:
f.write(self.key)
os.chmod(key_file, 0o400)
def encrypt(self, plaintext):
"""Encrypt plaintext string"""
if isinstance(plaintext, str):
plaintext = plaintext.encode()
return self.cipher.encrypt(plaintext)
def decrypt(self, ciphertext):
"""Decrypt ciphertext to string"""
plaintext = self.cipher.decrypt(ciphertext)
return plaintext.decode()
# Usage example
if __name__ == "__main__":
# Initialize with passphrase
encryptor = DataEncryption(passphrase="strong_application_password")
# Encrypt sensitive data
sensitive_data = "Credit Card: 4111-1111-1111-1111"
encrypted = encryptor.encrypt(sensitive_data)
print(f"Encrypted: {encrypted}")
# Decrypt data
decrypted = encryptor.decrypt(encrypted)
print(f"Decrypted: {decrypted}")
# Save key for future use
encryptor.save_key("/etc/app/encryption.key")
PHP Example
<?php
// Application-level encryption in PHP
class DataEncryption {
private $key;
private $cipher = "aes-256-gcm";
public function __construct($keyFile = null) {
if ($keyFile && file_exists($keyFile)) {
$this->key = file_get_contents($keyFile);
} else {
// Generate new key
$this->key = random_bytes(32);
}
}
public function saveKey($keyFile) {
file_put_contents($keyFile, $this->key);
chmod($keyFile, 0400);
}
public function encrypt($plaintext) {
$ivlen = openssl_cipher_iv_length($this->cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$tag = "";
$ciphertext = openssl_encrypt(
$plaintext,
$this->cipher,
$this->key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
// Combine IV, tag, and ciphertext for storage
return base64_encode($iv . $tag . $ciphertext);
}
public function decrypt($encrypted) {
$data = base64_decode($encrypted);
$ivlen = openssl_cipher_iv_length($this->cipher);
$iv = substr($data, 0, $ivlen);
$tag = substr($data, $ivlen, 16);
$ciphertext = substr($data, $ivlen + 16);
$plaintext = openssl_decrypt(
$ciphertext,
$this->cipher,
$this->key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
return $plaintext;
}
}
// Usage
$encryptor = new DataEncryption();
$encryptor->saveKey("/etc/app/encryption.key");
$sensitive = "Customer SSN: 123-45-6789";
$encrypted = $encryptor->encrypt($sensitive);
echo "Encrypted: " . $encrypted . "\n";
$decrypted = $encryptor->decrypt($encrypted);
echo "Decrypted: " . $decrypted . "\n";
?>
Bash Script Example
#!/bin/bash
# Simple file encryption/decryption script
CIPHER="aes-256-cbc"
KEY_FILE="/etc/encryption/master.key"
SALT="$(openssl rand -hex 16)"
# Generate key file if it doesn't exist
if [ ! -f "$KEY_FILE" ]; then
mkdir -p "$(dirname $KEY_FILE)"
openssl rand -base64 32 > "$KEY_FILE"
chmod 400 "$KEY_FILE"
fi
encrypt_file() {
local input_file="$1"
local output_file="${input_file}.enc"
if [ ! -f "$input_file" ]; then
echo "Error: Input file not found"
return 1
fi
openssl enc -$CIPHER -salt -in "$input_file" -out "$output_file" -pass file:"$KEY_FILE" -pbkdf2
if [ $? -eq 0 ]; then
echo "File encrypted: $output_file"
# Optionally securely delete original
# shred -vfz -n 5 "$input_file"
else
echo "Encryption failed"
return 1
fi
}
decrypt_file() {
local input_file="$1"
local output_file="${input_file%.enc}"
if [ ! -f "$input_file" ]; then
echo "Error: Input file not found"
return 1
fi
openssl enc -d -$CIPHER -in "$input_file" -out "$output_file" -pass file:"$KEY_FILE" -pbkdf2
if [ $? -eq 0 ]; then
echo "File decrypted: $output_file"
else
echo "Decryption failed"
return 1
fi
}
# Usage
case "$1" in
encrypt)
encrypt_file "$2"
;;
decrypt)
decrypt_file "$2"
;;
*)
echo "Usage: $0 {encrypt|decrypt} <file>"
exit 1
;;
esac
Key Management Best Practices
Hardware Security Module (HSM) Integration
For production environments handling sensitive data, HSMs provide the highest level of key security:
# Example: Using SoftHSM for testing/development
# (Use actual HSM hardware in production)
# Install SoftHSM
sudo apt-get install -y softhsm2
# Initialize token
softhsm2-util --init-token --slot 0 --label "EncryptionKeys"
# Import key to HSM
softhsm2-util --import /path/to/key.pem --slot 0 --label "DataKey" --id 0001
# List tokens
softhsm2-util --show-slots
# Use PKCS#11 interface to access keys
# Most encryption tools support PKCS#11
Cloud KMS Integration
AWS KMS Example
# Install AWS CLI
sudo apt-get install -y awscli
# Configure AWS credentials
aws configure
# Create KMS key
aws kms create-key --description "Data Encryption Key"
# Get key ID from output
KEY_ID="arn:aws:kms:region:account:key/key-id"
# Encrypt data
echo "sensitive data" | aws kms encrypt \
--key-id "$KEY_ID" \
--plaintext fileb:///dev/stdin \
--output text \
--query CiphertextBlob | base64 -d > encrypted_data.bin
# Decrypt data
aws kms decrypt \
--ciphertext-blob fileb://encrypted_data.bin \
--output text \
--query Plaintext | base64 -d
Key Rotation Strategy
# Create comprehensive key rotation script
cat > /root/scripts/encryption_key_rotation.sh << 'EOF'
#!/bin/bash
# Comprehensive Encryption Key Rotation
LOG_FILE="/var/log/security/key_rotation_$(date +%Y%m%d).log"
mkdir -p "$(dirname $LOG_FILE)"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
echo "========================================"
echo "ENCRYPTION KEY ROTATION"
echo "Started: $(date)"
echo "========================================"
echo ""
# 1. LUKS Key Rotation
echo "=== LUKS Key Rotation ==="
LUKS_DEVICES=$(lsblk -o NAME,FSTYPE | grep crypto_LUKS | awk '{print "/dev/"$1}')
for device in $LUKS_DEVICES; do
echo "Processing $device..."
# Generate new key
NEW_KEY_FILE="/root/luks-keys/$(basename $device).key.new"
dd if=/dev/urandom of="$NEW_KEY_FILE" bs=4096 count=1 2>/dev/null
chmod 400 "$NEW_KEY_FILE"
# Add new key
cryptsetup luksAddKey "$device" "$NEW_KEY_FILE"
# Remove old key (requires current key)
OLD_KEY_FILE="/root/luks-keys/$(basename $device).key"
if [ -f "$OLD_KEY_FILE" ]; then
cryptsetup luksRemoveKey "$device" "$OLD_KEY_FILE"
shred -vfz -n 5 "$OLD_KEY_FILE"
fi
# Rename new key to current
mv "$NEW_KEY_FILE" "$OLD_KEY_FILE"
echo "$device: Key rotated successfully"
done
echo ""
# 2. MySQL Encryption Key Rotation
echo "=== MySQL Key Rotation ==="
if systemctl is-active --quiet mysql; then
mysql -u root -p -e "ALTER INSTANCE ROTATE INNODB MASTER KEY;" 2>/dev/null
echo "MySQL master key rotated"
fi
echo ""
# 3. Application Key Rotation
echo "=== Application Key Rotation ==="
APP_KEY_DIR="/etc/app/encryption"
if [ -d "$APP_KEY_DIR" ]; then
for key_file in "$APP_KEY_DIR"/*.key; do
if [ -f "$key_file" ]; then
# Backup old key
cp "$key_file" "$key_file.old.$(date +%Y%m%d)"
# Generate new key
openssl rand -base64 32 > "$key_file"
chmod 400 "$key_file"
echo "Rotated: $key_file"
echo "NOTE: Application must re-encrypt data with new key"
fi
done
fi
echo ""
# 4. Document rotation
cat > "/root/key-rotation-records/rotation_$(date +%Y%m%d).txt" << RECORD
Key Rotation Record
Date: $(date)
Rotated by: $(whoami)
LUKS devices rotated: $(echo "$LUKS_DEVICES" | wc -l)
MySQL keys rotated: Yes
Application keys rotated: Yes
Next rotation due: $(date -d "+1 year" +%Y-%m-%d)
RECORD
echo "========================================"
echo "KEY ROTATION COMPLETED: $(date)"
echo "========================================"
echo ""
echo "REQUIRED ACTIONS:"
echo "1. Verify all encrypted volumes still accessible"
echo "2. Test database connectivity and encryption"
echo "3. Re-encrypt application data with new keys"
echo "4. Securely destroy old key backups after verification (30 days)"
echo "5. Update disaster recovery documentation"
EOF
chmod +x /root/scripts/encryption_key_rotation.sh
# Schedule annual key rotation
echo "0 3 1 1 * /root/scripts/encryption_key_rotation.sh" | sudo crontab -
Encryption Monitoring and Auditing
Encryption Status Monitoring
# Create comprehensive encryption monitoring script
cat > /root/scripts/encryption_monitor.sh << 'EOF'
#!/bin/bash
# Encryption at Rest Monitoring
REPORT_FILE="/var/log/security/encryption_status_$(date +%Y%m%d).txt"
ALERT_EMAIL="[email protected]"
exec > >(tee -a "$REPORT_FILE")
echo "========================================"
echo "ENCRYPTION STATUS REPORT"
echo "Date: $(date)"
echo "Hostname: $(hostname)"
echo "========================================"
echo ""
# Check LUKS encrypted volumes
echo "=== LUKS Encrypted Volumes ==="
LUKS_COUNT=0
lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINT,SIZE | while read line; do
if echo "$line" | grep -q "crypto_LUKS"; then
echo "$line"
((LUKS_COUNT++))
fi
done
echo "Total LUKS volumes: $LUKS_COUNT"
echo ""
# Check currently open encrypted volumes
echo "=== Active Encrypted Volumes ==="
ls -l /dev/mapper/ | grep -v "control"
echo ""
# Check MySQL encryption
echo "=== MySQL Encryption Status ==="
if systemctl is-active --quiet mysql mariadb; then
mysql -u root -p -e "
SELECT @@innodb_encrypt_tables,
@@innodb_encrypt_log,
@@encrypt_binlog,
@@encrypt_tmp_files;
" 2>/dev/null
echo ""
echo "Encrypted Tables:"
mysql -u root -p -e "
SELECT COUNT(*) as encrypted_tables
FROM INFORMATION_SCHEMA.TABLES
WHERE CREATE_OPTIONS LIKE '%ENCRYPTED=YES%';
" 2>/dev/null
fi
echo ""
# Check PostgreSQL pgcrypto
echo "=== PostgreSQL Encryption ==="
if systemctl is-active --quiet postgresql; then
sudo -u postgres psql -c "\dx pgcrypto" 2>/dev/null
fi
echo ""
# Check file system encryption
echo "=== File System Encryption ==="
mount | grep -E "ecryptfs|encfs|fscrypt"
echo ""
# Check for unencrypted sensitive directories
echo "=== Unencrypted Sensitive Data Warning ==="
SENSITIVE_DIRS="/var/backups /opt/app/data /var/www/uploads"
for dir in $SENSITIVE_DIRS; do
if [ -d "$dir" ]; then
# Check if directory is on encrypted volume
MOUNT_POINT=$(df "$dir" | tail -1 | awk '{print $1}')
if ! lsblk -o NAME,FSTYPE "$MOUNT_POINT" 2>/dev/null | grep -q "crypto_LUKS"; then
echo "WARNING: $dir is NOT on encrypted volume!"
echo " Mount point: $MOUNT_POINT"
else
echo "OK: $dir is encrypted"
fi
fi
done
echo ""
# Check encryption key file permissions
echo "=== Encryption Key Security ==="
find /root/luks-keys /etc/mysql/encryption /etc/app/encryption -type f 2>/dev/null | while read key_file; do
PERMS=$(stat -c "%a" "$key_file")
OWNER=$(stat -c "%U:%G" "$key_file")
if [ "$PERMS" != "400" ] && [ "$PERMS" != "600" ]; then
echo "WARNING: Weak permissions on $key_file: $PERMS (should be 400 or 600)"
fi
if [ "$OWNER" != "root:root" ] && [ "$OWNER" != "mysql:mysql" ]; then
echo "WARNING: Incorrect ownership on $key_file: $OWNER"
fi
done
echo ""
echo "========================================"
echo "REPORT COMPLETED: $(date)"
echo "========================================"
# Alert if warnings found
if grep -q "WARNING" "$REPORT_FILE"; then
echo "Encryption warnings detected!" | mail -s "Encryption Status Alert" -a "$REPORT_FILE" "$ALERT_EMAIL"
fi
EOF
chmod +x /root/scripts/encryption_monitor.sh
# Schedule daily monitoring
echo "0 8 * * * /root/scripts/encryption_monitor.sh" | sudo crontab -
Compliance Audit Script
# Create encryption compliance audit script
cat > /root/scripts/encryption_compliance_audit.sh << 'EOF'
#!/bin/bash
# Encryption at Rest Compliance Audit
AUDIT_FILE="/var/log/security/encryption_audit_$(date +%Y%m%d).txt"
exec > >(tee -a "$AUDIT_FILE")
echo "========================================"
echo "ENCRYPTION COMPLIANCE AUDIT"
echo "Date: $(date)"
echo "Auditor: $(whoami)"
echo "========================================"
echo ""
# Compliance checklist
echo "=== COMPLIANCE CHECKLIST ==="
echo ""
# 1. Encryption Algorithm Strength
echo "[ ] Requirement: AES-256 or stronger encryption"
cryptsetup luksDump /dev/sdb1 2>/dev/null | grep -E "Cipher|Key"
echo ""
# 2. Key Storage
echo "[ ] Requirement: Encryption keys stored separately from data"
echo "Key locations:"
find / -name "*.key" -type f 2>/dev/null | grep -E "luks|encryption|mysql|app"
echo ""
# 3. Key Permissions
echo "[ ] Requirement: Key files have restrictive permissions (400/600)"
find /root/luks-keys /etc/mysql/encryption /etc/app/encryption -type f 2>/dev/null -exec ls -la {} \;
echo ""
# 4. Key Rotation
echo "[ ] Requirement: Keys rotated at least annually"
echo "Last key rotation:"
ls -lt /root/key-rotation-records/ 2>/dev/null | head -5
echo ""
# 5. Data at Rest Coverage
echo "[ ] Requirement: All sensitive data encrypted at rest"
echo "Sensitive data locations and encryption status:"
for dir in /var/backups /opt/app/data /var/www/uploads /home; do
if [ -d "$dir" ]; then
MOUNT=$(df "$dir" | tail -1 | awk '{print $1}')
ENCRYPTED=$(lsblk -o NAME,FSTYPE "$MOUNT" 2>/dev/null | grep -c "crypto_LUKS")
if [ "$ENCRYPTED" -gt 0 ]; then
echo "✓ $dir: ENCRYPTED"
else
echo "✗ $dir: NOT ENCRYPTED"
fi
fi
done
echo ""
# 6. Database Encryption
echo "[ ] Requirement: Database files encrypted"
if systemctl is-active --quiet mysql mariadb; then
mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_encrypt%';" 2>/dev/null
fi
echo ""
# 7. Backup Encryption
echo "[ ] Requirement: Backups encrypted"
echo "Checking backup files..."
find /var/backups -name "*.tar.gz" -o -name "*.sql" 2>/dev/null | head -5
echo "Verify these are encrypted or on encrypted volumes"
echo ""
# 8. Key Backup
echo "[ ] Requirement: Encryption keys backed up securely"
echo "LUKS header backups:"
find /secure/backups -name "*luks-header*" 2>/dev/null
echo ""
# 9. Documentation
echo "[ ] Requirement: Encryption procedures documented"
echo "Documentation files:"
find /root/docs /opt/docs -name "*encryption*" -o -name "*key-management*" 2>/dev/null
echo ""
# 10. Access Logging
echo "[ ] Requirement: Access to encrypted data logged"
ausearch -k encrypted_data_access -ts today 2>/dev/null | wc -l
echo ""
echo "========================================"
echo "AUDIT COMPLETED"
echo "Report saved to: $AUDIT_FILE"
echo "========================================"
echo ""
echo "REMEDIATION REQUIRED:"
echo "1. Address any checklist items marked with ✗"
echo "2. Ensure all sensitive data is on encrypted volumes"
echo "3. Verify key rotation schedule is being followed"
echo "4. Update documentation to reflect current state"
echo "5. Schedule next audit for: $(date -d '+3 months' +%Y-%m-%d)"
EOF
chmod +x /root/scripts/encryption_compliance_audit.sh
Disaster Recovery and Key Management
LUKS Header Backup and Recovery
# Backup LUKS headers for all encrypted devices
cat > /root/scripts/backup_luks_headers.sh << 'EOF'
#!/bin/bash
# Backup LUKS Headers
BACKUP_DIR="/secure/backups/luks-headers"
mkdir -p "$BACKUP_DIR"
echo "Backing up LUKS headers..."
# Find all LUKS devices
lsblk -o NAME,FSTYPE | grep crypto_LUKS | awk '{print "/dev/"$1}' | while read device; do
BACKUP_FILE="$BACKUP_DIR/$(basename $device)-header-$(date +%Y%m%d).img"
echo "Backing up $device to $BACKUP_FILE"
cryptsetup luksHeaderBackup "$device" --header-backup-file "$BACKUP_FILE"
# Encrypt the backup
gpg --symmetric --cipher-algo AES256 "$BACKUP_FILE"
# Remove unencrypted backup
shred -vfz "$BACKUP_FILE"
echo "Backup completed: $BACKUP_FILE.gpg"
done
echo "All LUKS headers backed up successfully"
echo "Store these backups in a secure, off-site location"
EOF
chmod +x /root/scripts/backup_luks_headers.sh
# Recovery procedure (document this)
cat > /root/docs/luks_recovery.md << 'EOF'
# LUKS Header Recovery Procedure
## When to Use
- LUKS header is corrupted
- Cannot open encrypted volume
- "Device or resource busy" errors
## Recovery Steps
1. Identify corrupted device:
```bash
cryptsetup luksDump /dev/sdX
# If this fails, header is likely corrupted
-
Decrypt backup:
gpg --decrypt /secure/backups/luks-headers/sdX-header-YYYYMMDD.img.gpg > /tmp/header.img -
Restore header:
cryptsetup luksHeaderRestore /dev/sdX --header-backup-file /tmp/header.img -
Verify restoration:
cryptsetup luksDump /dev/sdX cryptsetup luksOpen /dev/sdX test_volume -
Secure cleanup:
shred -vfz /tmp/header.img
Important Notes
- NEVER restore a header to the wrong device
- Always verify device UUID before restoration
- Test recovery procedure regularly
- Keep multiple header backups from different dates
EOF
### Encryption Key Backup Procedure
```bash
# Create secure key backup script
cat > /root/scripts/backup_encryption_keys.sh << 'EOF'
#!/bin/bash
# Secure Encryption Key Backup
BACKUP_DIR="/secure/backups/keys"
BACKUP_FILE="$BACKUP_DIR/encryption-keys-$(date +%Y%m%d).tar.gz.gpg"
TEMP_DIR="/tmp/key-backup-$$"
mkdir -p "$BACKUP_DIR"
mkdir -p "$TEMP_DIR"
echo "Creating encryption key backup..."
# Collect all encryption keys
cp -r /root/luks-keys "$TEMP_DIR/" 2>/dev/null
cp -r /etc/mysql/encryption "$TEMP_DIR/" 2>/dev/null
cp -r /etc/app/encryption "$TEMP_DIR/" 2>/dev/null
# Create tarball
tar -czf "$TEMP_DIR/keys.tar.gz" -C "$TEMP_DIR" .
# Encrypt backup with GPG
gpg --symmetric --cipher-algo AES256 --output "$BACKUP_FILE" "$TEMP_DIR/keys.tar.gz"
# Secure cleanup
shred -vfz -n 5 "$TEMP_DIR"/keys.tar.gz
rm -rf "$TEMP_DIR"
echo "Key backup completed: $BACKUP_FILE"
echo "Store this backup in a secure, off-site location"
echo "CRITICAL: Document the GPG passphrase in your password manager"
# Calculate checksum
sha256sum "$BACKUP_FILE" > "$BACKUP_FILE.sha256"
EOF
chmod +x /root/scripts/backup_encryption_keys.sh
# Schedule monthly key backups
echo "0 4 1 * * /root/scripts/backup_encryption_keys.sh" | sudo crontab -
Performance Considerations
Encryption Performance Testing
# Create encryption performance benchmark script
cat > /root/scripts/encryption_benchmark.sh << 'EOF'
#!/bin/bash
# Encryption Performance Benchmark
REPORT_FILE="/tmp/encryption_benchmark_$(date +%Y%m%d).txt"
exec > >(tee "$REPORT_FILE")
echo "========================================"
echo "ENCRYPTION PERFORMANCE BENCHMARK"
echo "Date: $(date)"
echo "========================================"
echo ""
# 1. CPU Cryptography Capabilities
echo "=== CPU Capabilities ==="
echo "AES-NI Support:"
grep -m1 -o aes /proc/cpuinfo && echo "Yes" || echo "No"
echo ""
echo "CPU Model:"
grep "model name" /proc/cpuinfo | head -1
echo ""
# 2. Cryptsetup Benchmark
echo "=== Cryptsetup Cipher Benchmark ==="
cryptsetup benchmark
echo ""
# 3. OpenSSL Speed Test
echo "=== OpenSSL Benchmark ==="
openssl speed -elapsed aes-128-cbc aes-256-cbc
echo ""
# 4. Disk I/O Performance (unencrypted vs encrypted)
echo "=== Disk I/O Performance Comparison ==="
# Test unencrypted partition
echo "Unencrypted write test:"
dd if=/dev/zero of=/tmp/test.img bs=1M count=1024 conv=fdatasync 2>&1 | grep -E "copied|s,"
# Test encrypted partition (if mounted)
if mount | grep -q "/mnt/encrypted"; then
echo "Encrypted write test:"
dd if=/dev/zero of=/mnt/encrypted/test.img bs=1M count=1024 conv=fdatasync 2>&1 | grep -E "copied|s,"
rm /mnt/encrypted/test.img
fi
rm /tmp/test.img
echo ""
# 5. Database Performance
echo "=== Database Performance Impact ==="
if systemctl is-active --quiet mysql; then
echo "Testing MySQL query performance with encryption..."
mysql -u root -p -e "
USE test;
DROP TABLE IF EXISTS perf_test;
CREATE TABLE perf_test (
id INT AUTO_INCREMENT PRIMARY KEY,
data VARCHAR(255)
);
-- Insert test data
INSERT INTO perf_test (data) VALUES ('test');
INSERT INTO perf_test (data) SELECT data FROM perf_test;
INSERT INTO perf_test (data) SELECT data FROM perf_test;
INSERT INTO perf_test (data) SELECT data FROM perf_test;
-- Benchmark query
SELECT BENCHMARK(1000000, (SELECT COUNT(*) FROM perf_test));
DROP TABLE perf_test;
" 2>/dev/null
fi
echo ""
echo "========================================"
echo "BENCHMARK COMPLETED"
echo "Report saved to: $REPORT_FILE"
echo "========================================"
EOF
chmod +x /root/scripts/encryption_benchmark.sh
Conclusion
Data encryption at rest is a critical security control that protects sensitive information from unauthorized access when storage media is compromised. This guide has provided comprehensive coverage of encryption implementation across multiple layers—from full disk encryption with LUKS to file system encryption, database encryption, and application-level encryption.
Key Takeaways
1. Defense in Depth: Implement encryption at multiple layers for maximum protection. Disk encryption protects against physical theft, while application-level encryption provides fine-grained control.
2. Key Management is Critical: The security of encrypted data depends entirely on proper key management. Use separate storage for keys, implement regular rotation, and maintain secure backups.
3. Performance Impact Varies: Full disk encryption with modern hardware (AES-NI) has minimal performance impact, while application-level encryption requires careful optimization.
4. Compliance Requirements: GDPR, PCI-DSS, HIPAA, and other regulations mandate encryption at rest for certain types of data. Proper implementation and documentation are essential for compliance.
5. Regular Testing: Test encryption, decryption, and recovery procedures regularly to ensure they work when needed.
Best Practices Summary
- Use AES-256 encryption for all sensitive data
- Store encryption keys separately from encrypted data
- Implement automated key rotation (annually minimum)
- Backup LUKS headers and encryption keys securely
- Monitor encryption status continuously
- Document all encryption procedures and key management processes
- Test disaster recovery procedures regularly
- Use hardware security modules (HSMs) for production environments
- Enable audit logging for all access to encrypted data
- Educate staff on encryption policies and procedures
Next Steps
-
Immediate Actions:
- Identify all sensitive data requiring encryption
- Implement full disk encryption on new systems
- Enable database encryption for existing databases
- Document current encryption implementation
-
Short-term (1-3 months):
- Implement automated encryption monitoring
- Establish key rotation procedures
- Create backup and recovery procedures
- Conduct encryption compliance audit
-
Long-term:
- Migrate to HSM or cloud KMS for key management
- Implement application-level encryption for fine-grained control
- Regular security audits and penetration testing
- Continuous improvement of encryption practices
By implementing the techniques and procedures outlined in this guide, you'll establish a robust encryption at rest strategy that protects your organization's sensitive data against unauthorized access while maintaining compliance with regulatory requirements.


