summaryrefslogtreecommitdiffstats
path: root/content/posts/opening-multiple-db-tunnels-with-aws-ssm.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/opening-multiple-db-tunnels-with-aws-ssm.md')
-rw-r--r--content/posts/opening-multiple-db-tunnels-with-aws-ssm.md67
1 files changed, 67 insertions, 0 deletions
diff --git a/content/posts/opening-multiple-db-tunnels-with-aws-ssm.md b/content/posts/opening-multiple-db-tunnels-with-aws-ssm.md
new file mode 100644
index 0000000..14d5508
--- /dev/null
+++ b/content/posts/opening-multiple-db-tunnels-with-aws-ssm.md
@@ -0,0 +1,67 @@
+---
+title: Opening multiple DB tunnels with AWS SSM
+date: 2024-06-26
+extra:
+ kind: note
+---
+
+To open a tunneled connection to an AWS managed database, such as RDS or DocumentDB, the commonly recommended way is to use a bastion host and `aws ssm start-session`. The bastion host is an EC2 instance that is in the same VPC as your database. The AWS CLI command allows you to connect to SSM-enabled EC2 instances from your development machine using IAM authorization, without having to manage SSH keys.
+
+The script below connects to the specified PostgreSQL RDS and DocumentDB instances using a bastion host. Both databases will be accessible on a `localhost` port. Modify as necessary.
+
+```bash
+#!/bin/bash
+
+# Configure to match your environment
+BASTION_NAME="<YOUR_BASTION_INSTANCE_NAME>"
+DOCDB_CLUSTER_NAME="<YOUR_DOCDB_CLUSTER_NAME>"
+PG_CLUSTER_NAME="<YOUR_RDS_CLUSTER_NAME>"
+DOCDB_PORT="27017"
+PG_PORT="5432"
+
+# Fail on errors, do not allow use of unset variables
+set -eu
+
+# Colors for nicer output
+BB="\\033[34m"
+RST="\\033[0m"
+
+# Fetch the endpoints URIs and bastion instance ID
+DOCDB_ENDPOINT=$(aws docdb describe-db-clusters --db-cluster-identifier "${DOCDB_CLUSTER_NAME}" --query "DBClusters[0].Endpoint" --output text)
+PG_ENDPOINT=$(aws rds describe-db-clusters --db-cluster-identifier "${PG_CLUSTER_NAME}" --query "DBClusters[0].Endpoint" --output text)
+BASTION_INSTANCE=$(aws ec2 describe-instances --filter "Name=tag:Name,Values=${BASTION_NAME}" --query "Reservations[].Instances[?State.Name == 'running'].InstanceId[]" --output text)
+
+echo "DocumentDB endpoint: ${DOCDB_ENDPOINT}"
+echo "PostgreSQL endpoint: ${PG_ENDPOINT}"
+echo "Bastion host instance ID: ${BASTION_INSTANCE}"
+echo ""
+
+echo -e "${BB}Starting SSM sessions with DocumentDB and PostgreSQL port forwarding in localhost in this terminal...${RST}"
+
+# DocumentDB port forwarding
+aws ssm start-session \
+ --target "${BASTION_INSTANCE}" \
+ --document-name AWS-StartPortForwardingSessionToRemoteHost \
+ --parameters '{"portNumber":["'${DOCDB_PORT}'"],"localPortNumber":["'${DOCDB_PORT}'"],"host":["'"${DOCDB_ENDPOINT}"'"]}' &
+PID1=$!
+
+# PostgreSQL port forwarding
+aws ssm start-session \
+ --target "${BASTION_INSTANCE}" \
+ --document-name AWS-StartPortForwardingSessionToRemoteHost \
+ --parameters '{"portNumber":["'${PG_PORT}'"],"localPortNumber":["'${PG_PORT}'"],"host":["'"${PG_ENDPOINT}"'"]}' &
+PID2=$!
+
+cleanup() {
+ echo "Caught CTRL-C, stopping both tunnels..."
+ kill $PID1 $PID2
+ exit
+}
+
+# Catch the interrupt signal (CTRL-C)
+trap cleanup INT
+
+# Wait for both processes to exit
+wait $PID1
+wait $PID2
+```