From 31a47faae1a64368d5ea0e3836a387f2476e1801 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 13 Jun 2026 12:21:52 +0000 Subject: [PATCH] Serve TLS from the local dev Postgres Enable TLS on the in-cluster Postgres so local dev exercises the backend's new PostgreSQL TLS support (PGSSLMODE). An init container generates a self-signed server certificate (owned by the postgres uid, 0600 perms) and the server starts with ssl=on. The backend defaults to PGSSLMODE=prefer, so the local workers now connect over TLS automatically with no extra configuration. Documented the TLS behavior and how to verify an encrypted connection in the README. --- README.md | 30 ++++++++++++++++++++++++++++++ manifests/postgres.yaml | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/README.md b/README.md index 03c4f98..cabcdf4 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,36 @@ The local stack uses `local` and `oci`. PGHOST=127.0.0.1 PGPORT=15432 PGUSER=postgres PGPASSWORD=postgres PGDATABASE=platz psql ``` +## Database TLS + +The in-cluster Postgres ([manifests/postgres.yaml](manifests/postgres.yaml)) +serves TLS: an init container generates a self-signed certificate and the +server starts with `ssl=on`. This exercises the backend's TLS support +end-to-end in local dev. + +The backend's TLS behavior is controlled by `PGSSLMODE` (and `PGSSLROOTCERT` +for a custom CA), mirroring libpq's `sslmode`: + +* `disable` — plaintext (the pre-TLS behavior). +* `prefer` *(default)* — use TLS if the server offers it, otherwise plaintext; + the server certificate is **not** verified. +* `require` — always use TLS; the certificate is **not** verified. +* `verify-full` — always use TLS and verify the certificate chain **and** + hostname against the system trust store or `PGSSLROOTCERT`. + +Because the default is `prefer`, the local workers connect to the dev Postgres +over TLS automatically — no extra configuration needed. The certificate is +self-signed, so `verify-full` won't work locally without distributing the CA; +`prefer`/`require` are the right choices for the local stack. + +Verify a connection is encrypted from inside the cluster: + +```bash +kubectl -n platz exec deploy/postgres -- \ + psql -U postgres -d platz -c \ + "SELECT ssl, version FROM pg_stat_ssl JOIN pg_stat_activity USING (pid) WHERE usename = 'postgres';" +``` + ## Adding test charts Test charts live under [charts/](charts/) and are pushed to the in-cluster diff --git a/manifests/postgres.yaml b/manifests/postgres.yaml index d4575aa..fd2b974 100644 --- a/manifests/postgres.yaml +++ b/manifests/postgres.yaml @@ -39,9 +39,41 @@ spec: labels: app: postgres spec: + # Generate a self-signed server certificate before Postgres starts so the + # local database serves TLS, exercising the backend's TLS code path + # (PGSSLMODE). The key must be owned by the postgres user (uid 70 in the + # alpine image) with 0600 perms or the server refuses to start. + initContainers: + - name: generate-tls-cert + image: postgres:17-alpine + command: + - sh + - -c + - | + set -eu + if [ ! -f /certs/server.crt ]; then + command -v openssl >/dev/null 2>&1 || apk add --no-cache openssl + openssl req -new -x509 -days 3650 -nodes \ + -subj "/CN=postgres.platz.svc.cluster.local" \ + -keyout /certs/server.key \ + -out /certs/server.crt + fi + chmod 600 /certs/server.key + chown 70:70 /certs/server.key /certs/server.crt + volumeMounts: + - name: tls + mountPath: /certs containers: - name: postgres image: postgres:17-alpine + # Enable TLS using the certificate produced by the init container. + args: + - -c + - ssl=on + - -c + - ssl_cert_file=/certs/server.crt + - -c + - ssl_key_file=/certs/server.key ports: - containerPort: 5432 env: @@ -58,6 +90,10 @@ spec: volumeMounts: - name: data mountPath: /var/lib/postgresql/data + - name: tls + mountPath: /certs volumes: - name: data emptyDir: {} + - name: tls + emptyDir: {}