Executing maven unit tests on a Google Cloud SQL environment

3/4/2019

I have a Jenkins pod running in GCP's Kubernetes Engine and I'm trying to run a maven unit test that connects to a google cloud SQL database to perform said test. My application.yaml for my project looks like this:

spring:
  cloud:
     gcp:
        project-id: <my_project_id>
     sql: 
        database-name: <my_database_name>
        instance-connection-name: <my_instance_connection_name>

  jpa:
     database-platform: org.hibernate.dialect.MySQL55Dialect
     hibernate:
        ddl-auto: create-drop

  datasource:
     continue-on-error: true
     driver-class-name: com.mysql.cj.jdbc.Driver
     username: <my_cloud_sql_username>
     password: <my_cloud_sql_password>

The current Jenkinsfile associated with this project is:

Jenkinsfile:

pipeline {
   agent any

   tools{
      maven 'Maven 3.5.2'
      jdk 'jdk8'
   }
   environment {
       IMAGE = readMavenPom().getArtifactId()
       VERSION = readMavenPom().getVersion()
       DEV_DB_USER = "${env.DEV_DB_USER}"
       DEV_DB_PASSWORD = "${env.DEV_DB_PASSWORD}"
    }

   stages {
      stage('Build docker image') {
        steps {
            sh 'mvn -Dmaven.test.skip=true clean package'
            script{
               docker.build '$IMAGE:$VERSION'
            }

        }
    }
       stage('Run unit tests') {

          steps {
            withEnv(['GCLOUD_PATH=/var/jenkins_home/google-cloud-sdk/bin']) {
                withCredentials([file(credentialsId: 'key-sa', variable: 'GC_KEY')]) {
                   sh("gcloud auth activate-service-account --key-file=${GC_KEY}")
                   sh("gcloud container clusters get-credentials <cluster_name> --zone northamerica-northeast1-a --project <project_id>")
                   sh 'mvn test'
                }
             }          
           }                
        }
    }
}

}

My problem is when the Pipeline actually tries to run the mvn test using the above configuration (in my application.yaml) I'm getting this error:

  Caused by: 
  com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 
  Forbidden
  {
     "code" : 403,
     "errors" : [ {
        "domain" : "global",
        "message" : "Insufficient Permission: Request had insufficient authentication scopes.",
        "reason" : "insufficientPermissions"
      } ],
     "message" : "Insufficient Permission: Request had insufficient authentication scopes."
  }

I have two Google Cloud projects:

  • One that has the Kubernetes Cluster where the Jenkins pod is running.

  • Another project where the K8s Cluster contains my actual Spring Boot Application and the Cloud SQL database that I'm trying to access.

I also created the service account only in my Spring Boot Project for Jenkins to use with three roles: Cloud SQL Editor, Kubernetes Engine Cluster Admin and Project owner (to verify that the service account is not at fault).

I enabled the Cloud SQL, Cloud SQL admin and Kubernetes APIs in both projects and I double checked my Cloud SQL credentials and they are ok. In addition, I authenticated the Jenkins pipeline using the json file generated when I created the service account, following the recommendations discussed here:

Jenkinsfile (extract):

  ...
  withCredentials([file(credentialsId: 'key-sa', variable: 'GC_KEY')]) {
               sh("gcloud auth activate-service-account --key-file=${GC_KEY}")
               sh("gcloud container clusters get-credentials <cluster_name> --zone northamerica-northeast1-a --project <project_id>")
               sh 'mvn test'
   }
   ...
-- Carlos Gomez
google-cloud-sql
jenkins
kubernetes
maven
unit-testing

2 Answers

3/4/2019

I don't believe the GCP Java SDK relies on gcloud CLI at all. Instead, it looks for an environment variable GOOGLE_APPLICATION_CREDENTIALS that points to your service account key file and GCLOUD_PROJECT (see https://cloud.google.com/docs/authentication/getting-started).

Try adding the following:

sh("export GOOGLE_APPLICATION_CREDENTIALS=${GC_KEY}")
sh("export GCLOUD_PROJECT=<project_id>")
-- neildo
Source: StackOverflow

3/5/2019

There are a couple of different things you should verify to get this working. I'm assuming you are using the Cloud SQL JDBC SocketFactory for Cloud SQL.

  1. You should create a testing service account and give it whatever permissions are needed to execute the tests. To connect to Cloud SQL, it needs at a minimum the "Cloud SQL Client" role for the same project as the Cloud SQL instance.
  2. The Cloud SQL SF uses the Application Default Credentials (ADC) strategy for determining what authentication to use. This means the first place it looks for credentials is the GOOGLE_APPLICATION_CREDENTIALS env var, which should be a path to the key for the testing service account.
-- kurtisvg
Source: StackOverflow