mirror of https://github.com/postgres/postgres
Scripts are passphrase, direct, AWS, and two Yubikey ones. Backpatch-through: masterpull/59/head
parent
3d4843babc
commit
d7602afa2e
@ -0,0 +1,50 @@ |
||||
#!/bin/sh |
||||
|
||||
# This uses the AWS Secrets Manager using the AWS CLI and OpenSSL. |
||||
|
||||
[ "$#" -ne 1 ] && echo "cluster_key_command usage: $0 \"%d\"" 1>&2 && exit 1 |
||||
# No need for %R or -R since we are not prompting |
||||
|
||||
DIR="$1" |
||||
[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 |
||||
[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 |
||||
|
||||
# File containing the id of the AWS secret |
||||
AWS_ID_FILE="$DIR/aws-secret.id" |
||||
|
||||
|
||||
# ---------------------------------------------------------------------- |
||||
|
||||
|
||||
# Create an AWS Secrets Manager secret? |
||||
if [ ! -e "$AWS_ID_FILE" ] |
||||
then # The 'postgres' operating system user must have permission to |
||||
# access the AWS CLI |
||||
|
||||
# The epoch-time/directory/hostname combination is unique |
||||
HASH=$(echo -n "$(date '+%s')$DIR$(hostname)" | sha1sum | cut -d' ' -f1) |
||||
AWS_SECRET_ID="Postgres-cluster-key-$HASH" |
||||
|
||||
# Use stdin to avoid passing the secret on the command line |
||||
openssl rand -hex 32 | |
||||
aws secretsmanager create-secret \ |
||||
--name "$AWS_SECRET_ID" \ |
||||
--description 'Used for Postgres cluster file encryption' \ |
||||
--secret-string 'file:///dev/stdin' \ |
||||
--output text > /dev/null |
||||
if [ "$?" -ne 0 ] |
||||
then echo 'cluster key generation failed' 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "$AWS_SECRET_ID" > "$AWS_ID_FILE" |
||||
fi |
||||
|
||||
if ! aws secretsmanager get-secret-value \ |
||||
--secret-id "$(cat "$AWS_ID_FILE")" \ |
||||
--output text |
||||
then echo 'cluster key retrieval failed' 1>&2 |
||||
exit 1 |
||||
fi | awk -F'\t' 'NR == 1 {print $4}' |
||||
|
||||
exit 0 |
@ -0,0 +1,37 @@ |
||||
#!/bin/sh |
||||
|
||||
# This uses a key supplied by the user |
||||
# If OpenSSL is installed, you can generate a pseudo-random key by running: |
||||
# openssl rand -hex 32 |
||||
# To get a true random key, run: |
||||
# wget -q -O - 'https://www.random.org/cgi-bin/randbyte?nbytes=32&format=h' | tr -d ' \n'; echo |
||||
|
||||
[ "$#" -lt 1 ] && echo "cluster_key_command usage: $0 %R [%p]" 1>&2 && exit 1 |
||||
# Supports environment variable PROMPT |
||||
|
||||
FD="$1" |
||||
[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 |
||||
|
||||
[ "$2" ] && PROMPT="$2" |
||||
|
||||
|
||||
# ---------------------------------------------------------------------- |
||||
|
||||
[ ! "$PROMPT" ] && PROMPT='Enter cluster key as 64 hexadecimal characters: ' |
||||
|
||||
stty -echo <&"$FD" |
||||
|
||||
echo 1>&"$FD" |
||||
echo -n "$PROMPT" 1>&"$FD" |
||||
read KEY <&"$FD" |
||||
|
||||
stty echo <&"$FD" |
||||
|
||||
if [ "$(expr "$KEY" : '[0-9a-fA-F]*$')" -ne 64 ] |
||||
then echo 'invalid; must be 64 hexadecimal characters' 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "$KEY" |
||||
|
||||
exit 0 |
@ -0,0 +1,33 @@ |
||||
#!/bin/sh |
||||
|
||||
# This uses a passphrase supplied by the user. |
||||
|
||||
[ "$#" -lt 1 ] && echo "cluster_key_command usage: $0 %R [\"%p\"]" 1>&2 && exit 1 |
||||
|
||||
FD="$1" |
||||
[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 |
||||
# Supports environment variable PROMPT |
||||
|
||||
[ "$2" ] && PROMPT="$2" |
||||
|
||||
|
||||
# ---------------------------------------------------------------------- |
||||
|
||||
[ ! "$PROMPT" ] && PROMPT='Enter cluster passphrase: ' |
||||
|
||||
stty -echo <&"$FD" |
||||
|
||||
echo 1>&"$FD" |
||||
echo -n "$PROMPT" 1>&"$FD" |
||||
read PASS <&"$FD" |
||||
|
||||
stty echo <&"$FD" |
||||
|
||||
if [ ! "$PASS" ] |
||||
then echo 'invalid: empty passphrase' 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "$PASS" | sha256sum | cut -d' ' -f1 |
||||
|
||||
exit 0 |
@ -0,0 +1,63 @@ |
||||
#!/bin/sh |
||||
|
||||
# This uses the public/private keys on a PIV device, like a CAC or Yubikey. |
||||
# It uses a PIN stored in a file. |
||||
# It uses OpenSSL with PKCS11 enabled via OpenSC. |
||||
|
||||
[ "$#" -ne 1 ] && echo "cluster_key_command usage: $0 \"%d\"" 1>&2 && exit 1 |
||||
# Supports environment variable PIV_PIN_FILE |
||||
# No need for %R or -R since we are not prompting for a PIN |
||||
|
||||
DIR="$1" |
||||
[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 |
||||
[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 |
||||
|
||||
# Set these here or pass in as environment variables. |
||||
# File that stores the PIN to unlock the PIV |
||||
#PIV_PIN_FILE='' |
||||
# PIV slot 3 is the "Key Management" slot, so we use '0:3' |
||||
PIV_SLOT='0:3' |
||||
|
||||
# File containing the cluster key encrypted with the PIV_SLOT's public key |
||||
KEY_FILE="$DIR/pivpass.key" |
||||
|
||||
|
||||
# ---------------------------------------------------------------------- |
||||
|
||||
[ ! "$PIV_PIN_FILE" ] && echo 'PIV_PIN_FILE undefined' 1>&2 && exit 1 |
||||
[ ! -e "$PIV_PIN_FILE" ] && echo "$PIV_PIN_FILE does not exist" 1>&2 && exit 1 |
||||
[ -d "$PIV_PIN_FILE" ] && echo "$PIV_PIN_FILE is a directory" 1>&2 && exit 1 |
||||
|
||||
[ ! "$KEY_FILE" ] && echo 'KEY_FILE undefined' 1>&2 && exit 1 |
||||
[ -d "$KEY_FILE" ] && echo "$KEY_FILE is a directory" 1>&2 && exit 1 |
||||
|
||||
# Create a cluster key encrypted with the PIV_SLOT's public key? |
||||
if [ ! -e "$KEY_FILE" ] |
||||
then # The 'postgres' operating system user must have permission to |
||||
# access the PIV device. |
||||
|
||||
openssl rand -hex 32 | |
||||
if ! openssl rsautl -engine pkcs11 -keyform engine -encrypt \ |
||||
-inkey "$PIV_SLOT" -passin file:"$PIV_PIN_FILE" -out "$KEY_FILE" |
||||
then echo 'cluster key generation failed' 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
# Warn the user to save the cluster key in a safe place |
||||
cat 1>&2 <<END |
||||
|
||||
WARNING: The PIV device can be locked and require a reset if too many PIN |
||||
attempts fail. It is recommended to run this command manually and save |
||||
the cluster key in a secure location for possible recovery. |
||||
END |
||||
|
||||
fi |
||||
|
||||
# Decrypt the cluster key encrypted with the PIV_SLOT's public key |
||||
if ! openssl rsautl -engine pkcs11 -keyform engine -decrypt \ |
||||
-inkey "$PIV_SLOT" -passin file:"$PIV_PIN_FILE" -in "$KEY_FILE" |
||||
then echo 'cluster key decryption failed' 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
exit 0 |
@ -0,0 +1,76 @@ |
||||
#!/bin/sh |
||||
|
||||
# This uses the public/private keys on a PIV device, like a CAC or Yubikey. |
||||
# It requires a user-entered PIN. |
||||
# It uses OpenSSL with PKCS11 enabled via OpenSC. |
||||
|
||||
[ "$#" -lt 2 ] && echo "cluster_key_command usage: $0 \"%d\" %R [\"%p\"]" 1>&2 && exit 1 |
||||
# Supports environment variable PROMPT |
||||
|
||||
DIR="$1" |
||||
[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 |
||||
[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 |
||||
|
||||
FD="$2" |
||||
[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 |
||||
|
||||
[ "$3" ] && PROMPT="$3" |
||||
|
||||
# PIV slot 3 is the "Key Management" slot, so we use '0:3' |
||||
PIV_SLOT='0:3' |
||||
|
||||
# File containing the cluster key encrypted with the PIV_SLOT's public key |
||||
KEY_FILE="$DIR/pivpass.key" |
||||
|
||||
|
||||
# ---------------------------------------------------------------------- |
||||
|
||||
[ ! "$PROMPT" ] && PROMPT='Enter PIV PIN: ' |
||||
|
||||
stty -echo <&"$FD" |
||||
|
||||
# Create a cluster key encrypted with the PIV_SLOT's public key? |
||||
if [ ! -e "$KEY_FILE" ] |
||||
then echo 1>&"$FD" |
||||
echo -n "$PROMPT" 1>&"$FD" |
||||
|
||||
# The 'postgres' operating system user must have permission to |
||||
# access the PIV device. |
||||
|
||||
openssl rand -hex 32 | |
||||
# 'engine "pkcs11" set.' message confuses prompting |
||||
if ! openssl rsautl -engine pkcs11 -keyform engine -encrypt \ |
||||
-inkey "$PIV_SLOT" -passin fd:"$FD" -out "$KEY_FILE" 2>&1 |
||||
then stty echo <&"$FD" |
||||
echo 'cluster key generation failed' 1>&2 |
||||
exit 1 |
||||
fi | grep -v 'engine "pkcs11" set\.' |
||||
|
||||
echo 1>&"$FD" |
||||
|
||||
# Warn the user to save the cluster key in a safe place |
||||
cat 1>&"$FD" <<END |
||||
|
||||
WARNING: The PIV can be locked and require a reset if too many PIN |
||||
attempts fail. It is recommended to run this command manually and save |
||||
the cluster key in a secure location for possible recovery. |
||||
END |
||||
|
||||
fi |
||||
|
||||
echo 1>&"$FD" |
||||
echo -n "$PROMPT" 1>&"$FD" |
||||
|
||||
# Decrypt the cluster key encrypted with the PIV_SLOT's public key |
||||
if ! openssl rsautl -engine pkcs11 -keyform engine -decrypt \ |
||||
-inkey "$PIV_SLOT" -passin fd:"$FD" -in "$KEY_FILE" 2>&1 |
||||
then stty echo <&"$FD" |
||||
echo 'cluster key retrieval failed' 1>&2 |
||||
exit 1 |
||||
fi | grep -v 'engine "pkcs11" set\.' |
||||
|
||||
echo 1>&"$FD" |
||||
|
||||
stty echo <&"$FD" |
||||
|
||||
exit 0 |
@ -0,0 +1,33 @@ |
||||
#!/bin/sh |
||||
|
||||
# This uses a passphrase supplied by the user. |
||||
|
||||
[ "$#" -lt 1 ] && echo "ssl_passphrase_command usage: $0 %R [\"%p\"]" 1>&2 && exit 1 |
||||
|
||||
FD="$1" |
||||
[ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 |
||||
# Supports environment variable PROMPT |
||||
|
||||
[ "$2" ] && PROMPT="$2" |
||||
|
||||
|
||||
# ---------------------------------------------------------------------- |
||||
|
||||
[ ! "$PROMPT" ] && PROMPT='Enter cluster passphrase: ' |
||||
|
||||
stty -echo <&"$FD" |
||||
|
||||
echo 1>&"$FD" |
||||
echo -n "$PROMPT" 1>&"$FD" |
||||
read PASS <&"$FD" |
||||
|
||||
stty echo <&"$FD" |
||||
|
||||
if [ ! "$PASS" ] |
||||
then echo 'invalid: empty passphrase' 1>&2 |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "$PASS" |
||||
|
||||
exit 0 |
Loading…
Reference in new issue