Cloud SQL connection from Kubernetes in Go - Error 403: Insufficient Permission

8/8/2018

I need to connect to Google Cloud SQL from a Kubernetes pod using Go.

I have been following the following guides religiously: https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine https://cloud.google.com/sql/docs/mysql/connect-external-app#go

Here is my Kubernetes deployment yaml file:

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-service
  labels:
    app: my-service
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 10%
      maxSurge: 10%
  replicas: 1
  template:
    metadata:
      labels:
        app: my-service
    spec:
      imagePullSecrets:
      - name: regsecret
      containers:
      - name: my-service
        image: my-image
        imagePullPolicy: IfNotPresent
        env:
          - name: DB_INSTANCE
            value: "my-project-id:europe-west1:uk"
          - name: DB_USERNAME
            valueFrom:
              secretKeyRef:
                name: cloudsql-db-credentials
                key: username
          - name: DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: cloudsql-db-credentials
                key: password
      - name: cloudsql-proxy
        image: gcr.io/cloudsql-docker/gce-proxy:1.11
        command: ["/cloud_sql_proxy",
                  "-instances=my-project-id:europe-west1:uk=tcp:3306",
                  "-credential_file=/secrets/cloudsql/credentials.json"]
        volumeMounts:
          - name: cloudsql-instance-credentials
            mountPath: /secrets/cloudsql
            readOnly: true
      volumes:
        - name: cloudsql-instance-credentials
          secret:
            secretName: cloudsql-instance-credentials

And here is my attempt to connect using Go:

import (
    "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql"
    "github.com/spf13/viper"
    "log"
)

func Connect() {
    cfg := mysql.Cfg(
        viper.GetString("DB_INSTANCE"),
        viper.GetString("DB_USERNAME"),
        viper.GetString("DB_PASSWORD"))
    cfg.DBName = "my-db-name"

    db, err := mysql.DialCfg(cfg)
    if err != nil {
        log.Fatalf("Failed to create the Cloud SQL client: %v", err)
    }
}

Unfortunately, running this code results in:

2018/08/08 15:19:45 Failed to create the Cloud SQL client: ensure that the Cloud SQL API is enabled for your project (https://console.cloud.google.com/flows/enableapi?apiid=sqladmin). Error during createEphemeral for my-project-id:europe-west1:uk: googleapi: Error 403: Insufficient Permission, insufficientPermissions

I can confirm that the database obviously exists in Cloud SQL, the Cloud SQL API is indeed enabled, and that the service account that I used to generate the credentials (as described in the links above) does have the Cloud SQL Client role attached to it (I have also tried with Cloud SQL Admin and even project Owner with no success).

What am I missing?

EDIT:

Fixed it by updating my Go code to:

dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s",
    viper.GetString("DB_USERNAME"),
    viper.GetString("DB_PASSWORD"),
    "127.0.0.1:3306",
    "my-db-name")
db, err := sql.Open("mysql", dsn)
if err != nil {
    log.Fatalf("Failed to create the Cloud SQL client: %v", err)
}

Thanks @DazWilkin for the tip.

-- SebScoFr
go
google-cloud-platform
google-cloud-sql
kubernetes

1 Answer

8/12/2018

I know you've solved your issue already, but wanted to provide another alternative for anyone else reading this thread.

There are 2 ways you can connect to your instance: 1: Through a TCP connection: You have that solution already and this page shows you the details. Since the cloud SQL proxy container runs on the same pod as your app container, your host should point to localhost. 2: Unix socket:

You should also be able to connect through the following code (details here):

import (
       "database/sql"
        _ "github.com/go-sql-driver/mysql"
)

dsn := fmt.Sprintf("%s:%s@unix(/cloudsql/%s)/%s",
       dbUser,
       dbPassword,
       INSTANCE_CONNECTION_NAME,
       dbName)
db, err := sql.Open("mysql", dsn)

You may have to remove the =tcp:3306 portion from your deployment.yaml file through.

-- Prashant
Source: StackOverflow