Passing a SECRET KEY as environment variable in gcloud - google-cloud-platform

I have stored a key in the Secret manager of GCP and I'm trying to use that secret in the cloudbuild.yaml but every time I have this error:
ERROR: (gcloud.functions.deploy) argument --set-secrets: Secrets value configuration must match the pattern 'SECRET:VERSION' or 'projects/{PROJECT}/secrets/{SECRET}:{VERSION}' or 'projects/{PROJECT}/secrets/{SECRET}/versions/{VERSION}' where VERSION is a number or the label 'latest' [ 'projects/gcp-project/secrets/SECRETKEY/versions/latest' ]]
My cloud build file looks like this:
steps:
- id: installing-dependencies
name: 'python'
entrypoint: pip
args: ["install", "-r", "src/requirements.txt", "--user"]
- id: deploy-function
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
args:
- gcloud
- functions
- deploy
- name_of_my_function
- --region=us-central1
- --source=./src
- --trigger-topic=name_of_my_topic
- --runtime=python37
- --set-secrets=[ SECRETKEY = 'projects/gcp-project/secrets/SECRETKEY/versions/latest' ]
waitFor: [ "installing-dependencies" ]
I was reading the documentation, but I don't have any other clue that could help me.

As mentioned by al-dann, there should not be any space in set-secret line as you can see the documentation
Final correction in code :
--set-secrets=[SECRETKEY='projects/gcp-project/secrets/SECRETKEY/versions/latest']
For more information, you can refer to the stackoverflow thread and blog where brief information about secret manager has been well explained.

Related

how to specify default cloud run revision url in the cloud build yaml file

I have a GCP project where I continuously deploy changes (PRs) made to a GitHub repository to a cloud-run service using cloud build triggers
the way i set it up at first is that i use GCP GUI
this results in a trigger in cloud-build\
the cloud-build trigger has the yaml file that looks like this
- name: gcr.io/cloud-builders/docker
args:
- build
- '--no-cache'
- '-t'
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- .
- '-f'
- Dockerfile
id: Build
- name: gcr.io/cloud-builders/docker
args:
- push
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
id: Push
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
args:
- run
- services
- update
- $_SERVICE_NAME
- '--platform=managed'
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- >-
--labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID,$_LABELS
- '--region=$_DEPLOY_REGION'
- '--quiet'
id: Deploy
entrypoint: gcloud
images:
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
options:
substitutionOption: ALLOW_LOOSE
substitutions:
_PLATFORM: managed
_SERVICE_NAME: bordereau
_DEPLOY_REGION: europe-west1
_LABELS: gcb-trigger-id=((a long random id goes here))
_TRIGGER_ID: ((an other long random id goes here))
_GCR_HOSTNAME: eu.gcr.io
tags:
- gcp-cloud-build-deploy-cloud-run
- gcp-cloud-build-deploy-cloud-run-managed
- bordereau
when ever this trigger is run, a new cloud-run revision is created like this
then i can create a url that points to a specific url like this
that helps me access each revision using its unique URL
i tried many ways to eddit the cloud-build YAML file to give each revision a unique URL automaticly ( not manually through the GCP GUI ) but i dont seem to find a way! i tried many keywords, and read the documentation but that didnt help either!
any help is very much appreciated.
it would be great if the revision URL (tag) was something unique and short like first charecters of the commit SHA or the PR number
Usually you can do like that (see step id: tag)
- name: gcr.io/cloud-builders/docker
args:
- build
- '--no-cache'
- '-t'
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- .
- '-f'
- Dockerfile
id: Build
- name: gcr.io/cloud-builders/docker
args:
- push
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
id: Push
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
args:
- run
- services
- update
- $_SERVICE_NAME
- '--platform=managed'
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- >-
--labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID,$_LABELS
- '--region=$_DEPLOY_REGION'
- '--quiet'
id: Deploy
entrypoint: gcloud
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
args:
- -c
- |
export sha=$COMMIT_SHA
export CUSTOM_TAG=${sha:0:8}
export CURRENT_REV=$(gcloud alpha run services describe $_SERVICE_NAME --region=$_DEPLOY_REGION --platform=managed --format='value(status.traffic[0].revisionName)')
gcloud run services update-traffic $_SERVICE_NAME --set-tags=$$CUSTOM_TAG=$$CURRENT_REV --region=$_DEPLOY_REGION --platform=managed
id: tag
entrypoint: bash
images:
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
options:
substitutionOption: ALLOW_LOOSE
substitutions:
_PLATFORM: managed
_SERVICE_NAME: bordereau
_DEPLOY_REGION: europe-west1
_LABELS: gcb-trigger-id=((a long random id goes here))
_TRIGGER_ID: ((an other long random id goes here))
_GCR_HOSTNAME: eu.gcr.io
tags:
- gcp-cloud-build-deploy-cloud-run
- gcp-cloud-build-deploy-cloud-run-managed
- bordereau
In that custom tag, I put the 8 first character of the commit SHA
You can note the weird env var COMMIT_SHA copy to a local env var. It's a strange thing with CloudBuild.

