...
1# Using the Cloud SQL proxy on Kubernetes
2
3The Cloud SQL proxy is the recommended way to connect to Cloud SQL, even when
4using private IP. This is because the proxy provides strong encryption and
5authentication using IAM, which help keep your database secure.
6
7## Configure your application with Secrets
8
9In Kubernetes, [Secrets][ksa-secret] are a secure way to pass configuration
10details to your application. Each Secret object can contain multiple key/value
11pairs that can be pass to your application in multiple ways. When connecting to
12a database, you can create a Secret with details such as your database name,
13user, and password which can be injected into your application as env vars.
14
151. Create a secret with information needed to access your database:
16 ```shell
17 kubectl create secret generic <YOUR-DB-SECRET> \
18 --from-literal=username=<YOUR-DATABASE-USER> \
19 --from-literal=password=<YOUR-DATABASE-PASSWORD> \
20 --from-literal=database=<YOUR-DATABASE-NAME>
21 ```
222. Next, configure your application's container to mount the secrets as env
23 vars:
24 > [proxy_with_workload_identity.yaml](proxy_with_workload_identity.yaml#L21-L36)
25 ```yaml
26 env:
27 - name: DB_USER
28 valueFrom:
29 secretKeyRef:
30 name: <YOUR-DB-SECRET>
31 key: username
32 - name: DB_PASS
33 valueFrom:
34 secretKeyRef:
35 name: <YOUR-DB-SECRET>
36 key: password
37 - name: DB_NAME
38 valueFrom:
39 secretKeyRef:
40 name: <YOUR-DB-SECRET>
41 key: database
42 ```
433. Finally, configure your application to use these values. In the example
44above, the values will be in the env vars `DB_USER`, `DB_PASS`, and `DB_NAME`.
45
46[ksa-secret]: https://kubernetes.io/docs/concepts/configuration/secret/
47
48## Setting up a service account
49
50The first step to running the Cloud SQL proxy in Kubernetes is creating a
51service account to represent your application. It is recommended that you create
52a service account unique to each application, instead of using the same service
53account everywhere. This model is more secure since it allows your to limit
54permissions on a per-application basis.
55
56The service account for your application needs to meet the following criteria:
57
581. Belong to a project with the [Cloud SQL Admin API][admin-api] enabled
591. [Has been granted][grant-sa] the
60 [`Cloud SQL Client` IAM role (or equivalent)][csql-roles]
61 for the project containing the instance you want to connect to
621. If connecting using private IP, you must use a
63 [VPC-native GKE cluster][vpc-gke], in the same VPC as your Cloud SQL instance
64
65[admin-api]: https://console.cloud.google.com/flows/enableapi?apiid=sqladmin&redirect=https://console.cloud.google.com
66[grant-sa]: https://cloud.google.com/iam/docs/granting-roles-to-service-accounts
67[csql-roles]: https://cloud.google.com/iam/docs/understanding-roles#cloud-sql-roles
68[vpc-gke]: https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips
69
70## Providing the service account to the proxy
71
72Next, you need to configure Kubernetes to provide the service account to the
73Cloud SQL Auth proxy. There are two recommended ways to do this.
74
75### Workload Identity
76
77If you are using [Google Kubernetes Engine][gke], the preferred method is to
78use GKE's [Workload Identity][workload-id] feature. This method allows you to
79bind a [Kubernetes Service Account (KSA)][ksa] to a Google Service Account
80(GSA). The GSA will then be accessible to applications using the matching KSA.
81
821. [Enable Workload Identity for your cluster][enable-wi]
831. [Enable Workload Identity for your node pool][enable-wi-node-pool]
841. Create a KSA for your application `kubectl apply -f service-account.yaml`:
85
86 > [service-account.yaml](service_account.yaml#L2-L5)
87 ```yaml
88 apiVersion: v1
89 kind: ServiceAccount
90 metadata:
91 name: <YOUR-KSA-NAME> # TODO(developer): replace these values
92 ```
931. Enable the IAM binding between your `<YOUR-GSA-NAME>` and `<YOUR-KSA-NAME>`:
94 ```sh
95 gcloud iam service-accounts add-iam-policy-binding \
96 --role roles/iam.workloadIdentityUser \
97 --member "serviceAccount:<YOUR-GCP-PROJECT>.svc.id.goog[<YOUR-K8S-NAMESPACE>/<YOUR-KSA-NAME>]" \
98 <YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com
99 ```
1001. Add an annotation to `<YOUR-KSA-NAME>` to complete the binding:
101 ```sh
102 kubectl annotate serviceaccount \
103 <YOUR-KSA-NAME> \
104 iam.gke.io/gcp-service-account=<YOUR-GSA-NAME>@<YOUR-GCP-PROJECT>.iam.gserviceaccount.com
105 ```
1061. Finally, make sure to specify the service account for the k8s pod spec:
107 > [proxy_with_workload_identity.yaml](proxy_with_workload_identity.yaml#L2-L15)
108 ```yaml
109 apiVersion: apps/v1
110 kind: Deployment
111 metadata:
112 name: <YOUR-DEPLOYMENT-NAME>
113 spec:
114 selector:
115 matchLabels:
116 app: <YOUR-APPLICATION-NAME>
117 template:
118 metadata:
119 labels:
120 app: <YOUR-APPLICATION-NAME>
121 spec:
122 serviceAccountName: <YOUR-KSA-NAME>
123 ```
124
125[gke]: https://cloud.google.com/kubernetes-engine
126[workload-id]: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity
127[ksa]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
128[enable-wi]: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_existing_cluster
129[enable-wi-node-pool]: https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#option_2_node_pool_modification
130
131### Service account key file
132
133Alternatively, if your can't use Workload Identity, the recommended pattern is
134to mount a service account key file into the Cloud SQL proxy pod and use the
135`-credential_file` flag.
136
1371. Create a credential file for your service account key:
138 ```sh
139 gcloud iam service-accounts keys create ~/key.json \
140 --iam-account <YOUR-SA-NAME>@project-id.iam.gserviceaccount.com
141 ```
1421. Turn your service account key into a k8s [Secret][k8s-secret]:
143 ```shell
144 kubectl create secret generic <YOUR-SA-SECRET> \
145 --from-file=service_account.json=~/key.json
146 ```
1473. Mount the secret as a volume under the`spec:` for your k8s object:
148 > [proxy_with_sa_key.yaml](proxy_with_sa_key.yaml#L74-L77)
149 ```yaml
150 volumes:
151 - name: <YOUR-SA-SECRET-VOLUME>
152 secret:
153 secretName: <YOUR-SA-SECRET>
154 ```
155
1564. Follow the instructions in the next section to access the volume from the
157 proxy's pod.
158
159[k8s-secret]: https://kubernetes.io/docs/concepts/configuration/secret/
160
161## Run the Cloud SQL proxy as a sidecar
162
163We recommend running the proxy in a "sidecar" pattern (as an additional
164container sharing a pod with your application). We recommend this over running
165as a separate service for several reasons:
166
167* Prevents your SQL traffic from being exposed locally - the proxy provides
168 encryption on outgoing connections, but you should limit exposure for
169 incoming connections
170* Prevents a single point of failure - each application's access to
171 your database is independent from the others, making it more resilient.
172* Limits access to the proxy, allowing you to use IAM permissions per
173 application rather than exposing the database to the entire cluster
174* Allows you to scope resource requests more accurately - because the
175 proxy consumes resources linearly to usage, this pattern allows you to more
176 accurately scope and request resources to match your applications as it
177 scales
178
1791. Add the Cloud SQL proxy to the pod configuration under `containers`:
180 > [proxy_with_workload-identity.yaml](proxy_with_workload_identity.yaml#L39-L69)
181 ```yaml
182 - name: cloud-sql-proxy
183 # It is recommended to use the latest version of the Cloud SQL proxy
184 # Make sure to update on a regular schedule!
185 image: gcr.io/cloudsql-docker/gce-proxy:1.17
186 command:
187 - "/cloud_sql_proxy"
188
189 # If connecting from a VPC-native GKE cluster, you can use the
190 # following flag to have the proxy connect over private IP
191 # - "-ip_address_types=PRIVATE"
192
193 # Replace DB_PORT with the port the proxy should listen on
194 # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433
195 - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>"
196 securityContext:
197 # The default Cloud SQL proxy image runs as the
198 # "nonroot" user and group (uid: 65532) by default.
199 runAsNonRoot: true
200 # Resource configuration depends on an application's requirements. You
201 # should adjust the following values based on what your application
202 # needs. For details, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
203 resources:
204 requests:
205 # The proxy's memory use scales linearly with the number of active
206 # connections. Fewer open connections will use less memory. Adjust
207 # this value based on your application's requirements.
208 memory: "2Gi"
209 # The proxy's CPU use scales linearly with the amount of IO between
210 # the database and the application. Adjust this value based on your
211 # application's requirements.
212 cpu: "1"
213 ```
214 If you are using a service account key, specify your secret volume and add
215 the `-credential_file` flag to the command:
216
217 > [proxy_with_sa_key.yaml](proxy_with_sa_key.yaml#L49-L58)
218 ```yaml
219 # This flag specifies where the service account key can be found
220 - "-credential_file=/secrets/service_account.json"
221 securityContext:
222 # The default Cloud SQL proxy image runs as the
223 # "nonroot" user and group (uid: 65532) by default.
224 runAsNonRoot: true
225 volumeMounts:
226 - name: <YOUR-SA-SECRET-VOLUME>
227 mountPath: /secrets/
228 readOnly: true
229 ```
230
2311. Finally, configure your application to connect via `127.0.0.1` on whichever
232 `<DB_PORT>` you specified in the command section.
233
234
235## Connecting without the Cloud SQL proxy
236
237While not as secure, it is possible to connect from a VPC-native GKE cluster to
238a Cloud SQL instance on the same VPC using private IP without the proxy.
239
2401. Create a secret with your instance's private IP address:
241 ```shell
242 kubectl create secret generic <YOUR-PRIVATE-IP-SECRET> \
243 --from-literal=db_host=<YOUR-PRIVATE-IP-ADDRESS>
244 ```
245
2462. Next make sure you add the secret to your application's container:
247 > [no_proxy_private_ip.yaml](no_proxy_private_ip.yaml#L34-L38)
248 ```yaml
249 - name: DB_HOST
250 valueFrom:
251 secretKeyRef:
252 name: <YOUR-PRIVATE-IP-SECRET>
253 key: db_host
254 ```
255
2563. Finally, configure your application to connect using the IP address from the
257 `DB_HOST` env var. You will need to use the correct port for your db-engine
258 (MySQL: `3306`, Postgres: `5432`, SQLServer: `1433`).
View as plain text