Files
cozystack/packages/apps/postgres/tests/pg_hba_test.yaml
T
Yasar Rahman f6f879cf38 fix(postgres)!: refuse plaintext sessions on external instances
CloudNativePG offers TLS but its built-in last pg_hba rule, host all all
all, also accepts plaintext, so a client outside the cluster that connects
with sslmode=disable gets an unencrypted session. tls.enabled only decides
whether the external hostname goes into the certificate and cannot prevent
this.

When external is true the chart now renders spec.postgresql.pg_hba with
hostssl all all all scram-sha-256 followed by host all all all reject.
CloudNativePG places user rules after its fixed rules and before its
default rule, and the first match wins, so only TLS sessions are accepted.
The pod network cannot be told apart from an external client, so in-cluster
clients are held to the same rule; libpq's default sslmode=prefer already
negotiates TLS.

The new tri-state tls.required follows external when omitted. Setting it to
false keeps accepting plaintext on an external instance and true requires
TLS on an in-cluster one.

The hostssl rule uses the same password method as CloudNativePG's own
default rule (md5 before PostgreSQL 14, scram-sha-256 from 14), so
existing md5 verifiers keep working on PostgreSQL 13. Rendering fails
when postgresql.parameters.ssl is off while TLS is required, since
hostssl would never match and every remote session would be refused.

BREAKING CHANGE: external clients that connect without TLS are refused
after the upgrade. Set tls.required to false to keep accepting them.
Assisted-by: LLM
Signed-off-by: Yasar Rahman <yasar.rehman@gmail.com>
2026-10-11 00:26:22 +05:00

147 lines
3.4 KiB
YAML

suite: postgres pg_hba TLS enforcement
# CNPG appends user pg_hba rules after its fixed rules and before its default
# "host all all all" rule, and the first match wins. tls.required is a tri-state
# that follows external when omitted.
release:
name: pg-test
namespace: tenant-test
set:
_cluster:
scheduling: {}
cluster-domain: cozy.local
_namespace:
host: example.cozy.local
templates:
- templates/db.yaml
tests:
- it: renders no pg_hba when the instance is not external
documentSelector:
path: kind
value: Cluster
asserts:
- isNull:
path: spec.postgresql.pg_hba
- it: external instance accepts TLS sessions only
set:
external: true
documentSelector:
path: kind
value: Cluster
asserts:
- equal:
path: spec.postgresql.pg_hba
value:
- hostssl all all all scram-sha-256
- host all all all reject
- it: external instance still gets the TLS rules when tls.enabled is false
set:
external: true
tls:
enabled: false
documentSelector:
path: kind
value: Cluster
asserts:
- equal:
path: spec.postgresql.pg_hba[0]
value: hostssl all all all scram-sha-256
- it: tls.required false opts an external instance out
set:
external: true
tls:
required: false
documentSelector:
path: kind
value: Cluster
asserts:
- isNull:
path: spec.postgresql.pg_hba
- it: tls.required true applies to an in-cluster instance
set:
tls:
required: true
documentSelector:
path: kind
value: Cluster
asserts:
- equal:
path: spec.postgresql.pg_hba
value:
- hostssl all all all scram-sha-256
- host all all all reject
- it: pg_hba does not disturb postgresql.parameters
set:
external: true
documentSelector:
path: kind
value: Cluster
asserts:
- equal:
path: spec.postgresql.parameters.max_connections
value: "100"
# CloudNativePG's own default rule uses md5 before PostgreSQL 14, where
# password_encryption defaults to md5; md5 also accepts SCRAM verifiers.
- it: uses md5 on PostgreSQL 13 like CloudNativePG's default rule
set:
external: true
version: v13
documentSelector:
path: kind
value: Cluster
asserts:
- equal:
path: spec.postgresql.pg_hba
value:
- hostssl all all all md5
- host all all all reject
- it: uses scram-sha-256 from PostgreSQL 14
set:
external: true
version: v14
documentSelector:
path: kind
value: Cluster
asserts:
- equal:
path: spec.postgresql.pg_hba
value:
- hostssl all all all scram-sha-256
- host all all all reject
- it: refuses ssl off while TLS is required
set:
external: true
postgresql:
parameters:
ssl: "off"
asserts:
- failedTemplate:
errorPattern: "postgresql.parameters.ssl is off while tls.required is in effect"
- it: allows ssl off when TLS is not required
set:
external: true
tls:
required: false
postgresql:
parameters:
ssl: "off"
documentSelector:
path: kind
value: Cluster
asserts:
- isNull:
path: spec.postgresql.pg_hba