Data plane hardening (Postgres TLS, Redis, backups)
Audience: DevOps / platform engineers Time: ~25 min Prerequisites: Custom deployment (Kubernetes & Helm)
This guide documents implemented Control Plane and Helm defaults for data-in-transit hardening and logical database backups. Encryption at rest is customer-managed (cloud Postgres TDE, encrypted volumes).
Postgres TLS (CC6.7)
When the Control Plane API runs in a production-like environment (ENVIRONMENT=production or prod, and DEMO_MODE is not set), it enforces TLS on every startup:
sslmode=verify-fullis injected when no mode is set, or when a weak mode (disable,allow,prefer) is present.DB_SSL_MODEoverrides the default (e.g.requirefor environments where the CA is managed elsewhere).DB_SSL_ROOT_CERTpins the CA certificate path for server verification.- Escape hatch:
DB_TLS_ENFORCE=falselogs a warning and skips enforcement — use only when TLS terminates upstream (load balancer / PgBouncer with TLS passthrough).
Environment variables (Postgres TLS)
| Variable | Purpose | Default |
|---|---|---|
DB_SSL_MODE | Postgres sslmode override | verify-full |
DB_SSL_ROOT_CERT | Path to the CA certificate for server verification | unset |
DB_TLS_ENFORCE | Set false to skip enforcement (logged — not recommended) | true |
Helm: external managed Postgres (RDS / Azure Flexible Server)
database:
enabled: false # Disable in-cluster Postgres; use managed service
external:
enabled: true
url: "postgresql://user:pass@host:5432/controlcore?sslmode=verify-full&sslrootcert=/etc/ssl/certs/rds-ca.pem"
Mount the CA certificate in the Control Plane pod and reference it via DB_SSL_ROOT_CERT.
Troubleshooting:
SSL connection has been closed unexpectedly— verify the server cert, the CA inDB_SSL_ROOT_CERT, and that the hostname matches the certificate SAN. Runopenssl s_client -connect HOST:5432 -starttls postgresto test the TLS handshake independently.
Helm: in-cluster Postgres with TLS
tls:
enabled: true
secretName: controlcore-postgres-tls # kubernetes.io/tls Secret
database:
external:
enabled: false
Redis TLS + AUTH (CC6.7)
Production requires both TLS and a password:
REDIS_URLmust userediss://(TLS) and include a password, orREDIS_PASSWORDmust be set separately.REDIS_TLS_ENFORCE=falsedisables enforcement (logged — operator-acknowledged escape hatch).
Environment variables (Redis TLS)
| Variable | Purpose | Default |
|---|---|---|
REDIS_TLS_ENFORCE | Set false to skip enforcement (logged) | true |
REDIS_SSL_CA_CERT | Path to the CA certificate for Redis TLS | unset |
REDIS_SSL_CERT_REQS | TLS certificate verification level (required / optional / none) | required |
REDIS_PASSWORD | Redis password (alternative to embedding in REDIS_URL) | unset |
Helm: external managed Redis (ElastiCache / Azure Cache)
redis:
enabled: false
external:
enabled: true
url: "rediss://:PASSWORD@redis.example:6380/0"
auth:
existingSecret: controlcore-redis-auth
existingSecretPasswordKey: password
Helm: in-cluster Redis with TLS + AUTH
redis:
auth:
enabled: true
existingSecret: controlcore-redis-auth
tls:
enabled: true
secretName: controlcore-redis-tls
Troubleshooting:
Connection refusedonrediss://— confirm the Redis server is configured for TLS and presents a certificate trusted by the client.WRONGPASS— verify the password in the Kubernetes Secret matches the Redisrequirepassvalue.
Logical backup CronJob (CC7.5)
An opt-in Helm CronJob runs pg_dump on a schedule and prunes old archives. This is not a replacement for cloud-managed PITR (RDS automated backups, Azure Flexible Server point-in-time restore).
database:
backup:
enabled: true
schedule: "0 */6 * * *" # Every 6 hours
retentionDays: 14 # Prune dumps older than 14 days
storage:
existingClaim: controlcore-pg-backup # Durable ReadWriteOnce PVC
size: 20Gi
The CronJob uses TLS when tls.enabled: true. It runs as a non-privileged pod (PSA restricted). Credentials are read from secretKeyRef.
Verify the most recent backup ran successfully:
kubectl get jobs -n controlcore -l app.kubernetes.io/component=postgres-backup
kubectl logs -n controlcore -l job-name=<LATEST_JOB> --tail=20
Troubleshooting: Job
Completedbut backup PVC is empty — setstorage.existingClaimto a ReadWriteOnce PVC that persists across nodes. DefaultemptyDiris ephemeral and not durable.
Customer-managed encryption at rest
| Layer | Control Core chart | Your responsibility |
|---|---|---|
| Postgres data | PVC or external URL | Enable provider TDE / encrypted EBS / CSI volume encryption |
| Redis | Optional persistence PVC | Encrypt volume or use managed Redis (encrypted at rest by default on ElastiCache / Azure Cache) |
| Application secrets | secretKeyRef / ExternalSecrets | KMS/Vault key rotation per your organization's policy |
SOC 2 reconciliation
| TSC | Status in product | Evidence you collect |
|---|---|---|
| CC6.7 | Partial — Control Plane API TLS enforcement + Helm server TLS | TLS handshake test (openssl s_client), connection string audit, Postgres host-based auth review |
| CC7.5 | Partial — Helm backup CronJob template | CronJob success logs, restore drill RTO/RPO measurement |
See also Supply chain verification and Shared responsibility (enterprise).