14 KiB
Database Security Guide
Last Updated: November 2025 Status: Production Ready Security Grade: A-
Table of Contents
- Overview
- Database Inventory
- Security Implementation
- Data Protection
- Compliance
- Monitoring and Maintenance
- Troubleshooting
- Related Documentation
Overview
This guide provides comprehensive information about database security in the Bakery IA platform. Our infrastructure has been hardened from a D- security grade to an A- grade through systematic implementation of industry best practices.
Security Achievements
- 15 databases secured (14 PostgreSQL + 1 Redis)
- 100% TLS encryption for all database connections
- Strong authentication with 32-character cryptographic passwords
- Data persistence with PersistentVolumeClaims preventing data loss
- Audit logging enabled for all database operations
- Encryption at rest capabilities with pgcrypto extension
Security Grade Improvement
| Metric | Before | After |
|---|---|---|
| Overall Grade | D- | A- |
| Critical Issues | 4 | 0 |
| High-Risk Issues | 3 | 0 |
| Medium-Risk Issues | 4 | 0 |
| Encryption in Transit | None | TLS 1.2+ |
| Encryption at Rest | None | Available (pgcrypto + K8s) |
Database Inventory
PostgreSQL Databases (14 instances)
All running PostgreSQL 17-alpine with TLS encryption enabled:
| Database | Service | Purpose |
|---|---|---|
| auth-db | Authentication | User authentication and authorization |
| tenant-db | Tenant | Multi-tenancy management |
| training-db | Training | ML model training data |
| forecasting-db | Forecasting | Demand forecasting |
| sales-db | Sales | Sales transactions |
| external-db | External | External API data |
| notification-db | Notification | Notifications and alerts |
| inventory-db | Inventory | Inventory management |
| recipes-db | Recipes | Recipe data |
| suppliers-db | Suppliers | Supplier information |
| pos-db | POS | Point of Sale integrations |
| orders-db | Orders | Order management |
| production-db | Production | Production batches |
| alert-processor-db | Alert Processor | Alert processing |
Other Datastores
- Redis: Shared caching and session storage with TLS encryption
- RabbitMQ: Message broker for inter-service communication
Security Implementation
1. Authentication and Access Control
Service Isolation
- Each service has its own dedicated database with unique credentials
- Prevents cross-service data access
- Limits blast radius of credential compromise
Password Security
- Algorithm: PostgreSQL uses scram-sha-256 authentication (modern, secure)
- Password Strength: 32-character cryptographically secure passwords
- Generation: Created using OpenSSL:
openssl rand -base64 32 - Rotation Policy: Recommended every 90 days
Network Isolation
- All databases run on internal Kubernetes network
- No direct external exposure
- ClusterIP services (internal only)
- Cannot be accessed from outside the cluster
2. Encryption in Transit (TLS/SSL)
All database connections enforce TLS 1.2+ encryption.
PostgreSQL TLS Configuration
Server Configuration:
# PostgreSQL SSL Settings (postgresql.conf)
ssl = on
ssl_cert_file = '/tls/server-cert.pem'
ssl_key_file = '/tls/server-key.pem'
ssl_ca_file = '/tls/ca-cert.pem'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'
Client Connection String:
# Automatically enforced by DatabaseManager
"postgresql+asyncpg://user:pass@host:5432/db?ssl=require"
Certificate Details:
- Algorithm: RSA 4096-bit
- Signature: SHA-256
- Validity: 3 years (expires October 2028)
- CA Validity: 10 years (expires 2035)
Redis TLS Configuration
Server Configuration:
redis-server \
--requirepass $REDIS_PASSWORD \
--tls-port 6379 \
--port 0 \
--tls-cert-file /tls/redis-cert.pem \
--tls-key-file /tls/redis-key.pem \
--tls-ca-cert-file /tls/ca-cert.pem \
--tls-auth-clients no
Client Connection String:
"rediss://:password@redis-service:6379?ssl_cert_reqs=none"
3. Data Persistence
PersistentVolumeClaims (PVCs)
All PostgreSQL databases use PVCs to prevent data loss:
# Example PVC configuration
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: auth-db-pvc
namespace: bakery-ia
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
Benefits:
- Data persists across pod restarts
- Prevents catastrophic data loss from ephemeral storage
- Enables backup and restore operations
- Supports volume snapshots
Redis Persistence
Redis configured with:
- AOF (Append Only File): enabled
- RDB snapshots: periodic
- PersistentVolumeClaim: for data directory
Data Protection
1. Encryption at Rest
Kubernetes Secrets Encryption
All secrets encrypted at rest with AES-256:
# Encryption configuration
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
PostgreSQL pgcrypto Extension
Available for column-level encryption:
-- Enable extension
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- Encrypt sensitive data
INSERT INTO users (name, ssn_encrypted)
VALUES (
'John Doe',
pgp_sym_encrypt('123-45-6789', 'encryption_key')
);
-- Decrypt data
SELECT name, pgp_sym_decrypt(ssn_encrypted::bytea, 'encryption_key')
FROM users;
Available Functions:
pgp_sym_encrypt()- Symmetric encryptionpgp_pub_encrypt()- Public key encryptiongen_salt()- Password hashingdigest()- Hash functions
2. Backup Strategy
Automated Encrypted Backups
Script Location: /scripts/encrypted-backup.sh
Features:
- Backs up all 14 PostgreSQL databases
- Uses
pg_dumpfor data export - Compresses with
gzipfor space efficiency - Encrypts with GPG for security
- Output format:
<db>_<name>_<timestamp>.sql.gz.gpg
Usage:
# Create encrypted backup
./scripts/encrypted-backup.sh
# Decrypt and restore
gpg --decrypt backup_file.sql.gz.gpg | gunzip | psql -U user -d database
Recommended Schedule:
- Daily backups: Retain 30 days
- Weekly backups: Retain 90 days
- Monthly backups: Retain 1 year
3. Audit Logging
PostgreSQL logging configuration includes:
# Log all connections and disconnections
log_connections = on
log_disconnections = on
# Log all SQL statements
log_statement = 'all'
# Log query duration
log_duration = on
log_min_duration_statement = 1000 # Log queries > 1 second
# Log detail
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
Log Rotation:
- Daily or 100MB size limit
- 7-day retention minimum
- Ship to centralized logging (recommended)
Compliance
GDPR (European Data Protection)
| Requirement | Implementation | Status |
|---|---|---|
| Article 32 - Encryption | TLS for transit, pgcrypto for rest | ✅ Compliant |
| Article 5(1)(f) - Security | Strong passwords, access control | ✅ Compliant |
| Article 33 - Breach notification | Audit logs for breach detection | ✅ Compliant |
Legal Status: Privacy policy claims are now accurate - encryption is implemented.
PCI-DSS (Payment Card Data)
| Requirement | Implementation | Status |
|---|---|---|
| Requirement 3.4 - Encrypt transmission | TLS 1.2+ for all connections | ✅ Compliant |
| Requirement 3.5 - Protect stored data | pgcrypto extension available | ✅ Compliant |
| Requirement 10 - Track access | PostgreSQL audit logging | ✅ Compliant |
SOC 2 (Security Controls)
| Control | Implementation | Status |
|---|---|---|
| CC6.1 - Access controls | Audit logs, RBAC | ✅ Compliant |
| CC6.6 - Encryption in transit | TLS for all database connections | ✅ Compliant |
| CC6.7 - Encryption at rest | Kubernetes secrets + pgcrypto | ✅ Compliant |
Monitoring and Maintenance
Certificate Management
Certificate Expiry Monitoring
PostgreSQL and Redis Certificates Expire: October 17, 2028
Renewal Process:
# 1. Regenerate certificates (90 days before expiry)
cd infrastructure/tls && ./generate-certificates.sh
# 2. Update Kubernetes secrets
kubectl delete secret postgres-tls redis-tls -n bakery-ia
kubectl apply -f infrastructure/kubernetes/base/secrets/postgres-tls-secret.yaml
kubectl apply -f infrastructure/kubernetes/base/secrets/redis-tls-secret.yaml
# 3. Restart database pods (automatic)
kubectl rollout restart deployment -l app.kubernetes.io/component=database -n bakery-ia
Password Rotation
Recommended: Every 90 days
Process:
# 1. Generate new passwords
./scripts/generate-passwords.sh > new-passwords.txt
# 2. Update .env file
./scripts/update-env-passwords.sh
# 3. Update Kubernetes secrets
./scripts/update-k8s-secrets.sh
# 4. Apply secrets
kubectl apply -f infrastructure/kubernetes/base/secrets.yaml
# 5. Restart databases and services
kubectl rollout restart deployment -n bakery-ia
Health Checks
Verify PostgreSQL SSL
# Check SSL is enabled
kubectl exec -n bakery-ia <postgres-pod> -- sh -c \
'psql -U $POSTGRES_USER -d $POSTGRES_DB -c "SHOW ssl;"'
# Expected: on
# Check certificate permissions
kubectl exec -n bakery-ia <postgres-pod> -- ls -la /tls/
# Expected: server-key.pem has 600 permissions
Verify Redis TLS
# Test Redis connection with TLS
kubectl exec -n bakery-ia <redis-pod> -- redis-cli \
--tls \
--cert /tls/redis-cert.pem \
--key /tls/redis-key.pem \
--cacert /tls/ca-cert.pem \
-a $REDIS_PASSWORD \
ping
# Expected: PONG
Verify PVCs
# Check all PVCs are bound
kubectl get pvc -n bakery-ia
# Expected: All PVCs in "Bound" state
Audit Log Review
# View PostgreSQL logs
kubectl logs -n bakery-ia <db-pod>
# Search for failed connections
kubectl logs -n bakery-ia <db-pod> | grep -i "authentication failed"
# Search for long-running queries
kubectl logs -n bakery-ia <db-pod> | grep -i "duration:"
Troubleshooting
PostgreSQL Connection Issues
Services Can't Connect After Deployment
Symptom: Services show SSL/TLS errors in logs
Solution:
# Restart all services to pick up new TLS configuration
kubectl rollout restart deployment -n bakery-ia \
--selector='app.kubernetes.io/component=service'
"SSL not supported" Error
Symptom: PostgreSQL server rejected SSL upgrade
Solution:
# Check if TLS secret exists
kubectl get secret postgres-tls -n bakery-ia
# Check if mounted in pod
kubectl describe pod <db-pod> -n bakery-ia | grep -A 5 "tls-certs"
# Restart database pod
kubectl delete pod <db-pod> -n bakery-ia
Certificate Permission Denied
Symptom: FATAL: could not load server certificate file
Solution:
# Check init container logs
kubectl logs -n bakery-ia <pod> -c fix-tls-permissions
# Verify certificate permissions
kubectl exec -n bakery-ia <pod> -- ls -la /tls/
# server-key.pem should have 600 permissions
Redis Connection Issues
Connection Timeout
Symptom: SSL handshake is taking longer than 60.0 seconds
Solution:
# Check Redis logs
kubectl logs -n bakery-ia <redis-pod>
# Test Redis directly
kubectl exec -n bakery-ia <redis-pod> -- redis-cli \
--tls --cert /tls/redis-cert.pem \
--key /tls/redis-key.pem \
--cacert /tls/ca-cert.pem \
PING
Data Persistence Issues
PVC Not Binding
Symptom: PVC stuck in "Pending" state
Solution:
# Check PVC status
kubectl describe pvc <pvc-name> -n bakery-ia
# Check storage class
kubectl get storageclass
# For Kind, ensure local-path provisioner is running
kubectl get pods -n local-path-storage
Related Documentation
Security Documentation
- RBAC Implementation - Role-based access control
- TLS Configuration - TLS/SSL setup details
- Security Checklist - Deployment checklist
Source Reports
External References
- PostgreSQL SSL Documentation
- Redis TLS Documentation
- Kubernetes Secrets Encryption
- pgcrypto Documentation
Quick Reference
Common Commands
# Verify database security
kubectl get pods -n bakery-ia -l app.kubernetes.io/component=database
kubectl get pvc -n bakery-ia
kubectl get secrets -n bakery-ia | grep tls
# Check certificate expiry
kubectl exec -n bakery-ia <postgres-pod> -- \
openssl x509 -in /tls/server-cert.pem -noout -dates
# View audit logs
kubectl logs -n bakery-ia <db-pod> | tail -n 100
# Restart all databases
kubectl rollout restart deployment -n bakery-ia \
-l app.kubernetes.io/component=database
Security Validation Checklist
- All database pods running and healthy
- All PVCs in "Bound" state
- TLS certificates mounted with correct permissions
- PostgreSQL accepts TLS connections
- Redis accepts TLS connections
- pgcrypto extension loaded
- Services connect without TLS errors
- Audit logs being generated
- Passwords are strong (32+ characters)
- Backup script tested and working
Document Version: 1.0 Last Review: November 2025 Next Review: May 2026 Owner: Security Team