Why is my environment variable not recognized after Cloud Run deploy?

My node application needs an environment variable as requirement to make a POST request. Everything works fine in my local machine by accessing the .env file content directly. I also did make sure to set ${_TM_API_KEY} in GCP so I can trigger it, as suggested by the docs, however it doesn't seem to recognize the variable after the application is deployed. What am I doing wrong? Any further suggestion would be deeply appreciated it. My cloudbuild.yaml looks like this:
steps:
- id: build
name: gcr.io/cloud-builders/docker
args:
[
"build",
"-t",
"gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}",
"--build-arg=ENV=${_TM_API_KEY}",
".",
]
env:
- "TM_API_KEY=${_TM_API_KEY}"
- id: push
name: "gcr.io/cloud-builders/docker"
args: ["push", "gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}"]
- id: deploy
name: "gcr.io/cloud-builders/gcloud"
args:
- "run"
- "deploy"
- "suweb"
- "--set-env-vars=TM_API_KEY=${_TM_API_KEY}"
- "--image"
- "gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}"
- "--region"
- "us-central1"
- "--platform"
- "managed"
- "--allow-unauthenticated"
images:
- "gcr.io/${PROJECT_ID}/suweb:${SHORT_SHA}"
More details: the code where the API_KEY is being referenced is in the following header:
const headers = {
TM_API_KEY: process.env.TM_API_KEY,
"Content-Type": "multipart/form-data",
"Access-Control-Allow-Origin": "*",
};
And my .env file looks like this:
TM_API_KEY=_TM_API_KEY
It is a bit unclear for me if I should reference the trigger variable here as well (_TM_API_KEY) or write the key value.
After that, when doing a form post request, the server responds with a CORS policy error telling that such endpoint couldn't be reached. I tried by hard coding the API_KEY in the headers and everything works fine, no errors whatsoever.

Access GCP Secret during Cloud Build build step

Lets say I have a cloudbuild.yaml file that looks like this:
steps:
- name: 'gcr.io/cloud-builders/docker'
id: build
args: ['build', '-t', 'us.gcr.io/${PROJECT_ID}/image_name', '--build-arg', 'secret=$$SECRET', '.']
secretEnv: ['SECRET']
images:
- 'us.gcr.io/${PROJECT_ID}/image_name'
availableSecrets:
secretManager:
- versionName: projects/project/secrets/my_secret/versions/latest
env: 'SECRET'
Right now, the --build-arg is assigning to the Docker secret arg the value $SECRET instead of the value actually stored in the secret. How can I access the secret value during this step? All of the examples I can find online say to add a bash entrypoint however only for steps that aren't actually doing the build call.
It's a usual issue with Cloud Build and Secret Manager integration. You can access to the secret only in a script, not in entry-point and arguments (your case)
Try that
steps:
- name: 'gcr.io/cloud-builders/docker'
id: build
entrypoint: 'bash'
args:
- -c
- |
docker build -t us.gcr.io/${PROJECT_ID}/image_name --build-arg secret=$$SECRET .
secretEnv: ['SECRET']
The syntax for assigning secrets to docker args seems to be slightly different to that for normal environment variables. The following snippet is taken from a working project of my own and correctly accesses the secret, and you can see the difference compared to the normal environment variables:
...
env:
- PROJECT_ID=$PROJECT_ID
- NO_DEPLOY=$_NO_DEPLOY
- NO_E2E=$_NO_E2E
secretEnv:
- "EXAMPLE_API_KEY"
args:
- --destination=gcr.io/$PROJECT_ID/api
- --cache=true
- --build-arg=PROJECT_ID
- --build-arg=EXAMPLE_API_KEY
- --build-arg=NO_DEPLOY
- --build-arg=NO_E2E
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/example-api-key/versions/latest
env: "EXAMPLE_API_KEY"
...

Google cloudbuild secrets not substituted

