#!/usr/bin/env bash # Read-only lookups against prod read replicas (IAM auth). IDs/metadata only. # # prod-query.sh "\" | --tables | --columns " alias_name="$1"; shift row="$(awk -F'\t' -v a="$alias_name" '$1 == a { print; exit }' "$DIR/databases.tsv")" [[ -n "$row" ]] || die "unknown alias '$alias_name'. Known: $(cut -f1 "$DIR/databases.tsv" | paste -sd' ' -)" host="$(cut -f2 <<<"$row")" database="$(cut -f3 <<<"$row")" internal=0 case "$1" in --tables) internal=1 sql="select table_schema, table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by 1, 2" ;; --columns) [[ $# -eq 2 ]] || die "--columns needs a table name" [[ "$2" =~ ^[A-Za-z0-9_.]+$ ]] || die "invalid table name" internal=1 sql="select column_name, data_type from information_schema.columns where table_name = '${2##*.}' order by ordinal_position" ;; *) sql="$1" ;; esac if [[ $internal -eq 0 ]]; then sql="$(sed -E 's/[[:space:]]*;[[:space:]]*$//' <<<"$sql")" lc="$(tr '[:upper:]' '[:lower:]' <<<"$sql" | tr '\n' ' ')" [[ "$lc" =~ ^[[:space:]]*(select|with)[[:space:]] ]] || die "only a single SELECT/WITH statement is allowed" [[ "$sql" != *";"* ]] || die "multiple statements are not allowed" [[ ! "$lc" =~ (^|[^a-z_])(insert|update|delete|drop|alter|create|grant|revoke|truncate|copy|call|do|set|reset|lock|vacuum|pg_read_file|pg_ls_dir|dblink|lo_import|lo_export)([^a-z_]|$) ]] \ || die "statement contains a disallowed keyword" stripped="$(sed -E 's/count\([[:space:]]*\*[[:space:]]*\)//g' <<<"$lc")" [[ ! "$stripped" =~ (select|,)[[:space:]]*(distinct[[:space:]]+)?([a-z_0-9]+\.)?\* ]] \ || die "'*' in the select list is not allowed; list explicit ID/metadata columns (use --columns
)" fi aws sts get-caller-identity --profile "$PROFILE" >/dev/null 2>&1 \ || die "no valid AWS SSO session. Run: ! aws sso login --profile $PROFILE" PGPASSWORD="$(aws --profile "$PROFILE" rds generate-db-auth-token \ --hostname "$host" --port 5432 --region "$REGION" --username "$DB_USER")" export PGPASSWORD export PGHOST="$host" PGPORT=5432 PGDATABASE="$database" PGUSER="$DB_USER" PGSSLMODE=require export PGOPTIONS="-c default_transaction_read_only=on -c statement_timeout=30000" out="$(mktemp)" trap 'rm -f "$out"' EXIT psql -X --csv -v ON_ERROR_STOP=1 -c "$sql" >"$out" header="$(head -n 1 "$out")" if [[ $internal -eq 0 ]]; then bad="$(tr ',' '\n' <<<"$header" | tr -d '"' | grep -Ei "$DENY_COLS" || true)" if [[ -n "$bad" ]]; then echo "prod-query: blocked, output columns look like PII/PHI (rows not shown):" >&2 echo "$bad" >&2 echo "Select IDs/metadata only; use these fields only inside WHERE." >&2 exit 2 fi fi total=$(( $(wc -l <"$out") - 1 )) head -n $(( MAX_ROWS + 1 )) "$out" \ | sed -E 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}//g' if (( total > MAX_ROWS )); then echo "prod-query: output truncated to $MAX_ROWS of $total rows" >&2 fi