How to Connect from Cloud Functions to the Private IP Address of Cloud SQL in Google Cloud

Posted in: Cloud, DevOps, Google Cloud Platform, Site Reliability Engineering, Technical Track

Cloud functions allow you to run single-purpose functions without having to manage instances in Google Cloud. Cloud SQL is Google Cloud’s managed SQL service. For better security, it’s best practice to disable public IP in Cloud SQL. In terraform, the code to create Cloud SQL instance looks as follows:

resource "google_sql_database_instance" "pythian_test_instance" {
  provider = "google-beta"
  name = "pythian-test-instance"
  region = "europe-west1"
  database_version = "MYSQL_5_7"
  settings {
    tier = "db-g1-small"
    disk_size = "10"
    disk_autoresize = "true"
    ip_configuration {
      # Set false to disable the external IP address on the instance.
      ipv4_enabled = "false"
      private_network = "${module.vpc_network.network_self_link}"
      require_ssl = "false"
    }
  }
}

As stated in the Google Cloud documentation, connecting directly to Cloud SQL from cloud functions requires a public IP address in Cloud SQL. To connect to a private IP address, you need Serverless VPC.

“The instructions in this post require your Cloud SQL instance to have a public IP address. If you want to use a private IP address, see “Configuring Serverless VPC Access” and connect directly using the private IP address.”

What is Serverless VPC?

Serverless VPC allows the App Engine standard environment and Cloud Functions to connect directly to the VPC network. This means that it allows both of the services to connect to Cloud SQL with a private IP address.

For enabling Serverless VPC in a VPC, you must create a Serverless VPC connector. The connector is attached to the VPC network and region.

In terraform, the VPC connector code looks as follows:

resource "google_vpc_access_connector" "serverless_vpc_connector" {
  provider = "google-beta"
  name = "new-vpc-connector"
  region = "europe-west1"
  ip_cidr_range = "172.29.167.16/28"
  network = "${module.vpc_network.network_name}"
  project = "${data.google_project.project.id}"
}

The name should not be more than 25 characters. The ip_cidr_range should be in the /28 range and unused in the VPC.

This creates a connector with the following naming convention:

  • “projects/project-name/locations/europe-west1/connectors/new-vpc-connector”

Make sure that there are no firewall rules that block the connection from the /28 range to the Cloud SQL range.

Testing

To test this, create the following files with proper credentials and ip address. This cloud function code connects to MySQL database and lists all tables.

$ cat main.py
import pymysql
from sqlalchemy import create_engine

def sql_connect(request):
  engine = create_engine('mysql+pymysql://Username:Password@10.20.1.3/mysql',echo=True)
  tab = engine.execute('show tables;')
  return str([t[0] for t in tab])

$ cat requirements.txt
pymysql
sqlalchemy

The following command creates a cloud function called “sql_connect,” which is triggered by http. The cloud functions service account must have the correct permissions to access Cloud SQL (“Cloud SQL Client” is the preferred role).

# gcloud beta functions deploy sql_connect --runtime python37 --project <project name> --region <region> --vpc-connector <connector name> --trigger-http --service-account      <service account name>

When you deploy the function, you can test it in Web UI, or as shown below:

$ gcloud functions call sql_connect --project --region
executionId: sph56jcgvasf
result: "['columns_priv', 'db', 'engine_cost', 'event', 'func', 'general_log', 'gtid_executed',\
\ 'heartbeat', 'help_category', 'help_keyword', 'help_relation', 'help_topic', 'innodb_index_stats',\
\ 'innodb_table_stats', 'ndb_binlog_index', 'plugin', 'proc', 'procs_priv', 'proxies_priv',\
\ 'server_cost', 'servers', 'slave_master_info', 'slave_relay_log_info', 'slave_worker_info',\
\ 'slow_log', 'system_user', 'tables_priv', 'time_zone', 'time_zone_leap_second',\
\ 'time_zone_name', 'time_zone_transition', 'time_zone_transition_type', 'user']"

So, Serverless VPC Access solves a major security concern. Serverless VPC Access also supports connections to VPC networks connected through Cloud VPN and VPC Network Peering. This allows a secure way to connect to your on-premise environment from a GCP serverless environment.

email

Author

Want to talk with an expert? Schedule a call with our team to get the conversation started.

About the Author

Devops Engineer
Minto Joseph is an expert in opensource technologies with a deep understanding of Linux. This allows him to troubleshoot issues from kernel to the application layer. He also has extensive experience in debugging Linux performance issues. Minto uses his skills to architect, implement and debug enterprise environments.

5 Comments. Leave new

Thanks for this article, I have done the same setup to connect to a service with a private IP address within a VPC from my function but it seems to be not working. I have a service that runs in a compute instance and can access with private IP address like this(https://172.31.93.233/proxy.php).
I want to make an https request from function to access this service so I created a connector(with IP range: 172.31.0.0/28) to VPC which has IP range:172.30.0.0/16 and Ingress settings( Allow all traffic) and Egress settings( Route all traffic through the VPC connector). BUT somehow my function still failed to complete the request and stated this in a log: Function execution took 60002 ms, finished with status: ‘timeout’
Any idea about it?

Reply

> Egress settings( Route all traffic through the VPC connector).

There is no need to do that.

Just make sure that, when you are specifying vpc connector while deploying cloud functions..

# gcloud beta functions deploy sql_connect –runtime python37 –project –region –vpc-connector –trigger-http –service-account

Reply

I have almost the same setup which you mentioned here and written in the documentation. My function can access the HTTP service running on an instance under the same VPC through a private IP address using a serverless connector BUT when I try to access a service which I running on-premises and it is connected with a VPN with the same VPC here call is failing. A strange thing is that I can access this service through the instance which is under the same VPC and connected with a VPN.

I am trying to resolve this for many days but still not find any clue. Any idea about it?

Reply

If you are able to connect from instance to the onprem service, try creating an allow egress firewall rule to allow the cloud function service account to access the destination ip range.

Also make sure that your onprem environment is not blocking the serverless vpc range.

Reply

From Google Doc:
Note: Some resources, such as Cloud SQL and Cloud Memorystore instances, require connections to come from the same region as the resource.

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *