KURTIS VAN GENT: Hi, everyone.
Welcome to Connecting to Cloud SQL from Kubernetes.
My name is Kurtis Van Gent.
I'm a Developer Programs Engineer.
I work on Google Cloud Platform to make the developer
experience better for developers like you.
Today, we're going to be talking about how to connect
to Cloud SQL from Kubernetes.
We're going to have three main points.
The first is we're going to cover
how to connect to Cloud SQL in general,
then we're going to narrow down and talk about connecting
from Kubernetes to Cloud SQL.
And then finally, we're going to narrow down even more
and do a hands-on example of the best practices
for connecting from Kubernetes.
Before we begin, there's some basics
that you should understand before we start.
First, it's expected that you know and understand Cloud SQL
and how a managed database works,
what some of the benefits are, and when you should try and use
one.
Second, it's understood that you should understand
the basics of a container, how container images work,
and what some of the benefits for containerization are.
And finally, we hope that you understand
some of the basics, at least, of Kubernetes
and you understand some concepts such as pod and deployments.
First, let's talk about connecting to Cloud SQL.
When you're connecting, there's two different things
you need to think about.
First, the path-- how am I going to reach the instance?
And the second is authorization--
how do I get permission to talk to the instance?
When you're selecting a path, you have two different options.
The first option is public IP.
Public IP is a static IPv4 address
that's accessible from the public internet.
As long as you have access to the internet,
you can potentially connect to your Cloud SQL instance.
By default, authorization is required,
since we don't want anyone connecting
to your application that has access to the internet.
Some of the benefits of public IP
is that you can connect from outside GCP,
while one of the drawbacks is you may have higher
latency, since you're connecting over the internet instead
of using an internal network.
The second option you have is to connect using private IP.
Private IP is an IPv4 address that's
peered into your project via a Virtual Private Cloud or VPC,
for short.
By default, authorization is not required,
but you do have to be on the VPC to access your Cloud SQL
instance.
One of the benefits of private IP
is you usually have lower latency.
This is because you're not connecting over the internet
and instead connecting directly through an internal network.
Once you've decided how to connect,
the next step is authorization.
When it comes to authorization, there's
three different options you have to look at.
The first is the Cloud SQL Proxy.
The Cloud SQL Proxy is a binary that
provides IAM authentication.
It uses a service account to provide
authorization and strong encryption using
short-lived SSL certificates.
The second option you can use is authorized networks.
This is where you specify a list of IP addresses
that are authorized to connect.
For private IP, there is a similar feature
called VPC egress firewall rules that you can use instead.
The third option is self-managed SSL.
You can create SSL certificates for your instance that
can be distributed to your application that
encrypt your connections.
For MySQL and Postgres, this is a client
and server-side credential, while for SQL Server,
this is only a server-side credential.
It's important to remember that these are
options for authorization only.
You still have to authenticate with the database using
your username the password.
So to summarize, you have private IP
and you have public IP.
For public IP, you have to use either the Cloud SQL
Proxy or authorized networks.
We also recommend that if you are using authorized networks,
that you use self-managed SSL.
This encrypts your data and makes
sure that no one else can read it in transit unless they
have the certificates.
However, this is automatically done by the Cloud SQL Proxy,
so if you decide to use it, you won't
have to worry about managing your own SSL.
When it comes to public versus private,
use whichever one works best.
And for authorization, while we recommend the Cloud SQL Proxy,
it's perfectly OK to use authorized networks
and self-managed SSL as well.
Next, let's talk about Kubernetes to Cloud SQL.
There are three different ways that you're going to see people
recommending you to connect.
The first is you can connect directly using private IP.
The second is you can run the proxy as a service.
And finally, you can run the proxy as a sidecar.
This is our recommended solution over the first two.
Because private IP doesn't require any authorization,
it's possible to just connect directly.
You can just put in the private IP into your application
and connect with that directly to your Cloud SQL instance.
In order to access that private IP,
you have to be on a VPC-native Google Kubernetes Engine
cluster.
Now, this means that it has to be a GKE cluster.
If you're using a cluster off GCP,
you won't be able to connect.
Now, you may be thinking, if it's so easy to use private IP,
do I still want to use the proxy?
With the proxy, there's the downside of the initial setup
being a little bit of a hassle, but the upside
is you get strong IAM authentication and strong
encryption for all the data from your application.
For the proxy, the advantage is you
don't have to worry about the setup,
you can connect directly via IP, but it
requires a VPC-native cluster.
So if you're connecting from off-GKE,
you don't have that option.
And there's work authorization-- anyone on your cluster
could potentially connect to your database.
Why is IAM so important?
Like, why do we push the proxy so hard?
Well, the reason is is that you can
use a service account to represent
your entire application.
It gives you a one-to-one mapping of permissions
to applications, which makes it easy to manage.
If you decide that an application no longer has
a need to access the database, you
can simply remove the permission and it no longer can,
even if changes to the app are made.
Finally, it follows the principle of least privilege.
The app only has the minimum permissions that are needed,
which is a great security advantage.
When you're running the proxy as a service,
typically you do it as a separate deployment
from your application.
So you can see on the left here, we have our application pods
being deployed, and on the right,
we have our proxy pods being deployed.
And your application is going to connect directly to the proxy,
and then your proxy is going to route your connection
right to Cloud SQL.
One of the downsides to this is the traffic
between your application and proxy is not
encrypted by default. The proxy doesn't offer any encryption
on the client side, it only encrypts the traffic coming out
before it gets connected to Cloud SQL.
Another disadvantage is no authorization.
Anyone on your cluster can connect
to the proxy, which means anyone in your cluster
can connect to Cloud SQL.
This negates the advantage I was talking about before with Cloud
SQL IAM authentication.
Another disadvantage is there is a single point of failure.
If all of the applications are using a single deployment
of the proxy to run, if that deployment fails,
all of your applications are no longer able to connect.
If something goes wrong in the proxy
and it stops operating correctly,
all of your applications fail instead of just one instance.
Finally, another disadvantage is the application and proxy
aren't necessarily running in the same zone or region.
This adds additional latency because now your application
has to jump first to your proxy and then
to the Cloud SQL instance, which could
be in an entirely different region or zone, as well.
By keeping the application and proxy together,
you can eliminate this, meaning you only
have to worry about the latency to the Cloud SQL instance.
This is why we recommend running the proxy as a sidecar.
It's called a sidecar pattern because if you
think of a motorcycle with a sidecar,
it's attached to the side.
You still have your main application here in the middle
and then you have the Cloud SQL Proxy attached
to the side right here.
The application can connect to the Cloud SQL Proxy
directly, which then connects to Cloud SQL.
Because this is a pod, it's an atomic unit,
meaning the application and the Cloud SQL Proxy
are always together.
If the Cloud SQL Proxy fails, the application
has also failed.
If the application fails, the Cloud SQL Proxy
is still running in the other pods.
It's authorized because the Cloud SQL Proxy is inside
the same pod as the application.
Only the application can access it.
And you don't have to worry about other traffic accessing
a proxy that it's not supposed to.
It's also isolated.
If the application fails or the proxy fails,
you don't have to worry about the rest
of your application going down.
It's just that pod that fails.
And finally, it's encrypted.
The minute the data leaves your Cloud SQL Proxy,
it is encrypted and sent to your Cloud SQL instance
before it's unencrypted.
This means you don't have to worry about anybody potentially
listening in between your application and your proxy.
OK, so you're convinced.
You want to use the Cloud SQL Proxy in a sidecar, but how?
Let's talk about deploying the proxy as a sidecar.
Again, there's two different things you need to think about.
The first is you need to decide how to pass credentials
into the proxy.
Once you've decided that, you just
have to mount the proxy as a sidecar
onto an existing application.
When you're passing credentials, again, you
have a couple of choices to make.
The first is workload identity.
This is where you can map a Google Service Account, or GSA
for short, to a Kubernetes Service Account,
or KSA for short.
The advantage of this is you don't
have to worry about managing any secrets.
But it is a GKE-only feature.
This means you'll have to use a GKE cluster if you
want to take advantage of this.
If you're not using a GKE cluster
or if you're operating somewhere that
doesn't have workload identity, you can still
use a service account key file.
This is where you have service account credentials that
are stored in a JSON key file.
The downside is you have to worry
about keeping track of that JSON key file and rotating it,
but you are able to do this on a standard Kubernetes instance.
So option 1, workload identity for GKE.
If you look to the left over there,
you'll see the application of Cloud SQL Proxy.
What happens when you decide to use application default
credentials is the client library, including the Cloud
SQL Proxy, can reach out to the metadata server.
This is true for both the application and the proxy,
so you can use one service account
to represent both things.
Once the Cloud SQL Proxy makes that call,
it gets the token that it needs to authorize with the instance
and uses it to make any API calls necessary.
In order to set this up, the first thing you'll need to do
is create a Kubernetes Service Account.
This is a fairly simple deploy and can
be a config.yaml that's stored along with your application's
deployment.
Step two is you need to bind your Google Service
Account to the Kubernetes Service Account.
This is two steps.
It's one gcloud command that specifies
which Google Service Account you're using
and which Kubernetes Service Account.
And then it's a second step in kubectl
to connect to your Kubernetes Service Account.
Finally, once you've done the first two steps,
you need to add the Kubernetes Service
Account to your application.
All you need to do is add the service account name
that you specified in the first step
and then bound in the second step
to make sure that your application uses it
when it's deployed next.
GKE will automatically handle the metadata server for you,
as long as the option is enabled on your cluster.
The second option you have is the service account key file.
In this case, both the application and the proxy
are going to load the credentials from a file
and then use that credential to generate the tokens needed
to make any API calls.
Step one is you have to create a service account key.
So once you have your Google Service Account created,
you can use a quick gcloud command
to create a local key.json file.
Step two is you want to turn the key into a secret.
Using kubectl, you can create a generic secret
with whatever name you prefer, and you
can use a specific file name and load it from that local file.
In this case, we're using service_account.json,
and we're loading it from key.json,
which we created in step one.
Step 3 is we want to mount as a volume.
What this is going to do is put inside your pod's file system,
the file that you've created as a secret
and make it accessible for your application to access.
Once you've mounted it as a file,
both the application and the proxy
can read in and use it when it's creating API calls.
Now, after you've decided how you're
going to mount the credentials, you just
need to mount the proxy itself as a sidecar.
In this case, the proxy runs in its own container,
and it shares a pod with the main application.
This means it's really easy to take your existing
configuration and add the Cloud SQL Proxy to it.
You can see above we have a pretty standard containers
deployment here, where you have a list of containers
that you're using in your Cloud SQL Proxy.
On this top half here, we have things like the environment
variables you're using to configure your database-- see,
this one is DB_USER, which is created from a secret.
You also have the name of the application
in the other configuration, such as image or whatever
you've deciding to use.
On top of that, you can specify the name of the Cloud SQL
Proxy, so you add as a separate entry in your list here,
image cloudsql-docker/gce-proxy.
This is an image that we maintain for you
so that you can use it.
Second, you just need to add the command you want the Cloud SQL
Proxy to run.
So here we just have Cloud SQL Proxy.
If you're using private IP, you want
to enable the IP addresses types flag
instead of equal to private, and if you're using a service
account, you want to make sure that you add the credential
file flag, as well, to tell it where exactly that service
account is located.
Finally, you'll use the instances flag
to pass in the name of the instance
and the TCP port you want it to listen to.
You can use whatever TCP port you want,
or you can just default to the standard for MySQL, Postgres,
or SQL Server.
If you're interested in learning more,
here's some additional resources you can take a look at.
The first is the Cloud SQL Proxy, which is open-source,
written in Go, available on GitHub.
The second is the Cloud SQL JDBC socket factory.
This can be used by Java users to connect directly
to your Cloud SQL instance without using
the proxy in a similar manner.
If you're interested in finding more,
please take a look at the repos.
And if you encounter any issues, please open an issue on GitHub
and let us know.
Thanks for watching, and have a great day.