Skip to content

Commit

Permalink
With this change, it is possible to apply the required
Browse files Browse the repository at this point in the history
SSL configuration to enable SSL in the PG database.
Specifically, by mounting the appropriate certificates
in the pgconf directory, it is possible to  configure
the 'ssl_key_file', 'ssl_cert_file', 'ssl_ca_file' and
'ssl_crl_file' postgresql.conf settings for the cluster
via the DCS, effectively enabling the use of SSL and
client certificates when connecting to and
authenticating into the database.

In support of configuring the DCS for SSL, the
mechanism for detecting that the local node has been
initialized has been updated.  Now, in addition to
verifying that the node is in a running state, a check
is performed to first determine whether the local node
has the primary or replica role, and then whether or not
the primary or replica endpoint (depending on the role
identified) is returning status code 200.  This ensures
that all initial configuration has been applied to the
node prior to updating the DCS with the SSL configuration
using a JSON patch.

And finally, it is now possible to specify the certificates
needed to allow the replication user to authenticate via
client certificate in lieu of using a replication password.
  • Loading branch information
andrewlecuyer authored and jkatz committed Dec 30, 2019
1 parent cc4a798 commit 128011f
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 6 deletions.
35 changes: 35 additions & 0 deletions bin/postgres-ha/bootstrap-postgres-ha.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,33 @@ trap_sigterm() {
initialization_monitor() {
echo_info "Starting background process to monitor Patroni initization and restart the database if needed"
{
# Wait for the local node to enter a "running" state
while [[ $(curl --silent "127.0.0.1:${PGHA_PATRONI_PORT}/patroni" --stderr - \
| /opt/cpm/bin/yq r - state 2> /dev/null) != "running" ]]
do
sleep 1
echo "Cluster not yet inititialized, retrying" >> "/tmp/patroni_initialize_check.log"
done

# Identify the role of the local node, i.e. primary (master) or replica
init_role=$(curl --silent "127.0.0.1:${PGHA_PATRONI_PORT}/patroni" --stderr - | \
/opt/cpm/bin/yq r - role)

# Wait until the local primary or replica returns 200 indicating it is running
status_code=$(curl -o /dev/stderr -w "%{http_code}" "127.0.0.1:${PGHA_PATRONI_PORT}/${init_role}" 2> /dev/null)
until [[ "${status_code}" == "200" ]]
do
sleep 1
echo "${init_role} not yet inititialized, retrying" >> "/tmp/patroni_initialize_check.log"

status_code=$(curl -o /dev/stderr -w "%{http_code}" "127.0.0.1:${PGHA_PATRONI_PORT}/${init_role}" 2> /dev/null)
done

# Apply custom configuration other than custom 'postgres-ha.yaml', e.g. custom keys and
# certificates to enable SSL
source /opt/cpm/bin/ssl-config.sh
echo_info "SSL config is: ${PGHA_SSL_CONFIG}"

if [[ "${init_role}" == "master" ]]
then
echo_info "Detected that the local node has been initialized as 'master'"
Expand All @@ -78,6 +96,18 @@ initialization_monitor() {
echo_info "Creating user crunchyadm"
psql -c "CREATE USER crunchyadm LOGIN;"
fi

# If SSL certificates have been configured for the cluster, patch the cluster
# configuration to enable SSL and then restart the node
if [[ "${PGHA_SSL_CONFIG}" != "" ]]
then
echo_info "Now patching DCS to apply SSL configuration ${PGHA_SSL_CONFIG}"
curl -s -XPATCH -d \
"{\"postgresql\":{\"parameters\":{\"ssl\":\"on\"${PGHA_SSL_CONFIG}}}}" \
"127.0.0.1:${PGHA_PATRONI_PORT}/config"
echo_info "Executing Patroni restart to apply SSL configuration"
curl -X POST --silent "127.0.0.1:${PGHA_PATRONI_PORT}/restart"
fi
else
echo_info "Detected that the local node has been initialized as 'replica'"
echo_info "The post-init process is not executed for replicas and will be skipped"
Expand Down Expand Up @@ -213,6 +243,11 @@ initialization_monitor
# Remove the pause key from patroni.dynamic.json if it exists
remove_patroni_pause_key

# Ensure any existing SSL certificates in PGDATA have the proper permissions
chmod -f 0600 "${PATRONI_POSTGRESQL_DATA_DIR}/server.key" "${PATRONI_POSTGRESQL_DATA_DIR}/server.crt" \
"${PATRONI_POSTGRESQL_DATA_DIR}/ca.crt" "${PATRONI_POSTGRESQL_DATA_DIR}/ca.crl" \
"${PATRONI_POSTGRESQL_DATA_DIR}/replicator.crt" "${PATRONI_POSTGRESQL_DATA_DIR}/replicator.key"

# Bootstrap the cluster
bootstrap_cmd="$@ /tmp/postgres-ha-bootstrap.yaml"
echo_info "Initializing cluster bootstrap with command: '${bootstrap_cmd}'"
Expand Down
21 changes: 15 additions & 6 deletions bin/postgres-ha/pre-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ set_pg_user_credentials() {
env_check_err "PGHA_USER_PASSWORD"
fi

if [[ -d "/pgconf/pguser" ]]
if [[ -d "/pgconf/pgsuper" ]]
then
echo_info "Setting 'superuser' credentials using file system"

Expand All @@ -220,17 +220,26 @@ set_pg_user_credentials() {
env_check_err "PATRONI_SUPERUSER_PASSWORD"
fi

if [[ -d "/pgconf/pguser" ]]
if [[ -d "/pgconf/pgreplicator" ]]
then
echo_info "Setting 'replicator' credentials using file system"

# Configure certificate-based authentication for replication if proper certs are available.
# Otherwise use a password
if [[ -f "/pgconf/replicator.key" ]] && [[ -f "/pgconf/replicator.crt" ]] && [[ -f "/pgconf/ca.crt" ]]
then
export PATRONI_REPLICATION_SSLKEY="${PATRONI_POSTGRESQL_DATA_DIR}/replicator.key"
export PATRONI_REPLICATION_SSLCERT="${PATRONI_POSTGRESQL_DATA_DIR}/replicator.crt"
export PATRONI_REPLICATION_SSLROOTCERT="${PATRONI_POSTGRESQL_DATA_DIR}/ca.crt"
else
PATRONI_REPLICATION_PASSWORD=$(cat /pgconf/pgreplicator/password)
err_check "$?" "Set replication user password" "Unable to set PATRONI_REPLICATION_PASSWORD using secret"
export PATRONI_REPLICATION_PASSWORD
fi

PATRONI_REPLICATION_USERNAME=$(cat /pgconf/pgreplicator/username)
err_check "$?" "Set replication user" "Unable to set PATRONI_REPLICATION_USERNAME using secret"
export PATRONI_REPLICATION_USERNAME

PATRONI_REPLICATION_PASSWORD=$(cat /pgconf/pgreplicator/password)
err_check "$?" "Set replication user password" "Unable to set PATRONI_REPLICATION_PASSWORD using secret"
export PATRONI_REPLICATION_PASSWORD
else
env_check_err "PATRONI_REPLICATION_USERNAME"
env_check_err "PATRONI_REPLICATION_PASSWORD"
Expand Down
48 changes: 48 additions & 0 deletions bin/postgres-ha/ssl-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

source /opt/cpm/bin/common_lib.sh
enable_debugging

PGHA_SSL_CONFIG=""

custom_config() {
src=${1?}
dest=${2?}
mode=${3?}
if [[ -f ${src?} ]]
then
echo_info "Custom ${src?} detected. Applying custom configuration.."

cp ${src?} ${dest?}
err_check "$?" "Applying custom configuration" "Could not copy ${src?} to ${dest?}"

chmod ${mode?} ${dest?}
err_check "$?" "Applying custom configuration" "Could not set mode ${mode?} on ${dest?}"

case "${src?}" in
"/pgconf/server.key")
PGHA_SSL_CONFIG+=",\"ssl_key_file\":\"server.key\""
;;
"/pgconf/server.crt")
PGHA_SSL_CONFIG+=",\"ssl_cert_file\":\"server.crt\""
;;
"/pgconf/ca.crt")
PGHA_SSL_CONFIG+=",\"ssl_ca_file\":\"ca.crt\""
;;
"/pgconf/ca.crl")
PGHA_SSL_CONFIG+=",\"ssl_crl_file\":\"ca.crl\""
;;
esac
fi
}

# Call the custom-config function in order to configure any certificates available in the
# '/pgconf' directory as needed to enable SSL
custom_config "/pgconf/server.key" "${PATRONI_POSTGRESQL_DATA_DIR}/server.key" 600
custom_config "/pgconf/server.crt" "${PATRONI_POSTGRESQL_DATA_DIR}/server.crt" 600
custom_config "/pgconf/ca.crt" "${PATRONI_POSTGRESQL_DATA_DIR}/ca.crt" 600
custom_config "/pgconf/ca.crl" "${PATRONI_POSTGRESQL_DATA_DIR}/ca.crl" 600
custom_config "/pgconf/replicator.crt" "${PATRONI_POSTGRESQL_DATA_DIR}/replicator.crt" 600
custom_config "/pgconf/replicator.key" "${PATRONI_POSTGRESQL_DATA_DIR}/replicator.key" 600

export PGHA_SSL_CONFIG

0 comments on commit 128011f

Please sign in to comment.