Skip to content

Commit 18b6875

Browse files
committed
docs: import CloudNativePG main
1 parent 4d05ab9 commit 18b6875

3 files changed

Lines changed: 125 additions & 16 deletions

File tree

website/docs/declarative_role_management.md

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,23 +179,74 @@ stringData:
179179
password: SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
180180
```
181181

182+
:::warning
183+
The example above uses `stringData:`, where Kubernetes encodes the value
184+
for you, which is the safest path for pre-hashed passwords. If you must
185+
use `data:`, encode the bytes exactly with `printf '%s' "$hash" | base64`
186+
(or `echo -n "$hash" | base64`). A trailing newline from a naive
187+
`echo "$hash" | base64` makes the value miss the SCRAM/MD5 shadow-format
188+
check, so the operator falls back to treating it as cleartext and
189+
re-hashes it, and login stops working.
190+
:::
191+
182192
### Safety when transmitting cleartext passwords
183193

184-
While role passwords are safely managed in Kubernetes using Secrets,
185-
there is still a risk on the PostgreSQL side. If creating/altering a role with
186-
password, PostgreSQL may print the password as part of the query statement
187-
in some `postgres` logs, as mentioned in the [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-createrole.html):
194+
Role passwords are safely managed in Kubernetes using Secrets, but the
195+
SQL path between the operator and PostgreSQL is also a concern. As noted
196+
in the [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-createrole.html):
188197

189198
> The password will be transmitted to the server in cleartext, and it might
190199
> also be logged in the client's command history or the server log
191200

192-
CloudNativePG adds a safety layer by temporarily suppressing both statement
193-
logging (`log_statement`) and error statement logging
194-
(`log_min_error_statement`) for any CREATE or ALTER operation on a role with
195-
password, thus preventing leakage in both success and failure scenarios.
201+
CloudNativePG protects this path in two complementary ways:
202+
203+
1. Before emitting `CREATE`/`ALTER ROLE ... PASSWORD '...'`, the operator
204+
SCRAM-SHA-256 encodes any cleartext password operator-side (client-side
205+
from PostgreSQL's point of view). This is the standard PostgreSQL
206+
practice for keeping cleartext out of server logs and extensions like
207+
`pg_stat_statements` or `pgaudit`, and is the same encoding that
208+
`psql \password` and libpq's `PQencryptPasswordConn` perform. The
209+
literal PostgreSQL receives is the SCRAM-SHA-256 verifier stored in
210+
`pg_authid.rolpassword`. Passwords already provided in MD5 or
211+
SCRAM-SHA-256 shadow form are forwarded unchanged.
212+
2. The same `CREATE`/`ALTER ROLE` statements are executed inside a
213+
transaction that temporarily suppresses both statement logging
214+
(`log_statement`) and error statement logging
215+
(`log_min_error_statement`), preventing leakage to the PostgreSQL log
216+
in both success and failure scenarios.
217+
196218
The Status section of the cluster does not print the query statement for any
197219
managed role operation.
198220

221+
#### Opting out of operator-side encoding
222+
223+
If you need PostgreSQL (not the operator) to decide how the password is
224+
hashed (for example, on a cluster running `password_encryption = md5`),
225+
set the annotation `cnpg.io/passwordPassthrough: "enabled"` on the
226+
basic-auth Secret. The operator will then forward the password value
227+
verbatim.
228+
229+
:::warning
230+
The `cnpg.io/passwordPassthrough` annotation must be set on the
231+
**basic-auth Secret** itself, not on the `Cluster` resource. Placing it
232+
on the `Cluster` has no effect, and the operator will continue to apply
233+
SCRAM-SHA-256 encoding to the password before sending it to PostgreSQL.
234+
:::
235+
236+
The opt-in is per-Secret and applies to every basic-auth Secret the
237+
operator consumes (managed-role secrets, but also the superuser and
238+
application-user secrets), so a single cluster can mix passthrough
239+
secrets and operator-encoded secrets freely. The statement-logging
240+
suppression layer described above still applies in both modes.
241+
242+
:::warning
243+
With `cnpg.io/passwordPassthrough: "enabled"`, the operator forwards
244+
the Secret's `password` value verbatim. If that value is cleartext (the
245+
common case on a `password_encryption = md5` cluster), extensions such
246+
as `pg_stat_statements` or `pgaudit` will observe it. This is the
247+
expected trade-off for letting PostgreSQL choose the hash format.
248+
:::
249+
199250
## Unrealizable role configurations
200251

201252
In PostgreSQL, in some cases, commands cannot be honored by the database and

website/docs/installation_upgrade.md

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,66 @@ removed before installing the new one. This won't affect user data but
267267
only the operator itself.
268268

269269

270+
<!--
271+
### Upgrading to 1.30.0 or 1.29.2
272+
273+
:::info[Important]
274+
We strongly recommend that all CloudNativePG users upgrade to version
275+
1.30.0, or at least to the latest stable version of your current minor release
276+
(e.g., 1.29.2).
277+
:::
278+
279+
Starting from versions 1.30.0 and 1.29.2, for security reasons,
280+
CloudNativePG SCRAM-SHA-256 encodes role passwords **operator-side**
281+
(client-side from PostgreSQL's point of view) before issuing
282+
`CREATE`/`ALTER ROLE` statements. As a result, the literal that reaches
283+
the PostgreSQL parser (and that extensions such as `pg_stat_statements`
284+
or `pgaudit` may observe) is the same hash that ends up in
285+
`pg_authid.rolpassword`, never the cleartext secret. The encoding is
286+
applied to every basic-auth `Secret` the operator consumes: the
287+
`postgres` superuser secret, the application-user secret, and any
288+
managed-role password secret. Passwords already supplied in MD5 or
289+
SCRAM-SHA-256 shadow form are passed through unchanged.
290+
291+
Since PostgreSQL [14](https://www.postgresql.org/docs/release/14.0/),
292+
`password_encryption` defaults to `scram-sha-256`, so we do not expect
293+
existing installations to be affected by this change.
294+
295+
If your cluster has explicitly overridden `password_encryption` to a
296+
value other than `scram-sha-256` (for example, `md5`) and you want
297+
PostgreSQL (not the operator) to decide how the password is hashed,
298+
opt out by setting the annotation `cnpg.io/passwordPassthrough: "enabled"`
299+
on each basic-auth `Secret` the operator consumes. The operator will
300+
then forward the password value verbatim, and PostgreSQL will encode it
301+
according to its own `password_encryption` GUC.
302+
303+
:::warning
304+
The `cnpg.io/passwordPassthrough` annotation must be set on the
305+
**basic-auth Secret** itself, not on the `Cluster` resource. Placing it
306+
on the `Cluster` has no effect, and the operator will continue to apply
307+
SCRAM-SHA-256 encoding to the password before sending it to PostgreSQL.
308+
:::
309+
310+
:::warning
311+
With `cnpg.io/passwordPassthrough: "enabled"` the operator forwards the
312+
Secret's `password` value verbatim. If that value is cleartext, as is
313+
common on `password_encryption = md5` clusters, extensions such as
314+
`pg_stat_statements` or `pgaudit` will observe it.
315+
:::
316+
317+
See ["Opting out of operator-side encoding"](declarative_role_management.md#opting-out-of-operator-side-encoding)
318+
for details.
319+
320+
-->
321+
270322
### Upgrading to 1.29.1 or 1.28.3
271323

324+
:::info[Important]
325+
We strongly recommend that all CloudNativePG users upgrade to version
326+
1.29.1, or at least to the latest stable version of your current minor release
327+
(e.g., 1.28.x).
328+
:::
329+
272330
Version 1.29.1 and 1.28.3 ship the fix for `CVE-2026-44477` /
273331
`GHSA-423p-g724-fr39`. The metrics exporter now authenticates as a
274332
dedicated `cnpg_metrics_exporter` role with `pg_monitor` privileges
@@ -283,14 +341,6 @@ the metrics exporter
283341
role"](monitoring.md#manually-creating-the-metrics-exporter-role) in
284342
the monitoring documentation.
285343

286-
### Upgrading to 1.29.0 or 1.28.x
287-
288-
:::info[Important]
289-
We strongly recommend that all CloudNativePG users upgrade to version
290-
1.29.0, or at least to the latest stable version of your current minor release
291-
(e.g., 1.28.x).
292-
:::
293-
294344
### Upgrading to 1.27 from a previous minor version
295345

296346
Version 1.27 introduces a change in the default behavior of the

website/docs/labels_annotations.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ CloudNativePG manages the following predefined annotations:
201201
`cnpg.io/operatorVersion`
202202
: Version of the operator.
203203

204+
`cnpg.io/passwordPassthrough`
205+
: When set to `enabled` on a basic-auth `Secret` consumed by the
206+
operator (superuser, application user, or a managed-role password
207+
secret), the operator forwards the password value verbatim in the
208+
`CREATE`/`ALTER ROLE` statement instead of SCRAM-SHA-256 encoding
209+
it operator-side. PostgreSQL then encodes the value according to its
210+
own `password_encryption` setting. See [Opting out of operator-side encoding](declarative_role_management.md#opting-out-of-operator-side-encoding).
211+
204212
`cnpg.io/pgControldata`
205213
: Output of the `pg_controldata` command. This annotation replaces the old,
206214
deprecated `cnpg.io/hibernatePgControlData` annotation.

0 commit comments

Comments
 (0)