I am trying to retrieve secrets from the secrets manager in the cloudbuild.yaml file but I can't find a way.
- name: 'gcr.io/cloud-builders/gcloud'
args:
- beta
- run
- deploy
- ${REPO_NAME}
- --region=europe-west2
- --image=gcr.io/$PROJECT_ID/${REPO_NAME}:$COMMIT_SHA
- --service-account=${_SERVICE_ACCOUNT}
- --cpu=2
- --allow-unauthenticated
- --set-env-vars=GCP_DB_INSTANCE_NAME=$$GCP_DB_INSTANCE_NAME
- --set-env-vars=PG_DATABASE=$$PG_DATABASE
- --set-env-vars=PG_PASSWORD=$$PG_PASSWORD
- --set-env-vars=PG_USER=$$PG_USER
- --set-env-vars=GCP_PROJECT=$$GCP_PROJECT
- --set-env-vars=GCP_BUCKET_NAME=$$GCP_BUCKET_NAME
- --add-cloudsql-instances=$$GCP_DB_INSTANCE_NAME
secretEnv: [ 'GCP_DB_INSTANCE_NAME', 'PG_DATABASE', 'PG_PASSWORD', 'PG_USER', 'GCP_PROJECT', 'GCP_BUCKET_NAME' ]
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/GCP_DB_INSTANCE_NAME/versions/latest
env: GCP_DB_INSTANCE_NAME
- versionName: projects/$PROJECT_ID/secrets/PG_DATABASE/versions/latest
env: PG_DATABASE
- versionName: projects/$PROJECT_ID/secrets/PG_PASSWORD/versions/latest
env: PG_PASSWORD
- versionName: projects/$PROJECT_ID/secrets/PG_USER/versions/latest
env: PG_USER
- versionName: projects/$PROJECT_ID/secrets/GCP_PROJECT/versions/latest
env: GCP_PROJECT
- versionName: projects/$PROJECT_ID/secrets/GCP_BUCKET_NAME/versions/latest
env: GCP_BUCKET_NAME
But the variables are not substituted. I have logged the values in my api and that is what I get:
2021-08-05T22:31:33.437926Z key value PG_DATABASE $PG_DATABASE
2021-08-05T22:31:33.437965Z key value PG_USER $PG_USER
2021-08-05T22:31:33.437985Z key value PG_PASSWORD $PG_PASSWORD
2021-08-05T22:31:33.438063Z key value GCP_PROJECT $GCP_PROJECT
2021-08-05T22:31:33.438093Z key value GCP_BUCKET_NAME $GCP_BUCKET_NAME
How can I substitute the secrets in my step?
Instead of injecting these variables at build time, it would be better to inject them at runtime. As written, the secrets will be viewable in plaintext by anyone with permission to view the Cloud Run service. That's because they are resolved during the build step and set as environment variables. Furthermore, if you were to revoke or change one of these secrets, the Cloud Run service would continue to operate with the old value.
A better solution is to use the native Cloud Run Secret Manager integration, which resolves secrets at instance boot. It would look like this:
- name: 'gcr.io/cloud-builders/gcloud'
args:
- run
- deploy
- ${REPO_NAME}
- --region=europe-west2
- --image=gcr.io/$PROJECT_ID/${REPO_NAME}:$COMMIT_SHA
- --service-account=${_SERVICE_ACCOUNT}
- --cpu=2
- --allow-unauthenticated
- --set-secrets=GCP_DB_INSTANCE_NAME=projects/$PROJECT_ID/secrets/GCP_DB_INSTANCE_NAME:latest,PG_DATABASE=projects/$PROJECT_ID/secrets/PG_DATABASE:latest // continue
- --add-cloudsql-instances=$$GCP_DB_INSTANCE_NAME
Cloud Run will automatically resolve the secrets when it boots a new instance. You'd need to grant $SERVICE_ACCOUNT permissions to access the secret.
Can you please give it a try as below?
- name: 'gcr.io/cloud-builders/gcloud'
secretEnv: [ 'GCP_DB_INSTANCE_NAME', 'PG_DATABASE', 'PG_PASSWORD', 'PG_USER', 'GCP_PROJECT', 'GCP_BUCKET_NAME' ]
entrypoint: 'bash'
args:
- -c
- |
gcloud beta run deploy ${REPO_NAME} --region=europe-west2 --image=gcr.io/$PROJECT_ID/${REPO_NAME}:$COMMIT_SHA --service-account=${_SERVICE_ACCOUNT} --cpu=2 --allow-unauthenticated --set-env-vars=GCP_DB_INSTANCE_NAME=$$GCP_DB_INSTANCE_NAME --set-env-vars=PG_DATABASE=$$PG_DATABASE --set-env-vars=PG_PASSWORD=$$PG_PASSWORD --set-env-vars=PG_USER=$$PG_USER --set-env-vars=GCP_PROJECT=$$GCP_PROJECT --set-env-vars=GCP_BUCKET_NAME=$$GCP_BUCKET_NAME --add-cloudsql-instances=$$GCP_DB_INSTANCE_NAME
According to the docs, you have to specify the flag -c in the args field so anything after it will be treated as a command.
Ref: https://cloud.google.com/build/docs/securing-builds/use-secrets

How to access GSM secrets through Cloud Build and pass to Cloud Function

How does one pass a secret from Google Secrets Manager (GSM) to a Cloud Function when using Cloud Build? The below cloudbuild.yaml has three steps. Further, I'm using volumes to create permanent storage between build steps. I can confirm GSM retrieval by Cloud Build. However, when I attempt to pass a secret in yaml format using --env-vars-file I encounter the following error ...
Already have image (with digest): gcr.io/cloud-builders/gcloud
ERROR: gcloud crashed (AttributeError): 'str' object has no attribute 'items'
cloudbuild.yaml:
steps:
- name: 'gcr.io/cloud-builders/gcloud'
volumes:
- name: 'secrets'
path: '/secrets'
entrypoint: "bash"
args:
- "-c"
- |
echo -n 'gsm_secret:' > /secrets/my-secret-file.txt
- name: 'gcr.io/cloud-builders/gcloud'
volumes:
- name: 'secrets'
path: '/secrets'
entrypoint: "bash"
args:
- "-c"
- |
gcloud components update
gcloud beta secrets versions access --secret=MySecret latest >> /secrets/my-secret-file.txt
cat /secrets/my-secret-file.txt
- name: 'gcr.io/cloud-builders/gcloud'
volumes:
- name: 'secrets'
path: '/secrets'
args: [
'functions', 'deploy', 'gsm-foobar',
'--project=[...]',
'--trigger-http',
'--runtime=go111',
'--region=us-central1',
'--memory=256MB',
'--timeout=540',
'--entry-point=GSM',
'--allow-unauthenticated',
'--source=https://source.developers.google.com/[...]',
'--service-account', '[...]#appspot.gserviceaccount.com',
'--env-vars-file', '/secrets/my-secret-file.txt'
]
Update:
Usage of volumes is not required as /workspace is permanent storage between steps in Cloud Build. Also, gcloud components update is no longer necessary as the default Cloud SDK version, as of today, is 279.0.0
A Solution:
steps:
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: "bash"
args:
- "-c"
- |
echo "gsm_secret: $(gcloud beta secrets versions access --secret=MySecret latest)" > /workspace/my-secret-file.txt
cat /workspace/my-secret-file.txt
- name: 'gcr.io/cloud-builders/gcloud'
args: [
'functions', 'deploy', 'gsm-foobar',
[...]
'--entry-point=GSM',
'--allow-unauthenticated',
'--source=https://source.developers.google.com/[...]',
'--service-account', '[...]#appspot.gserviceaccount.com',
'--env-vars-file=/workspace/my-secret-file.txt'
]
On second read, I realize your 2nd step puts the secret value in the file. I think you're missing the newline.
NB I've not tried this for myself!
Ensure you have a newline at the end of your secrets file.
See: https://cloud.google.com/functions/docs/env-var
Update: tried it ;-)
I think your issue was the final newline.
Using the following in a step prior to the deployment, works:
echo "gsm_secret: $(gcloud beta secrets versions access --secret=MySecret latest)" > /secrets/my-secret-file.txt
Or, more simply, perhaps:
steps:
- name: "gcr.io/cloud-builders/gcloud"
entrypoint: /bin/bash
args:
- "-c"
- |
gcloud functions deploy ... \
--set-env-vars=NAME=$(gcloud beta secrets versions access --secret=name latest)
Also, see secretEnv. This is a more elegant mechanism..This functionality should perhaps be augmented by Google to support secret manager (in addition to KMS).
As of 2021 February 10, you can access Secret Manager secrets directly from Cloud Build using the availableSecrets field:
steps:
- id: 'deploy'
name: 'gcr.io/cloud-builders/gcloud'
entrypoint: 'bash'
args:
- '-c'
- 'gcloud functions deploy --set-env-vars=SECRET=$$MY_SECRET'
secretEnv: ['MY_SECRET']
availableSecrets:
secretManager:
- versionName: 'projects/my-project/secrets/my-secret/versions/latest'
env: 'MY_SECRET'
Documentation