mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-19 19:01:42 +00:00
feat: validate the initial database name at create and in the guest
DBName was passed through unvalidated, so a name such as my-db was accepted at CreateDBInstance and only quoted into safety by psql inside the guest. Engine gains a validateDBName rule and ValidateDBName, and rds-init re-checks the same rule in load_handoff before initdb, where a failure would clear the datadir and spend the one-shot master password. PostgreSQL caps the name at NAMEDATALEN-1.
This commit is contained in:
@@ -71,6 +71,10 @@ MOUNTS_FILE="${RDS_MOUNTS_FILE:-/proc/mounts}"
|
||||
# AWS, so a customer's `GRANT rds_superuser TO ...` works here too.
|
||||
MASTER_GROUP_ROLE="rds_superuser"
|
||||
|
||||
# NAMEDATALEN-1: the server truncates a longer identifier, so the database
|
||||
# created would not be the one the customer asked for.
|
||||
MAX_DB_NAME_LEN=63
|
||||
|
||||
log() { echo "[rds-init] $*"; }
|
||||
fail() { echo "[rds-init] ERROR: $*" >&2; exit 1; }
|
||||
|
||||
@@ -134,6 +138,20 @@ load_handoff() {
|
||||
;;
|
||||
esac
|
||||
|
||||
# The same rule the control plane applies, for the same reason the reserved
|
||||
# name is re-checked: an unusable name reaches initdb, fails at CREATE
|
||||
# DATABASE and spends the one-shot password on the way. psql quotes the
|
||||
# identifier, so here this is defence in depth rather than the barrier.
|
||||
case "${RDS_DB_NAME}" in
|
||||
'') ;;
|
||||
[!A-Za-z]* | *[!A-Za-z0-9_]*)
|
||||
fail "RDS_DB_NAME ${RDS_DB_NAME} must begin with a letter and hold only letters, digits and underscores; the control plane should have rejected it"
|
||||
;;
|
||||
esac
|
||||
if [ "${#RDS_DB_NAME}" -gt "${MAX_DB_NAME_LEN}" ]; then
|
||||
fail "RDS_DB_NAME is longer than the ${MAX_DB_NAME_LEN} characters PostgreSQL allows; the control plane should have rejected it"
|
||||
fi
|
||||
|
||||
case "${RDS_PORT}" in
|
||||
'' | *[!0-9]*) fail "bootstrap config has a non-numeric RDS_PORT: ${RDS_PORT}" ;;
|
||||
esac
|
||||
|
||||
@@ -207,7 +207,10 @@ write_handoff() {
|
||||
# password carrying shell metacharacters — or a newline — survive the
|
||||
# handoff intact and reach the checks that exist for it.
|
||||
[ -n "$2" ] && echo "RDS_MASTER_PASSWORD='$2'"
|
||||
[ -n "$3" ] && echo "RDS_DB_NAME=$3"
|
||||
# Quoted as rds-agent's shellQuote writes it, so a name carrying a space
|
||||
# or a shell metacharacter survives the handoff and reaches the check
|
||||
# that exists for it rather than being mangled on the way.
|
||||
[ -n "$3" ] && echo "RDS_DB_NAME='$3'"
|
||||
[ -n "${PENDING:-}" ] && echo "RDS_BOOTSTRAP_PENDING=${PENDING}"
|
||||
[ -n "${PAYLOAD_ID:-}" ] && echo "RDS_PAYLOAD_ID=${PAYLOAD_ID}"
|
||||
# Last, and unconditional: an optional line failing its test would make
|
||||
@@ -811,6 +814,31 @@ for reserved in postgres rds_superuser rdsadmin pg_toast_owner PostGres; do
|
||||
unset MASTER_USER
|
||||
done
|
||||
|
||||
# --- Case 10: an initial database name the control plane would have refused ---
|
||||
# The name is interpolated into a CREATE DATABASE, and a failure there is a
|
||||
# failure after initdb: the datadir is cleared and the one-shot password is
|
||||
# gone. Refusing before initdb is what keeps the create retryable.
|
||||
for badname in 'my-db' 'my db' 'my/db' 'my.db' '1db' \
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; do
|
||||
reset_state
|
||||
write_handoff initialize 's3cr3t' "${badname}"
|
||||
run_fails "bad-dbname-${badname}"
|
||||
[ -s "${INITDB_CALLS}" ] \
|
||||
&& fail "bad-dbname-${badname}: initdb ran before the name was refused" \
|
||||
|| pass "bad-dbname-${badname}: refused before initdb"
|
||||
done
|
||||
|
||||
# The rule is a rejection of malformed names, not of every name: the boundary
|
||||
# length and an underscore have to keep working.
|
||||
reset_state
|
||||
write_handoff initialize 's3cr3t' \
|
||||
'a_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
||||
write_parameters
|
||||
if run_ok "dbname-at-the-limit"; then
|
||||
grep -q 'CREATE DATABASE' "${PSQL_CALLS}" \
|
||||
&& pass "dbname-at-the-limit: accepted" || fail "dbname-at-the-limit: no CREATE DATABASE"
|
||||
fi
|
||||
|
||||
if [ "${FAILS}" -eq 0 ]; then
|
||||
echo "PASS: all rds-init cases"
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user