Encryption at Rest
Encryption at Rest
Field-level and full-disk encryption for data at rest.
Overview
All data at rest is encrypted using AES-256-GCM:
- Algorithm: AES-256-GCM (FIPS 140-2 validated)
- Key Management: HashiCorp Vault with HSM
- Key Rotation: Automatic every 90 days
- Compliance: FedRAMP, NIST 800-53, HIPAA, GDPR
Encryption Layers
graph TB A[Application Data] --> B[Field-Level Encryption] B --> C[Database Encryption] C --> D[Full-Disk Encryption] D --> E[Physical Storage]
Field-Level Encryption
Encrypted Fields
PII/PHI Fields:
- Email addresses
- Phone numbers
- Social Security Numbers
- Medical record numbers
- Financial data
Sensitive Data:
- API keys
- OAuth tokens
- Encryption keys
- Passwords (hashed + encrypted)
Implementation
EncryptionService.ts:
import * as crypto from 'crypto'; interface EncryptedField { ciphertext: string; // Base64 encoded iv: string; // Initialization vector salt: string; // Key derivation salt tag: string; // Authentication tag keyId: string; // Key version algorithm: 'aes-256-gcm'; encryptedAt: Date; } class FieldEncryptionService { private algorithm = 'aes-256-gcm'; private keyDerivation = 'pbkdf2'; private iterations = 100000; private saltLength = 32; private ivLength = 12; private tagLength = 16; async encryptField( fieldName: string, value: string, metadata?: Record<string, any> ): Promise<EncryptedField> { // Get current encryption key from Vault const key = await this.vault.getCurrentKey(); // Generate random IV and salt const iv = crypto.randomBytes(this.ivLength); const salt = crypto.randomBytes(this.saltLength); // Derive key using PBKDF2 const derivedKey = crypto.pbkdf2Sync( key.material, salt, this.iterations, 32, // 256 bits 'sha256' ); // Encrypt with AES-256-GCM const cipher = crypto.createCipheriv( this.algorithm, derivedKey, iv ); const encrypted = Buffer.concat([ cipher.update(value, 'utf8'), cipher.final() ]); const tag = cipher.getAuthTag(); // Audit log await this.auditLog.log({ event: 'field_encrypted', fieldName, keyId: key.id, timestamp: new Date() }); return { ciphertext: encrypted.toString('base64'), iv: iv.toString('base64'), salt: salt.toString('base64'), tag: tag.toString('base64'), keyId: key.id, algorithm: this.algorithm, encryptedAt: new Date() }; } async decryptField( encryptedField: EncryptedField ): Promise<string> { // Get encryption key by ID (supports key rotation) const key = await this.vault.getKey(encryptedField.keyId); // Decode from Base64 const ciphertext = Buffer.from(encryptedField.ciphertext, 'base64'); const iv = Buffer.from(encryptedField.iv, 'base64'); const salt = Buffer.from(encryptedField.salt, 'base64'); const tag = Buffer.from(encryptedField.tag, 'base64'); // Derive key const derivedKey = crypto.pbkdf2Sync( key.material, salt, this.iterations, 32, 'sha256' ); // Decrypt with AES-256-GCM const decipher = crypto.createDecipheriv( this.algorithm, derivedKey, iv ); decipher.setAuthTag(tag); const decrypted = Buffer.concat([ decipher.update(ciphertext), decipher.final() ]); // Audit log await this.auditLog.log({ event: 'field_decrypted', keyId: encryptedField.keyId, timestamp: new Date() }); return decrypted.toString('utf8'); } async reencryptField( encryptedField: EncryptedField ): Promise<EncryptedField> { // Decrypt with old key const plaintext = await this.decryptField(encryptedField); // Encrypt with current key return await this.encryptField( 'reencrypted', plaintext ); } }
Usage Example
const encryption = new FieldEncryptionService(); // Encrypt user email const encryptedEmail = await encryption.encryptField( 'email', 'user@example.com' ); // Store in database await db.query( 'INSERT INTO users (id, email_encrypted) VALUES ($1, $2)', [userId, JSON.stringify(encryptedEmail)] ); // Decrypt when needed const encrypted = JSON.parse(user.email_encrypted); const email = await encryption.decryptField(encrypted);
Database Encryption
PostgreSQL Transparent Data Encryption (TDE)
Configuration:
-- Enable pgcrypto extension CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Encrypted column CREATE TABLE users ( id UUID PRIMARY KEY, email BYTEA, -- Encrypted email_iv BYTEA, email_tag BYTEA, created_at TIMESTAMP ); -- Insert encrypted data INSERT INTO users (id, email, email_iv, email_tag) VALUES ( gen_random_uuid(), pgp_sym_encrypt('user@example.com', 'encryption-key'), gen_random_bytes(12), gen_random_bytes(16) ); -- Query encrypted data SELECT id, pgp_sym_decrypt(email, 'encryption-key') AS email FROM users;
TimescaleDB Encryption
Hypertable Encryption:
-- Create encrypted hypertable CREATE TABLE traces ( trace_id TEXT, timestamp TIMESTAMPTZ, data_encrypted BYTEA, PRIMARY KEY (timestamp, trace_id) ); SELECT create_hypertable('traces', 'timestamp'); -- Encrypted data retention policy SELECT add_retention_policy('traces', INTERVAL '90 days', if_not_exists => TRUE );
Redis Encryption
Redis Configuration:
# redis.conf requirepass your-strong-password # Enable TLS tls-port 6380 tls-cert-file /etc/redis/certs/redis.crt tls-key-file /etc/redis/certs/redis.key tls-ca-cert-file /etc/redis/certs/ca.crt # Encrypt RDB snapshots rdbcompression yes
Application-Level Encryption:
import Redis from 'ioredis'; const redis = new Redis({ port: 6380, host: 'redis.local.bluefly.io', password: process.env.REDIS_PASSWORD, tls: { ca: fs.readFileSync('/etc/redis/certs/ca.crt'), cert: fs.readFileSync('/etc/redis/certs/client.crt'), key: fs.readFileSync('/etc/redis/certs/client.key') } }); // Encrypt before storing const encryptedValue = await encryption.encryptField('cache', value); await redis.set(key, JSON.stringify(encryptedValue)); // Decrypt after retrieval const encrypted = JSON.parse(await redis.get(key)); const decrypted = await encryption.decryptField(encrypted);
Full-Disk Encryption
Linux (LUKS)
Setup:
# Create encrypted volume cryptsetup luksFormat /dev/sdb # Open encrypted volume cryptsetup luksOpen /dev/sdb encrypted_volume # Create filesystem mkfs.ext4 /dev/mapper/encrypted_volume # Mount mount /dev/mapper/encrypted_volume /mnt/encrypted
Docker Volumes
Encrypted Volume:
volumes: encrypted_data: driver: local driver_opts: type: "nfs" o: "addr=nfs.local.bluefly.io,rw,encryption=aes256" device: ":/encrypted/data"
Key Management
HashiCorp Vault Integration
Vault Configuration:
# Enable transit secrets engine vault secrets enable transit # Create encryption key vault write -f transit/keys/bluefly-platform # Configure key rotation vault write transit/keys/bluefly-platform/config \ min_decryption_version=1 \ min_encryption_version=0 \ deletion_allowed=false \ auto_rotate_period=90d
Application Integration:
import Vault from 'node-vault'; class VaultKeyManager { private vault: Vault.client; private mountPoint = 'transit'; private keyName = 'bluefly-platform'; async encrypt(plaintext: string): Promise<string> { const response = await this.vault.write( `${this.mountPoint}/encrypt/${this.keyName}`, { plaintext: Buffer.from(plaintext).toString('base64') } ); return response.data.ciphertext; } async decrypt(ciphertext: string): Promise<string> { const response = await this.vault.write( `${this.mountPoint}/decrypt/${this.keyName}`, { ciphertext } ); return Buffer.from(response.data.plaintext, 'base64').toString('utf8'); } async rotateKey(): Promise<void> { await this.vault.write( `${this.mountPoint}/keys/${this.keyName}/rotate`, {} ); } async getKeyVersion(): Promise<number> { const response = await this.vault.read( `${this.mountPoint}/keys/${this.keyName}` ); return response.data.latest_version; } }
Key Rotation
Automatic Rotation
Schedule: Every 90 days Method: Gradual re-encryption
Rotation Process:
class KeyRotationService { async rotateKeys(): Promise<void> { // 1. Create new key version await this.vault.rotateKey(); // 2. Get all encrypted fields const fields = await this.db.query(` SELECT id, data_encrypted, key_id FROM encrypted_data WHERE key_id != $1 `, [await this.vault.getCurrentKeyVersion()]); // 3. Re-encrypt in batches const batchSize = 1000; for (let i = 0; i < fields.length; i += batchSize) { const batch = fields.slice(i, i + batchSize); await Promise.all(batch.map(async (field) => { const decrypted = await this.encryption.decryptField( field.data_encrypted ); const reencrypted = await this.encryption.encryptField( 'rotated', decrypted ); await this.db.query( 'UPDATE encrypted_data SET data_encrypted = $1 WHERE id = $2', [reencrypted, field.id] ); })); console.log(`Rotated ${i + batch.length} of ${fields.length} fields`); } // 4. Audit log await this.auditLog.log({ event: 'key_rotation_complete', fieldsRotated: fields.length, timestamp: new Date() }); } }
Backup Encryption
Encrypted Backups
PostgreSQL Backup:
# Create encrypted backup pg_dump llm_platform | \ gpg --encrypt --recipient backup@bluefly.io > \ backup-$(date +%Y%m%d).sql.gpg # Restore encrypted backup gpg --decrypt backup-20250115.sql.gpg | \ psql llm_platform
File Backup:
# Create encrypted tar archive tar czf - /data | \ openssl enc -aes-256-cbc -salt -out backup.tar.gz.enc # Extract encrypted archive openssl enc -aes-256-cbc -d -in backup.tar.gz.enc | \ tar xzf -
Compliance
FIPS 140-2 Validation
Crypto Module: OpenSSL FIPS 140-2 validated Validation Certificate: #3953 Algorithms:
- AES-256-GCM (encryption)
- PBKDF2-HMAC-SHA256 (key derivation)
- RSA-2048 (key wrapping)
Audit Requirements
Audit Events:
- Field encryption/decryption
- Key access
- Key rotation
- Backup creation/restoration
- Unauthorized access attempts
Log Format:
{ "timestamp": "2025-01-15T10:00:00Z", "event": "field_encrypted", "fieldName": "email", "keyId": "vault-key-v12", "userId": "user-123", "ipAddress": "192.168.1.100" }