Skip to content

Instantly share code, notes, and snippets.

@keymon
Last active February 21, 2023 13:15
Show Gist options
  • Save keymon/8abbc70cdafa17f4c159b30b9b0bf9d3 to your computer and use it in GitHub Desktop.
Save keymon/8abbc70cdafa17f4c159b30b9b0bf9d3 to your computer and use it in GitHub Desktop.
Warpper script to get dynamic IAM RDS credentials and call a command (psql, terraform, whatever)
#!/bin/bash
set -o pipefail -e -u
SCRIPT_NAME="$0"
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_ROOT_DIR="$(cd "${SCRIPT_DIR}" && git rev-parse --show-toplevel)"
# Role to assume before trying to assume the master_user role
RDS_CREDS_ROLE_ARN="${RDS_CREDS_ROLE_ARN:-}"
assume_role() {
local role_arn="$1"
local session_name="$2"
# Be sure we unset the AWS credential variables, so there are no conflicts
# with the env vars used in different AWS tool versions
# Related: https://aws.amazon.com/blogs/security/a-new-and-standardized-way-to-manage-credentials-in-the-aws-sdks/
echo "unset AWS_SESSION_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECURITY_TOKEN AWS_ROLE_ARN"
if which aws > /dev/null 2>&1; then
(
[ -n "${LOCAL_AWS_PROFILE:-}" ] && export AWS_PROFILE="${LOCAL_AWS_PROFILE}"
aws sts assume-role --role-arn "${role_arn}" --role-session-name "${session_name}" | \
jq -r '"export -n AWS_PROFILE; export AWS_ACCESS_KEY_ID=\(.Credentials.AccessKeyId) AWS_SECRET_ACCESS_KEY=\(.Credentials.SecretAccessKey) AWS_SESSION_TOKEN=\"\(.Credentials.SessionToken)\""'
)
# Support assume-role-arn, for instance on atlantis
elif which assume-role-arn > /dev/null 2>&1; then
(
[ -n "${LOCAL_AWS_PROFILE:-}" ] && export AWS_PROFILE="${LOCAL_AWS_PROFILE}"
assume-role-arn --role "${role_arn}" --name "${session_name}"
)
else
echo "Unable to find aws cli or assume-role-arn" 1>&2
return 1
fi
}
read_db_info() {
local rds_name="$1"
local rw_or_ro="$2"
local rds_config_file="${PROJECT_ROOT_DIR}/assets/rds-config.${rds_name}.sh"
if [ ! -f "${rds_config_file}" ]; then
echo "ERROR: Cannot find ${rds_config_file} with the static config of RDS" 1>&2
return 1
fi
if [ "${rw_or_ro}" == "ro" ]; then
cat "${rds_config_file}" | sed 's/PGHOST_RO/PGHOST/'
else
cat "${rds_config_file}" | sed 's/PGHOST_RW/PGHOST/'
fi
}
# Assumes AWS creds and DB env vars are set
aws_generate_db_auth_token() {
if which aws > /dev/null 2>&1; then
aws rds generate-db-auth-token \
--hostname "${PGHOST}" \
--port "${PGPORT}" \
--region "${REGION}" \
--username "${PGUSER}"
# Support rds-auth-token, for instance on atlantis
elif which rds-auth-token > /dev/null 2>&1; then
rds-auth-token \
--hostname "${PGHOST}" \
--port "${PGPORT}" \
--region "${REGION}" \
--username "${PGUSER}"
else
echo "Unable to find aws cli or rds-auth-token" 1>&2
return 1
fi
}
get_rds_creds() {
local rds_name="$1"
local rw_or_ro="$2"
# store injected PGHOST and PGPORT
OVERRIDE_PGHOST="${PGHOST:-}"
OVERRIDE_PGPORT="${PGPORT:-}"
# Load DB config
db_info="$(read_db_info "${rds_name}" "${rw_or_ro}")"
# echo "${db_info}" 1>&2
eval "${db_info}"
# Get the new PGPASSWORD token
if [ -n "${PGPASSWORD:-}" ]; then
echo "# WARNING: Using already defined \$PGPASSWORD. Not generating a dynamic | IAM one." 1>&2
else
if [ -n "${LOCAL_AWS_PROFILE:-}" ] && [ \
-n "${AWS_SESSION_TOKEN:-}" -o \
-n "${AWS_ACCESS_KEY_ID:-}" -o \
-n "${AWS_SECRET_ACCESS_KEY:-}" -o \
-n "${AWS_SECURITY_TOKEN:-}" \
]; then
echo "WARNING: Meant to be using a AWS_PROFILE=${LOCAL_AWS_PROFILE} but also some AWS environment creds are set. Might cause a conflict and generate an invalid PGPASSWORD. You might want to run: 'unset AWS_SESSION_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECURITY_TOKEN AWS_ROLE_ARN'" 1>&2
fi
if [ -z "${PGUSER_ROLE_ARN:-}" ]; then
echo "ERROR: neither PGPASSWORD nor PGUSER_ROLE_ARN are set. cannot get credentials" 1>&2
exit 1
fi
PGPASSWORD="$(
# Assume firts role for the account if defined
if [ -n "${RDS_CREDS_ROLE_ARN}" ]; then
assume_role="$(assume_role "${RDS_CREDS_ROLE_ARN}" "rds_iam_master_user")"
[ -n "${assume_role}" ] || exit 1
eval "${assume_role}"
fi
# assume AWS role to connect to the DB as master user
assume_master_user_role="$(assume_role "${PGUSER_ROLE_ARN}" "rds_iam_master_user")"
[ -n "${assume_master_user_role}" ] || exit 1
eval "${assume_master_user_role}"
aws_generate_db_auth_token
)"
[ -n "${PGPASSWORD:-}" ] || return 1
fi
export PGSSLMODE="${PGSSLMODE}"
export PGHOST_REAL="${PGHOST}"
export PGPORT_REAL="${PGPORT}"
export PGHOST="${OVERRIDE_PGHOST:-${PGHOST}}"
export PGPORT="${OVERRIDE_PGPORT:-${PGPORT}}"
export PGDATABASE="${PGDATABASE}"
export PGUSER="${PGUSER}"
export REGION="${REGION}"
export PGPASSWORD="${PGPASSWORD}"
}
print_connection_vars() {
local pgpassword_redacted
local pgpassword_encoded
if [[ "${PGPASSWORD}" == *X-Amz-Credential* ]]; then
pgpassword_redacted="${PGPASSWORD}"
pgpassword_encoded="$(echo "${pgpassword_redacted}" | jq -Rr '. | @uri')"
else
pgpassword_redacted="<redacted>"
pgpassword_encoded="<redacted>"
echo "WARNING: Redacting non RDS IAM PGPASSWORD" 1>&2
fi
cat <<EOF
# DB connection parameters. Note: RDS IAM password lasts 15m
export PGSSLMODE="$PGSSLMODE"
export PGHOST="$PGHOST"
export PGPORT="$PGPORT"
export PGDATABASE="$PGDATABASE"
export PGUSER="$PGUSER"
export PGPASSWORD="$pgpassword_redacted"
export REGION="$REGION"
# Original remote db endpoints
# export PGHOST="$PGHOST_REAL"
# export PGPORT="$PGPORT_REAL"
# DB connection postgres:// url
export DATABASE_URL="postgres://${PGUSER}:${pgpassword_encoded}@${PGHOST}:${PGPORT}/${PGDATABASE}?${PGSSLMODE:+sslmode=${PGSSLMODE}}"
EOF
}
list_configs() {
ls "${PROJECT_ROOT_DIR}"/assets/*.sh | sed -n "s|.*/\?rds-config.\([^.]*\).sh| $SCRIPT_NAME \1 rw|p"
}
usage() {
cat 1>&2 <<EOF
Generates config and variables for RDS in form of shell vars.
Reads the RDS config from the files in:
\$GITROOT/assets/rds-config.<dbname>.sh
and it generates a IAM RDS password using the role from \$PGUSER_ROLE_ARN.
The script will assume that role.
Usage:
$SCRIPT_NAME [options] <dbname> [rw|ro] [cmd]
Options:
--port Override the port to export. Equivalent to export PGPORT
--host Override the host to export. Equivalent to export PGHOST
Examples:
$SCRIPT_NAME my-cool-db-prod rw
$SCRIPT_NAME my-cool-db-prod rw <cmd>
Env vars:
PGPASSWORD if set, uses that value instead of a IAM generated one.
This is good to use static credentials. See below
PGPORT PGHOST if set, will export/print these instead of the config ones.
The configuration PGHOST and PGPORT are still used to generate
the RDS IAM creds.
RDS_CREDS_ROLE_ARN if set, assume this role before assuming PGUSER_ROLE_ARN
LOOP Print the creds in a loop
Example using static creds:
terraform output
read -s -p "Introduce static pass from terraform: " PGPASSWORD
export PGPASSWORD
${SCRIPT_NAME} my-db devel rw
Known configs:
$(list_configs)
EOF
exit 1
}
##############################################################
# Parse arguments
while true; do
case "$1" in
--help|-h)
usage
exit 0
;;
-p|--port)
PGPORT="${2}"
shift
shift
;;
-h|--host)
PGHOST="${2}"
shift
shift
;;
-*)
echo "ERROR: Unknown option: $1" 1>&2
usage
exit 1
;;
*)
break
;;
esac
done
if [ $# -lt 2 ]; then
usage
fi
dbname="${1}"; shift
mode="${1:-rw}"; shift || true
# Store the passed password in a different var
PGPASSWORD_ORIG="${PGPASSWORD:-}"
if [ $# -lt 1 ]; then
# Loop generating RDS creds
while true; do
if get_rds_creds "${dbname}" "${mode}"; then
print_connection_vars
else
echo "ERROR: Failed generating RDS IAM creds. Maybe you need to run gimme-aws-creds again?"1>&2
[ -n "${LOOP:-}" ] || exit 1
fi
[ -n "${LOOP:-}" ] || break
# Restore the originally passed if any, so next loops generate it again
PGPASSWORD="${PGPASSWORD_ORIG}"
read -p "Press enter to generate new creds. Ctrl+C to continue."
done
else
get_rds_creds "${dbname}" "${mode}"
"$@"
fi
# Where to start the tunnel
export TUNNEL_CONTEXT="some-k8s-cluster-used-for-tunneling"
export PGSSLMODE=require
export PGHOST_RW=my-cool-db.asdfghjkl.us-west-2.rds.amazonaws.com
# export PGHOST_RO=n/a
export PGPORT=5432
export PGDATABASE=my-cool-db
export PGUSER=${PGUSER:-theboss}
export REGION=us-west-2
export PGUSER_ROLE_ARN="arn:aws:iam::1234567890:role/my-cool-db_admin_master_user"
# AWS profile to use when running locally
export LOCAL_AWS_PROFILE=my-production-account-profile
#!/bin/bash
# shellcheck shell=bash
# shellcheck disable=SC2088
set -e -o pipefail -u
SCRIPT_NAME="$0"
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_ROOT_DIR="$(cd "${SCRIPT_DIR}" && git rev-parse --show-toplevel)"
usage() {
cat <<EOF
Combines retrieval of the DB creds (ie RDS IAM) with setting up a tunnel
to the RDS instance.
See the scripts for more details:
./${SCRIPT_DIR}/rds-tunnel-pod.sh
./${SCRIPT_DIR}/rds_creds.sh
for more details
Loads the DB config from ./assets/*
Usage:
${SCRIPT_NAME} <dbname> <rw|ro> [cmd]
If no cmd is passed, it will just sleep and print the credentials
Existing RDS databases:
EOF
# Print the existing configs
ls ${PROJECT_ROOT_DIR}/assets/rds-config.* | sed "s|.*/rds-config.\(.*\)\.sh| ${SCRIPT_NAME} \1 rw psql|"
echo
exit 0
}
if [ $# -lt 2 ]; then
usage
fi
dbname="${1}"; shift
mode="${1:-rw}"; shift || true
# Run rds_creds to fail quick if AWS creds are not working
"${SCRIPT_DIR}"/rds_creds.sh "${dbname}" "${mode}" > /dev/null
if [ $# -lt 1 ]; then
LOOP=1 \
"${SCRIPT_DIR}"/rds-tunnel-pod.sh run "${dbname}" "${mode}" \
"${SCRIPT_DIR}"/rds_creds.sh "${dbname}" "${mode}"
else
"${SCRIPT_DIR}"/rds-tunnel-pod.sh run "${dbname}" "${mode}" \
"${SCRIPT_DIR}"/rds_creds.sh "${dbname}" "${mode}" "$@"
fi
#!/bin/bash
set -o pipefail -e -u
SCRIPT_NAME="$0"
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_ROOT_DIR="$(cd "${SCRIPT_DIR}" && git rev-parse --show-toplevel)"
usage() {
cat 1>&2 <<EOF
Helper script that re-exports all the postgres RDS connection vars into
variables with some prefix.
This is very useful to pass credentials to terraform as TF_VAR_<foo>.
It will unset the postgres variables. It can call a sub command or
just print to stdout.
This is meant to be used in combination with other scripts.
Usage:
$SCRIPT_NAME <prefix> [cmd]
Example:
./scripts/rds-connect-wrapper.sh my-cool-db rw \
$SCRIPT_NAME TF_VAR_my-cool-db-rw \
terraform plan
EOF
}
print_connection_vars() {
local prefix="$1"
cat <<EOF
# DB connection parameters. Note: RDS IAM password lasts 15m
export ${prefix}_pgsslmode="$PGSSLMODE"
export ${prefix}_pghost="$PGHOST"
export ${prefix}_pgport="$PGPORT"
export ${prefix}_pgdatabase="$PGDATABASE"
export ${prefix}_pguser="$PGUSER"
export ${prefix}_pgpassword="$PGPASSWORD"
export ${prefix}_region="$REGION"
# DB connection postgres:// url
export ${prefix}_database_url="postgres://${PGUSER}:${PGPASSWORD}@${PGHOST}:${PGPORT}/${PGDATABASE}?${PGSSLMODE:+sslmode=${PGSSLMODE}}"
EOF
}
unset_vars() {
unset PGSSLMODE PGHOST PGPORT PGDATABASE PGUSER PGPASSWORD REGION
}
if [ $# -lt 1 ]; then
usage
fi
prefix="${1}"; shift
if [ $# -lt 1 ]; then
print_connection_vars "${prefix}"
else
eval "$(print_connection_vars "${prefix}")"
# Unset the PG* before running the command
unset PGSSLMODE PGHOST PGPORT PGDATABASE PGUSER PGPASSWORD
"$@"
fi
#!/bin/bash
# shellcheck shell=bash
# shellcheck disable=SC2088
set -e -o pipefail -u
SCRIPT_NAME="$0"
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_ROOT_DIR="$(cd "${SCRIPT_DIR}" && git rev-parse --show-toplevel)"
#----------------------------------------------------------
TUNNEL_NAMESPACE=rds-tunnel
TUNNEL_LABEL=type=rds-tunnel
TUNNEL_TTL=3600
TUNNEL_WAIT_TTL=360
# Override for instance when running on docker to host.docker.internal
TUNNEL_HOST="${TUNNEL_HOST:-localhost}"
# Override if running on docker with, for instance
# localhost,172.17.0.1
# or the output of
# docker network inspect bridge --format='{{(index .IPAM.Config 0).Gateway}}'
TUNNEL_LISTEN_ADDR="${TUNNEL_LISTEN_ADDR:-localhost}"
#----------------------------------------------------------
check_aws_creds() {
# TODO: add more smart checks, like check that the account id matches
if ! aws sts get-caller-identity > /dev/null; then
echo "Unable to use AWS creds. Did you load the creds for the corresponding environment (ie. gimme-aws-creds)?" 1>&2
if [ -n "${AWS_ACCESS_KEY_ID}" ]; then
echo "AWS_ACCESS_KEY_ID is set. Maybe credentials are expired?" 1>&2
fi
if [ -z "${AWS_PROFILE}" ]; then
echo "AWS_PROFILE is not set, maybe set it? For instance: export AWS_PROFILE=my-prod-env-db-administrator" 1>&2
else
echo "AWS_PROFILE is set. Maybe credentials are expired?" 1>&2
fi
exit 1
fi
}
wait_kubectl_tunnel() {
local output_file="$1"
local kubectl_tunnel_pid="$2"
echo "Waiting for tunnel to start. Press Ctrl+C to cancel..." 1>&2
if [ -z "${CCTUNNEL_SLEEP_WAIT:-}" ]; then
# Wait for at least one "Forwarding" line
while ! grep -q "Forwarding" "${output_file}"; do sleep 1; done
echo "Tunnel started in $!" 1>&2
else
# Simple sleep wait
sleep 10
fi
if ! ps -ea | grep -q "${kubectl_tunnel_pid}"; then
echo "WARNING: kubectl PID ${kubectl_tunnel_pid} not running, tunnel might not be up!" 1>&2
fi
}
# Tries to find a free port randomly from a given range
random_free_port() {
local max_attempts=5
local low_range=8432
local range=200
for i in $(seq "${max_attempts}"); do
# Pick a random port between 8432-8632
local port="$((${low_range} + ${RANDOM} % ${range}))"
# Check if the port is not open
if ! nc -z -w 0 localhost 8433; then
echo "Found free port ${port}" 1>&2
echo "${port}"
return
fi
done
echo "Unable to find a free port after 5 attempts" 1>&2
return 1
}
start_socat_pod() {
local k8s_context="$1"
local endpoint="$2"
local port="$3"
local pod_name="$4"
if ! kubectl --context "${k8s_context}" get ns "${TUNNEL_NAMESPACE}" > /dev/null 2>&1; then
kubectl --context "${k8s_context}" create ns "${TUNNEL_NAMESPACE}"
fi
if kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" get pod "${pod_name}" > /dev/null 2>&1; then
echo "Pod ${TUNNEL_NAMESPACE}/${pod_name} already exists. Tunnel pod already running?" 1>&2
return 0
fi
kubectl --context "${k8s_context}" run "${pod_name}" \
--namespace "${TUNNEL_NAMESPACE}" \
--image=alpine/socat \
-it --tty \
--labels=type=rds-tunnel \
--expose=false \
--attach=false \
--port=${port} \
--restart=Never \
--pod-running-timeout=5m \
--command -- sh -c \
"socat -d -d -d tcp-listen:${port},fork,reuseaddr tcp-connect:${endpoint}:${port} 2>&1 |
(
while read -t ${TUNNEL_TTL} l; do true; done;
echo 'No activity detected. Exiting'; killall socat;
)" > /dev/null
echo "Waiting for pod to start..." 1>&2
START_EPOCH="$(date +%s)"
while true; do
if kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" wait --for=condition=Ready "pod/${pod_name}" --timeout=20s; then
kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" get pod "${pod_name}"
break
fi
if [ "$((START_EPOCH + TUNNEL_WAIT_TTL))" -lt "$(date +%s)" ]; then
echo "Timeout waiting for pod" 1>&2
return 1
fi
kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" get pod "${pod_name}" --no-headers=true
done
}
tunnel_started_tip() {
local k8s_context="$1"
local endpoint="$2"
local port="$3"
local pod_name="$4"
cat 1>&2 <<EOF
Pod ${pod_name} started. You can start a tunnel now with:
kubectl port-forward \\
--context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" \\
--address ${TUNNEL_LISTEN_ADDR} \\
pod/${pod_name} ${port}:${port}
You can then connect using:
export PGHOST=localhost
export PGPORT="${port}"
read PGUSER
read PGPASSWORD
psql
EOF
}
run_kubectl_tunnel() {
local k8s_context="$1"
local remote_port="$2"
local local_port="$3"
local pod_name="$4"
echo "starting local kubectl tunnel on ${local_port}"
kubectl --context "${k8s_context}" -n "${TUNNEL_NAMESPACE}" \
port-forward \
--address "${TUNNEL_LISTEN_ADDR}" \
"pod/${pod_name}" "${local_port}:${remote_port}" \
> "${TMPDIR}/kubectl-tunnel.stdout" &
KUBECTL_TUNNEL_PID="$!"
wait_kubectl_tunnel "${TMPDIR}/kubectl-tunnel.stdout" "${KUBECTL_TUNNEL_PID}"
export PGHOST="${TUNNEL_HOST}"
export PGPORT="${local_port}"
export TF_VAR_override_db_host="${TUNNEL_HOST}"
export TF_VAR_override_db_port="${local_port}"
cat <<EOF
Kubectl tunnel started. Setting environment variables to use with clients/terraform
export PGHOST="${PGHOST}"
export PGPORT="${PGPORT}"
export TF_VAR_override_db_host="${TF_VAR_override_db_host}"
export TF_VAR_override_db_port="${TF_VAR_override_db_port}"
EOF
}
delete_tunnel_pods() {
local k8s_context="$1"
local pod_name="$2"
echo "Deleting tunnel pod ${pod_name}..." 1>&2
kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" \
delete pods --wait=0 --ignore-not-found=true "${pod_name}"
}
clean_terminated_pods() {
local k8s_context="$1"
pods_to_delete="$(
kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" get pods -l "${TUNNEL_LABEL}" -o json | \
jq -r '.items[]|select(.status.containerStatuses[].state.terminated)|.metadata.name'
)"
if [ "${pods_to_delete}" ]; then
echo "Found ${pods_to_delete//$'\n'/,} orphaned pods. Deleting them" 1>&2
for p in ${pods_to_delete}; do
kubectl --context "${k8s_context}" --namespace "${TUNNEL_NAMESPACE}" delete pod --wait=false "$p"
done
fi
}
load_config() {
local rds_name="$1"
local rw_or_ro="$2"
# Load the config
local rds_config_file="${PROJECT_ROOT_DIR}/assets/rds-config.${rds_name}.sh"
if [ ! -f "${rds_config_file}" ]; then
echo "ERROR: Cannot find ${rds_config_file} with the static config of RDS" 1>&2
return 1
fi
eval "$(
cat ${rds_config_file} | \
grep \
-e TUNNEL_CONTEXT= \
-e PGHOST_RW= \
-e PGHOST_RO= \
-e PGPORT=
)"
if [ "${rw_or_ro}" == "ro" ]; then
export ENDPOINT="${PGHOST_RO}"
else
export ENDPOINT="${PGHOST_RW}"
fi
export PORT="${PGPORT}"
}
usage() {
cat <<EOF
Starts a pod to used as TCP tunnel to the remote RDS instance in the
corresponding k8s cluster.
Loads the DB config from ./assets/*
Usage:
${SCRIPT_NAME} [options] [start|stop] <dbname> <rw|ro>
${SCRIPT_NAME} [options] run <dbname> <rw|ro> <cmd>
Actions
- start: start the remote pod in the cluster
- stop: deletes the remote pod
- run: starts the tunnel, runs the given command
Options:
- --port <n> Use given port locally rather than a random one
Examples:
${SCRIPT_NAME} start my-cool-db rw
${SCRIPT_NAME} stop my-cool-db rw
${SCRIPT_NAME} run my-cool-db rw terraform plan
Env Vars:
PRINT_RDS_CREDS Print RDS connection info
TUNNEL_PORT Use given port locally rather than a random one
Existing RDS databases:
EOF
# Print the existing configs
ls ${PROJECT_ROOT_DIR}/assets/rds-config.* | sed "s|.*/rds-config.\(.*\)\.sh| ${SCRIPT_NAME} run \1 rw|"
echo
exit 0
}
trap_handler() {
if [ -d "${TMPDIR:-}" ]; then
rm -rf "${TMPDIR:-/tmp/foo}"
fi
# kill kubectl tunnel if running
if [ "${KUBECTL_TUNNEL_PID:-}" ]; then
kill "${KUBECTL_TUNNEL_PID}"
fi
}
##############################################################
# Parse arguments
while true; do
case "$1" in
--help|-h)
usage
exit 0
;;
-p|--port)
TUNNEL_PORT="${2}"
shift
shift
;;
-*)
echo "ERROR: Unknown option: $1" 1>&2
usage
exit 1
;;
*)
break
;;
esac
done
if [ $# -lt 3 ]; then
usage
fi
action="${1}"; shift
dbname="${1}"; shift
mode="${1}"; shift
# Unique pod name
TUNNEL_POD_NAME="rds-tunnel-${dbname}-${mode}-${USER}"
TUNNEL_POD_NAME="${TUNNEL_POD_NAME//_/-}"
# Initial checks
# [ -z "${SKIP_CHECK_AWS_CREDS:-}" ] && check_aws_creds
export -n TMPDIR # avoid bugs caused by a exported TMPDIR
TMPDIR="$(mktemp -d)"
trap 'trap_handler' EXIT
load_config "${dbname}" "${mode}"
case "${action}" in
start)
clean_terminated_pods "${TUNNEL_CONTEXT}"
start_socat_pod "${TUNNEL_CONTEXT}" "${ENDPOINT}" "${PORT}" "${TUNNEL_POD_NAME}"
tunnel_started_tip "${TUNNEL_CONTEXT}" "${ENDPOINT}" "${PORT}" "${TUNNEL_POD_NAME}"
;;
stop)
clean_terminated_pods "${TUNNEL_CONTEXT}"
delete_tunnel_pods "${TUNNEL_CONTEXT}" "${TUNNEL_POD_NAME}"
;;
run)
# Get a random free port
TUNNEL_PORT="${TUNNEL_PORT:-$(random_free_port)}"
clean_terminated_pods "${TUNNEL_CONTEXT}"
start_socat_pod "${TUNNEL_CONTEXT}" "${ENDPOINT}" "${PORT}" "${TUNNEL_POD_NAME}"
run_kubectl_tunnel "${TUNNEL_CONTEXT}" "${PORT}" "${TUNNEL_PORT}" "${TUNNEL_POD_NAME}"
if [ $# -ge 1 ]; then
"$@"
else
echo "Tip: Run '$SCRIPT_DIR/rds_creds.sh ${dbname} ${mode}' to get new RDS IAM creds"
echo "Sleeping... Ctrl+C to exit" 1>&2
sleep 14400
fi
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment