TL;DR: here’s a handy bash script which can connect to a private Cloud SQL instance(MySQL in this case) via a bastion host.
Prerequisites:
- Google Cloud SQL instance with mTLS certs provisioned
- Google Cloud SDK installed(the gcloud command)
- a bash shell(better be V5.0+)
- OpenSSH and MySQL CLI installed
Google Cloud SQL is an RDB as a service very similar to AWS RDS. To secure the connections to the databases in Cloud SQL, I can either use public IP + mTLS + IP whitelists or only use private IP with optional mTLS encryption at transit.
I’m not saying which one is more secure but I personally prefer to use private IP and connect through private networks. Below is a handy bash script I use to connect to a Cloud SQL instance via a bastion host.
#!/bin/bash
set -eu
if [[ $# == 0 ]]; then
echo "Usage: $0 <cloudsql instance name> -u <mysql user> -p ... [optional mysql cli switches]"
exit 1
fi
MYSQL_PORT=${MYSQL_PORT:-3306}
INSTANCE=$1
shift
# clean up regardless how the script finishes
trap "rm ca.pem client-cert.pem client-key.pem; ssh -S bastion-socket -O exit my.bastion.dns" EXIT
PROJECT=${PROJECT:-my-gcp-project-id}
echo Setting default GCP project to $PROJECT...
gcloud config set project $PROJECT
echo Retrieve Cloud SQL instance IP...
CLOUDSQL_HOST=$(gcloud sql instances describe $INSTANCE --format='value(ipAddresses[0].ipAddress)')
echo Extracting server CA certificate via cloud sql API...
gcloud beta sql ssl server-ca-certs list \
--format="value(cert)" \
--instance=$INSTANCE > ca.pem
# assuming the client-cert has a CN of ${INSTANCE}-client
echo Extracting client certificate via cloud sql API...
gcloud sql ssl client-certs describe ${INSTANCE}-client \
--instance=$INSTANCE \
--format="value(cert)" > client-cert.pem
# assuing the client private key is in a GSM secret
echo Extracting client private key from GSM...
gcloud secrets versions access latest \
--secret ${INSTANCE}-client-key-pem > client-key.pem
echo SSH Tunneling...
ssh -fN -L $MYSQL_PORT:$CLOUDSQL_HOST:3306 \ # standard local port forwarding running in background
-M -S bastion-socket \ # use a master socket to clean up later
-o UserKnownHostsFile=/dev/null \ # ignore host key
-o StrictHostKeyChecking=no \
my.bastion.dns
echo Running mysql client...
mysql -h 127.0.0.1 -P $MYSQL_PORT \ # connect to the forwarded port
--ssl-ca=ca.pem \
--ssl-cert=client-cert.pem \
--ssl-key=client-key.pem $@ # pass along arguments🙂
Reference:
