From 9dd08c48bc3f44078a3967166ab37a9bcc574b51 Mon Sep 17 00:00:00 2001 From: Weimin Yu Date: Tue, 6 Apr 2021 09:43:15 -0400 Subject: [PATCH] Use credential in secretmanager to deploy schema (#1055) * Use credential in secretmanager to deploy schema Fetch the schema_deployer credential from SecretManager when deploying the schema to Cloud SQL. --- db/build.gradle | 35 ++++++++++---------- release/cloudbuild-schema-deploy.yaml | 28 ++++++++++------ release/schema-deployer/deploy_sql_schema.sh | 16 ++++----- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/db/build.gradle b/db/build.gradle index 56794e361..9459ccc9f 100644 --- a/db/build.gradle +++ b/db/build.gradle @@ -1,3 +1,5 @@ +import org.gradle.process.internal.ExecException + // Copyright 2019 The Nomulus Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,7 +42,7 @@ ext { } getSocketFactoryAccessInfo = { env -> - def cred = getCloudSqlCredential(env, 'admin').split(' ') + def cred = getCloudSqlCredential(env).split(' ') def sqlInstance = cred[0] println "Database set to Cloud SQL instance ${sqlInstance}." return [ @@ -65,26 +67,25 @@ ext { } } - // Retrieves Cloud SQL credential for a given role. Result is in the form of - // 'instancename username password'. + // Retrieves the Cloud SQL credential for the schema deployer. Result is in + // the form of 'instancename username password'. // // The env parameter may be one of the following: alpha, crash, sandbox, or - // production. The role parameter may be superuser. (More roles will be added - // later). - getCloudSqlCredential = { env, role -> - def devProject = rootProject.devProject - def gcpProject = rootProject.projects[env] - def keyProject = env in restrictedDbEnv? devProject : gcpProject + // production. + // + // User must make sure that the nomulus tool can be found on PATH. An alias + // will not work. + getCloudSqlCredential = { env -> + try { + execInBash('which nomulus', '/tmp') + } catch (ExecException e) { + throw new IllegalStateException( + 'nomulus not found. Make sure it is on PATH, not just an alias.') + } def command = - """gsutil cp \ - gs://${gcpProject}-beam/cloudsql/${role}_credential.enc - | \ - base64 -d | \ - gcloud kms decrypt --location global --keyring nomulus-tool-keyring \ - --key nomulus-tool-key --plaintext-file=- \ - --ciphertext-file=- \ - --project=${keyProject}""" + "nomulus -e ${env} get_sql_credential --user schema_deployer" - return execInBash(command, '/tmp') + return execInBash(command, project.rootDir) } } diff --git a/release/cloudbuild-schema-deploy.yaml b/release/cloudbuild-schema-deploy.yaml index fe765e872..139154a08 100644 --- a/release/cloudbuild-schema-deploy.yaml +++ b/release/cloudbuild-schema-deploy.yaml @@ -27,9 +27,9 @@ # See https://github.com/spinnaker/spinnaker/issues/3028 for more information. steps: # Download and decrypt the nomulus tool credential, which has the privilege to -# start Cloud SQL proxy to all environments. -# Also download and decrypt the admin_credential file, which has the cloud -# instance name and database login name and password. +# start Cloud SQL proxy to all environments. This credential is also used to +# authenticate the nomulus tool when fetching the schema deployer credential in +# the next step. - name: 'gcr.io/$PROJECT_ID/builder:latest' volumes: - name: 'secrets' @@ -45,13 +45,21 @@ steps: --ciphertext-file=- \ --plaintext-file=/secrets/cloud_sql_credential.json \ --location=global --keyring=nomulus-tool-keyring --key=nomulus-tool-key - gsutil cp gs://$PROJECT_ID-deploy/cloudsql-credentials/${_ENV}/admin_credential.enc - \ - | base64 -d \ - | gcloud kms decrypt \ - --ciphertext-file=- \ - --plaintext-file=/secrets/admin_credential.dec \ - --location global --keyring=nomulus-tool-keyring \ - --key=nomulus-tool-key +# Fetch the Cloud SQL credential for schema_deployer +- name: 'gcr.io/$PROJECT_ID/nomulus-tool:latest' + volumes: + - name: 'secrets' + path: '/secrets' + args: + - -e + - ${_ENV} + - --credential + - /secrets/cloud_sql_credential.json + - get_sql_credential + - --user + - schema_deployer + - --output + - /secrets/schema_deployer_credential.dec # Download the schema jar to be deployed. - name: 'gcr.io/$PROJECT_ID/builder:latest' volumes: diff --git a/release/schema-deployer/deploy_sql_schema.sh b/release/schema-deployer/deploy_sql_schema.sh index 38d3a381f..898acea2d 100755 --- a/release/schema-deployer/deploy_sql_schema.sh +++ b/release/schema-deployer/deploy_sql_schema.sh @@ -18,19 +18,19 @@ # - /flyway/jars: the schema jar to be deployed. # # Database login info may be passed in two ways: -# - Decrypt the admin_credential.enc file on GCS and map it as -# /secrets/admin_credential.dec -# - Provide the content of the admin_credential as command line arguments +# - Save it in the format of "cloud_sql_instance login password" in a file and +# map the file as /secrets/schema_deployer_credential.dec +# - Provide the content of the credential as command line arguments set -e if [ "$#" -le 1 ]; then - if [ ! -f /secrets/admin_credential.dec ]; then - echo "Missing /secrets/admin_credential.dec" + if [ ! -f /secrets/schema_deployer_credential.dec ]; then + echo "Missing /secrets/schema_deployer_credential.dec" exit 1 fi - cloud_sql_instance=$(cut -d' ' -f1 /secrets/admin_credential.dec) - db_user=$(cut -d' ' -f2 /secrets/admin_credential.dec) - db_password=$(cut -d' ' -f3 /secrets/admin_credential.dec) + cloud_sql_instance=$(cut -d' ' -f1 /secrets/schema_deployer_credential.dec) + db_user=$(cut -d' ' -f2 /secrets/schema_deployer_credential.dec) + db_password=$(cut -d' ' -f3 /secrets/schema_deployer_credential.dec) flyway_action=${1:-validate} elif [ "$#" -ge 3 ]; then cloud_sql_instance=$1