Cloud Run can’t directly connect to Cloud SQL without exposing credentials because Cloud Run instances are ephemeral and don’t have a persistent identity or secrets store that can be reliably accessed by the application code at runtime.
Here’s how to make that connection securely, using the Cloud SQL Auth Proxy, which acts as a secure bridge.
The Problem: Securely Connecting Cloud Run to Cloud SQL
You’ve got a web application running on Cloud Run and a database on Cloud SQL. You need them to talk to each other. The obvious way is to put the database username and password directly into your Cloud Run service’s environment variables. This is a bad idea. Cloud Run instances can be scaled to zero, meaning they disappear. If they disappear, your credentials disappear too, or worse, if someone gains access to your Cloud Run service configuration, they get your database credentials. Also, directly exposing database credentials in environment variables is a security anti-pattern.
The Cloud SQL Auth Proxy solves this by providing a secure, authenticated, and encrypted tunnel to your Cloud SQL instance without needing to manage database credentials in your application.
How it Works: The Cloud SQL Auth Proxy
The Cloud SQL Auth Proxy is a small, self-contained binary that you run alongside your application in the same Cloud Run service. It handles the authentication and encryption for you.
Here’s the flow:
- Cloud Run Instance Starts: When your Cloud Run service scales up, it starts your application container and the Cloud SQL Auth Proxy container (or the proxy binary within your app container).
- Proxy Authenticates: The Auth Proxy uses the service account associated with your Cloud Run service to authenticate with Google Cloud. This service account needs the
Cloud SQL Clientrole (roles/cloudsql.client). - Proxy Connects to Cloud SQL: Once authenticated, the proxy establishes a secure, encrypted connection to your Cloud SQL instance. It uses IAM for authentication, not database passwords.
- Application Connects to Proxy: Your application container then connects to the Auth Proxy, which is listening on a local port (e.g.,
127.0.0.1:5432for PostgreSQL,127.0.0.1:3306for MySQL). - Proxy Forwards Traffic: The Auth Proxy forwards the database traffic securely to your Cloud SQL instance.
This means your application never sees the database password or username; it only needs to know how to connect to localhost on a specific port.
Setting it Up: Two Main Approaches
There are two common ways to run the Cloud SQL Auth Proxy with Cloud Run:
- As a Sidecar Container: This is the recommended and cleanest approach. You define two containers in your Cloud Run service: one for your application and one for the Auth Proxy.
- As a Binary within Your Application Container: You can include the Auth Proxy binary directly in your application’s Docker image and run it as a background process. This is slightly more complex to manage.
Let’s focus on the sidecar approach.
Approach 1: Sidecar Container (Recommended)
1. Grant IAM Permissions:
Ensure your Cloud Run service account has the Cloud SQL Client role.
- Go to IAM & Admin -> IAM.
- Find your Cloud Run service account (often
PROJECT_NUMBER-compute@developer.gserviceaccount.comor a custom one you’ve assigned). - Click the pencil icon to edit its permissions.
- Click Add Another Role.
- Select Cloud SQL Client.
- Click Save.
2. Configure Your Cloud Run Service:
You’ll need to deploy your Cloud Run service with a Dockerfile that defines both your application and the Auth Proxy as separate containers.
Here’s a sample Dockerfile for a Node.js application using PostgreSQL:
# ---- Base Image ----
# Use a base image that has Node.js installed.
FROM node:18-slim AS builder
# Set the working directory.
WORKDIR /usr/src/app
# Copy package.json and package-lock.json.
COPY package*.json ./
# Install app dependencies.
RUN npm install
# Copy the rest of your application code.
COPY . .
# ---- Application Image ----
FROM node:18-slim
# Set the working directory.
WORKDIR /usr/src/app
# Copy application code from the builder stage.
COPY --from=builder /usr/src/app .
# Expose the port your application listens on.
EXPOSE 8080
# ---- Cloud SQL Auth Proxy ----
# Use the official Google Cloud SDK image for the proxy
FROM google/cloud-sdk:latest AS proxy
# Install the Cloud SQL Auth proxy binary
RUN apt-get update && apt-get install -y --no-install-recommends libsqlite3-dev && \
gcloud components install sql-proxy && \
rm -rf /var/lib/apt/lists/*
# ---- Final Image ----
# Multi-stage build: combine app and proxy
FROM node:18-slim
WORKDIR /usr/src/app
# Copy application code
COPY --from=builder /usr/src/app .
# Copy the Cloud SQL Auth proxy binary from the proxy stage
COPY --from=proxy /google/cloud-sdk/bin/cloud_sql_proxy /usr/local/bin/cloud_sql_proxy
# Expose the application port
EXPOSE 8080
# Set the entrypoint to run both the proxy and the application
# Replace YOUR_APP_PORT with the port your app listens on (e.g., 8080)
# Replace YOUR_APP_CMD with the command to start your app (e.g., "npm start")
# Replace YOUR_CLOUD_SQL_CONNECTION_NAME with your Cloud SQL instance connection name
# Replace YOUR_DB_PORT with your database port (e.g., 5432 for PostgreSQL, 3306 for MySQL)
ENTRYPOINT ["/bin/sh", "-c"]
CMD="\
/usr/local/bin/cloud_sql_proxy \
--port=5432 \
--address=127.0.0.1 \
--enable_iam_login \
--projects=YOUR_PROJECT_ID \
--auto_iam_authn \
& \
npm start \
"
Explanation of the CMD:
/usr/local/bin/cloud_sql_proxy: This is the command to start the proxy.--port=5432: The port the proxy will listen on locally for your application to connect to. Use3306for MySQL.--address=127.0.0.1: The IP address the proxy will bind to.127.0.0.1means it will only be accessible from within the same container (or other containers in the same Cloud Run instance).--enable_iam_login: This is crucial. It tells the proxy to use IAM database authentication instead of requiring a database password. Your application will need to be configured to use this IAM login mechanism. For PostgreSQL, this means the user created in Cloud SQL must match the service account name. For MySQL, this is handled implicitly by the proxy.--projects=YOUR_PROJECT_ID: Specifies the Google Cloud project ID where your Cloud SQL instance resides.--auto_iam_authn: This flag tells the proxy to automatically attempt IAM authentication for incoming connections.&: This runs the proxy in the background, allowing the next command to execute.npm start: This is your application’s command to start.
Important Considerations for IAM Login:
- PostgreSQL: You need to create a database user in your Cloud SQL instance that matches the name of your Cloud Run service account (e.g.,
service-account-name@your-project.iam.gserviceaccount.com). Then, when your application connects, it should specify this user. Your connection string might look like:postgres://service-account-name@your-project.iam.gserviceaccount.com@127.0.0.1:5432/your-db-name. - MySQL: The proxy handles IAM authentication more transparently. You don’t typically need to create a user matching the service account name.
3. Update Your Application’s Database Connection:
Modify your application’s database connection logic to point to 127.0.0.1 (localhost) on the port you specified for the proxy (e.g., 5432 for PostgreSQL, 3306 for MySQL).
Example (Node.js with pg for PostgreSQL):
const { Pool } = require('pg');
const pool = new Pool({
user: process.env.DB_USER || 'service-account-name@your-project.iam.gserviceaccount.com', // Replace with your service account user
host: '127.0.0.1', // Connect to the proxy on localhost
database: process.env.DB_NAME || 'your-database-name',
password: process.env.DB_PASSWORD, // Leave this undefined or null if using IAM login
port: process.env.DB_PORT || 5432,
});
// ... rest of your app
Example (Node.js with mysql2 for MySQL):
const mysql = require('mysql2/promise');
async function getConnection() {
const connection = await mysql.createConnection({
user: 'root', // Or any user you've set up in MySQL that allows IAM auth
host: '127.0.0.1', // Connect to the proxy on localhost
database: process.env.DB_NAME || 'your-database-name',
password: process.env.DB_PASSWORD, // Leave this undefined or null if using IAM login
port: process.env.DB_PORT || 3306,
});
return connection;
}
// ... rest of your app
4. Deploy to Cloud Run:
Build your Docker image and deploy it to Cloud Run. Make sure to:
- Assign the correct service account to your Cloud Run service.
- Set any necessary environment variables for your application (e.g.,
DB_NAME).
Approach 2: Binary within Application Container
This involves downloading the Cloud SQL Auth Proxy binary and running it as a background process within your application’s main container.
1. Download the Proxy:
You can download the proxy binary for Linux AMD64 from the official Google Cloud SDK.
2. Integrate into your Dockerfile:
# Base image for your application (e.g., Node.js)
FROM node:18-slim
WORKDIR /usr/src/app
# Install necessary packages for the proxy and your app
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
libsqlite3-dev \
&& rm -rf /var/lib/apt/lists/*
# Download and install the Cloud SQL Auth Proxy
RUN wget https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.8.2/cloud-sql-proxy.linux.amd64 -O /usr/local/bin/cloud_sql_proxy \
&& chmod +x /usr/local/bin/cloud_sql_proxy
# Copy your application code
COPY package*.json ./
RUN npm install
COPY . .
# Expose application port
EXPOSE 8080
# Start the proxy and your application
# Replace YOUR_CLOUD_SQL_CONNECTION_NAME, YOUR_DB_PORT, YOUR_PROJECT_ID, and YOUR_APP_CMD
ENTRYPOINT ["/bin/sh", "-c"]
CMD="\
/usr/local/bin/cloud_sql_proxy \
--port=5432 \
--address=127.0.0.1 \
--enable_iam_login \
--projects=YOUR_PROJECT_ID \
--auto_iam_authn \
& \
npm start \
"
This approach is less modular and makes your application’s Dockerfile heavier. The sidecar pattern is generally preferred for better separation of concerns.
The Counterintuitive Bit: IAM Login is Not Just for "Admin" Users
When you use --enable_iam_login and --auto_iam_authn with Cloud SQL, it’s easy to think this is only for super-admin users. However, this mechanism is designed to work with any database user you create in Cloud SQL that is explicitly configured to allow IAM authentication. For PostgreSQL, this means creating a user with a name that matches your service account. For MySQL, the proxy handles mapping the authenticated service account to a user allowed to connect. This allows you to manage database access granularly via IAM roles, rather than managing separate database passwords for each service.
Next Steps
After successfully connecting your Cloud Run service to Cloud SQL using the Auth Proxy, the next common challenge is managing database migrations efficiently for your ephemeral Cloud Run services.