Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This is a [BOSH](https://www.bosh.io) release for [PostgreSQL](https://www.postg
* [Contributing](#contributing)
* [Known Limitation](#known-limitation)
* [Upgrading](#upgrading)
* [Migrating password authentication from MD5 to SCRAM-SHA-256](#migrating-password-authentication-from-md5-to-scram-sha-256)
* [CI](#ci)

## Deploying
Expand Down Expand Up @@ -194,6 +195,48 @@ Even if you deploy more instances, no replication is configured.

Refer to [versions.yml](versions.yml) in order to assess if a postgres-release version upgrades the PostgreSQL version.

### Migrating password authentication from MD5 to SCRAM-SHA-256

> **⚠ Upcoming breaking change**
>
> The current default for `databases.password_authentication_algorithm` is `md5` for backwards
> compatibility. A future release will change the default to `scram-sha-256`, which is the modern,
> cryptographically stronger algorithm recommended by the PostgreSQL project.

**Why this matters**

`databases.password_authentication_algorithm` controls both the `password_encryption` setting in
`postgresql.conf` and the auth-method column in `pg_hba.conf`. If the value is changed to
`scram-sha-256` while existing role passwords are still stored as MD5 hashes, those roles will
**immediately fail to authenticate** — clients will receive an error until every affected role's
password has been reset so PostgreSQL can re-hash it with SCRAM.

**Migration procedure** (perform these steps in order)

1. Set the property in your deployment manifest:
```yaml
databases.password_authentication_algorithm: scram-sha-256
```
2. Re-deploy so the new `postgresql.conf` and `pg_hba.conf` are applied:
```bash
bosh -d DEPLOYMENT_NAME deploy MANIFEST_PATH
```
3. Reset **every** role password so PostgreSQL re-hashes it with SCRAM.
Connect as a superuser and run for each role:
```sql
ALTER ROLE <name> WITH PASSWORD '<password>';
```
> Roles whose passwords are still stored as MD5 hashes cannot authenticate via SCRAM
> and will be locked out until this step is completed.
4. Verify that no MD5 hashes remain:
```sql
SELECT rolname, rolpassword
FROM pg_authid
WHERE rolpassword NOT LIKE 'SCRAM-SHA-256$%'
AND rolpassword IS NOT NULL;
```
The query must return **zero rows** before the migration is complete.

### Upgrade Test Policy

The maintainers of the postgres-release test the following upgrade paths:
Expand Down
24 changes: 24 additions & 0 deletions jobs/postgres/spec
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,30 @@ properties:
databases.max_connections:
description: "Maximum number of database connections"
default: 500
databases.password_authentication_algorithm:
description: |
Defines the password hashing algorithm used by PostgreSQL for both `password_encryption`
(postgresql.conf) and the auth-method column in pg_hba.conf.
Accepted values: "md5" or "scram-sha-256".

Default is "md5" for backwards compatibility with existing deployments.

*** IMPORTANT – BREAKING CHANGE NOTICE ***
A future release will change the default to "scram-sha-256", which is the modern,
cryptographically stronger algorithm recommended by the PostgreSQL project.

If you want to migrate now, or when the default changes, you MUST:
1. Set this property to "scram-sha-256" in your deployment manifest.
2. Restart / re-deploy PostgreSQL so the new postgresql.conf and pg_hba.conf are applied.
3. Reset every role password so PostgreSQL re-hashes it with SCRAM:
ALTER ROLE <name> WITH PASSWORD '<password>';
Roles whose passwords are still stored as MD5 hashes cannot authenticate
via SCRAM and will be locked out until their password is reset.
4. Verify with:
SELECT rolname, rolpassword FROM pg_authid
WHERE rolpassword NOT LIKE 'SCRAM-SHA-256$%' AND rolpassword IS NOT NULL;
The query should return zero rows when the migration is complete.
default: "md5"
databases.log_line_prefix:
description: "The postgres `printf` style string that is output at the beginning of each log line"
default: "%m: "
Expand Down
12 changes: 10 additions & 2 deletions jobs/postgres/templates/pg_hba.conf.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
<%
_algo = p("databases.password_authentication_algorithm")
unless ["md5", "scram-sha-256"].include?(_algo)
raise "databases.password_authentication_algorithm must be 'md5' or 'scram-sha-256', got: '#{_algo}'. " \
"Note: pg_hba.conf auth-methods such as 'password', 'peer', or 'trust' must be " \
"configured through other properties."
end
%>
local all vcap trust
host all vcap 127.0.0.1/32 trust
host all vcap ::1/128 trust
<% if !p("databases.trust_local_connections").nil? && !p("databases.trust_local_connections") %>
local all all md5
local all all <%= p("databases.password_authentication_algorithm") %>
<% else %>
local all all trust
host all all 127.0.0.1/32 trust
Expand All @@ -18,4 +26,4 @@ host all all ::1/128 trust
line
%>
<% end %>
host all all 0.0.0.0/0 md5
host all all 0.0.0.0/0 <%= p("databases.password_authentication_algorithm") %>
Comment thread
ZPascal marked this conversation as resolved.
7 changes: 7 additions & 0 deletions jobs/postgres/templates/postgresql.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ p("databases.roles", []).each do |role|
end
end
end

_algo = p("databases.password_authentication_algorithm")
unless ["md5", "scram-sha-256"].include?(_algo)
raise "databases.password_authentication_algorithm must be 'md5' or 'scram-sha-256', got: '#{_algo}'. " \
"These are the only values accepted by PostgreSQL's password_encryption parameter."
end
%>
# Control the available listen_addresses via
# deployment manifest - add networks to the job
Expand All @@ -35,6 +41,7 @@ end
listen_addresses = '0.0.0.0'
port = <%= p("databases.port") %>
max_connections = <%= p("databases.max_connections") %>
password_encryption = <%= p("databases.password_authentication_algorithm") %>
external_pid_file = '/var/vcap/sys/run/postgres/postgres.pid'
authentication_timeout = 1min

Expand Down