You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit c5a8122
Browse filesBrowse the repository at this point in the historyBrowse files
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.
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 <[email protected]>
Copy file name to clipboardExpand all lines: packages/apps/postgres/README.md
+13-4Lines changed: 13 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -175,6 +175,14 @@ The tri-state `tls.enabled` controls whether the chart injects `serverAltDNSName
175
175
- `tls.enabled: true` with `external: false` — no `serverAltDNSNames` injection is needed (there is no external hostname to add); CNPG's auto-generated cert covers internal services.
176
176
- `tls.enabled: false` — the chart skips `serverAltDNSNames` injection. **Note:** CNPG keeps its built-in TLS on the wire regardless of this flag; this toggle only controls whether the external hostnames are added to the cert. To force PostgreSQL to drop TLS entirely you would need to set `postgresql.parameters.ssl = "off"` at the CNPG layer, which is out of scope for this flag.
177
177
178
+
**Refusing plaintext sessions.** CNPG offers TLS but its built-in last `pg_hba` rule, `host all all all`, also accepts plaintext, so a client using `sslmode=disable` gets an unencrypted session. The tri-state `tls.required` closes that:
179
+
180
+
- `tls.required: null` (the default) — follows `external`. With `external: true` the chart renders `spec.postgresql.pg_hba` as `hostssl all all all scram-sha-256` followed by `host all all all reject`. CNPG puts these after its fixed rules and before its default rule, and the first matching rule wins, so only TLS sessions are authenticated.
181
+
- `tls.required: true` — the same rules regardless of `external`.
182
+
- `tls.required: false` — no `pg_hba` rules are rendered and CNPG's default applies, which accepts plaintext.
183
+
184
+
The rules cover every client, in-cluster ones included, because the pod network cannot be told apart from an external client. libpq's default `sslmode=prefer` already negotiates TLS, so only clients that disable TLS explicitly are refused. Instances that were external before this setting existed refuse such clients after the upgrade; set `tls.required: false` to keep accepting them. See the CloudNativePG [`pg_hba` documentation](https://cloudnative-pg.io/documentation/current/postgresql_conf/#the-pg_hba-section).
185
+
178
186
**Retrieving the CA bundle** for client verification:
179
187
180
188
The trust anchor is published as `postgres-<name>.tenant-ca`, where `<name>` is the name of the Postgres resource: an object holding `ca.crt` and nothing else, created for every release and delivered to tenants through the `core.cozystack.io/tenantsecrets` API that the base tenant roles already grant. The `postgres-` prefix comes from the release naming this application definition applies, so a Postgres named `foo` gets `postgres-foo.tenant-ca`.
@@ -218,10 +226,11 @@ For `sslmode=verify-full` to work, the CA bundle retrieved above must be saved t
| `tls` | TLS configuration for server connections. | `object` | `{}` |
224
-
| `tls.enabled` | Tri-state switch controlling whether the chart injects the external hostnames into the operator-managed CNPG cert via spec.certificates.serverAltDNSNames. When omitted, the chart injects them if `external: true` and skips them otherwise. Set explicitly to `true` to inject regardless of `external` (no-op when `external: false` since there is no external hostname to add). Set to `false` to skip injection. Note that CNPG keeps its built-in TLS on the wire regardless of this flag — this toggle only controls the chart-side SAN injection; to disable PostgreSQL TLS entirely set `postgresql.parameters.ssl = "off"` at the CNPG layer. | `*bool` | `null` |
| `tls` | TLS configuration for server connections. | `object` | `{}` |
232
+
| `tls.enabled` | Tri-state switch controlling whether the chart injects the external hostnames into the operator-managed CNPG cert via spec.certificates.serverAltDNSNames. When omitted, the chart injects them if `external: true` and skips them otherwise. Set explicitly to `true` to inject regardless of `external` (no-op when `external: false` since there is no external hostname to add). Set to `false` to skip injection. Note that CNPG keeps its built-in TLS on the wire regardless of this flag — this toggle only controls the chart-side SAN injection; to disable PostgreSQL TLS entirely set `postgresql.parameters.ssl = "off"` at the CNPG layer. | `*bool` | `null` |
233
+
| `tls.required` | Tri-state switch controlling whether the server refuses sessions that are not encrypted. When omitted, it is on if `external: true` and off otherwise. When on, the chart renders `spec.postgresql.pg_hba` with `hostssl all all all scram-sha-256` followed by `host all all all reject`, so a client that connects with `sslmode=disable` is refused instead of getting a plaintext session; in-cluster clients are held to the same rule, since the pod network cannot be told apart from an external client. Set to `false` to keep accepting plaintext sessions on an external instance, or to `true` to require TLS on an in-cluster one. | `*bool` | `null` |
Copy file name to clipboardExpand all lines: packages/apps/postgres/values.schema.json
+4Lines changed: 4 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -157,6 +157,10 @@
157
157
"enabled": {
158
158
"description": "Tri-state switch controlling whether the chart injects the external hostnames into the operator-managed CNPG cert via spec.certificates.serverAltDNSNames. When omitted, the chart injects them if `external: true` and skips them otherwise. Set explicitly to `true` to inject regardless of `external` (no-op when `external: false` since there is no external hostname to add). Set to `false` to skip injection. Note that CNPG keeps its built-in TLS on the wire regardless of this flag — this toggle only controls the chart-side SAN injection; to disable PostgreSQL TLS entirely set `postgresql.parameters.ssl = \"off\"` at the CNPG layer.",
159
159
"type": "boolean"
160
+
},
161
+
"required": {
162
+
"description": "Tri-state switch controlling whether the server refuses sessions that are not encrypted. When omitted, it is on if `external: true` and off otherwise. When on, the chart renders `spec.postgresql.pg_hba` with `hostssl all all all scram-sha-256` followed by `host all all all reject`, so a client that connects with `sslmode=disable` is refused instead of getting a plaintext session; in-cluster clients are held to the same rule, since the pod network cannot be told apart from an external client. Set to `false` to keep accepting plaintext sessions on an external instance, or to `true` to require TLS on an in-cluster one.",
Copy file name to clipboardExpand all lines: packages/apps/postgres/values.yaml
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -101,6 +101,7 @@ flavor: postgresql
101
101
102
102
## @typedef {struct} TLS - TLS configuration for PostgreSQL server connections.
103
103
## @field {*bool} enabled - Tri-state switch controlling whether the chart injects the external hostnames into the operator-managed CNPG cert via spec.certificates.serverAltDNSNames. When omitted, the chart injects them if `external: true` and skips them otherwise. Set explicitly to `true` to inject regardless of `external` (no-op when `external: false` since there is no external hostname to add). Set to `false` to skip injection. Note that CNPG keeps its built-in TLS on the wire regardless of this flag — this toggle only controls the chart-side SAN injection; to disable PostgreSQL TLS entirely set `postgresql.parameters.ssl = "off"` at the CNPG layer.
104
+
## @field {*bool} required - Tri-state switch controlling whether the server refuses sessions that are not encrypted. When omitted, it is on if `external: true` and off otherwise. When on, the chart renders `spec.postgresql.pg_hba` with `hostssl all all all scram-sha-256` followed by `host all all all reject`, so a client that connects with `sslmode=disable` is refused instead of getting a plaintext session; in-cluster clients are held to the same rule, since the pod network cannot be told apart from an external client. Set to `false` to keep accepting plaintext sessions on an external instance, or to `true` to require TLS on an in-cluster one.
104
105
105
106
## @param {TLS} tls - TLS configuration for server connections.
0 commit comments