Search code examples
dockergoogle-cloud-platformgoogle-cloud-buildgoogle-secret-manager

Cloud Build, Container Registry, Cloud Run: Run tests without exposing env var


Cloud build do the following:

  1. Build image from dockerfile (see dockerfile below)
  2. Push image to container registry
  3. Update service in Cloud Run

My issue is the following:

As I'm running my tests on build time, I need my MONGODB_URI secret on build time, but I've read that using --build-arg is not safe to expose secrets.

I could run npm install and npm run test in Cloud Build container, but it would make build time longer as I'll have to run npm install two times.

Is there a way I can run only once npm install without having to expose secrets ?

Dockerfile

FROM node:16
COPY . ./
WORKDIR /
RUN npm install 

ARG env
ARG mongodb_uri

ENV ENVIRONMENT=$env
ENV DB_REMOTE_PROD=$mongodb_uri

RUN npm run test
RUN npm run build
CMD ["node", "./build/index.js"]

And my cloudbuild.yaml config:

steps:
  - name: gcr.io/cloud-builders/docker
    args:
      - '-c'
      - >-
        docker build --no-cache -t
        $_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
        --build-arg ENVIRONMENT=staging --build-arg mongodb_uri=$$MONGODB_URI -f
        Dockerfile .
    id: Build
    entrypoint: bash
    secretEnv:
      - MONGODB_URI
  - 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:
      - '-c'
      - >-
        gcloud 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
        --region=$_DEPLOY_REGION --update-env-vars=ENVIRONMENT=staging
        --update-env-vars=DB_REMOTE_PROD=$$MONGODB_URI --quiet
    id: Deploy
    entrypoint: bash
    secretEnv:
      - MONGODB_URI
images:
  - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
options:
  substitutionOption: ALLOW_LOOSE
  logging: CLOUD_LOGGING_ONLY
substitutions:
  _TRIGGER_ID: 44b16efe-0219-41af-b32b-9b98438728c3
  _GCR_HOSTNAME: eu.gcr.io
  _PLATFORM: managed
  _SERVICE_NAME: app-staging
  _DEPLOY_REGION: europe-southwest1
availableSecrets:
  secretManager:
    - versionName: projects/PROJECT_ID/secrets/mongodb_app_staging/versions/1
      env: MONGODB_URI

With my method, the secret is exposed not only in the container since I pass it as build-args, but it is also exposed to all users with access to cloud run...


Solution

  • Your container build step is not so bad. You provide your secrets to your container, but it is not visible. It's only reference.

    You can hardly do better. A solution could be to perform the secret access directly inside the Dockerfile, but I'm not sure that the "security gain" worth the Dockerfile increased complexity. (If you want more details, let me know, I will be able to share sample)


    About Cloud Run, you are totally true: exposing secret in plain text in environment variable is totally not acceptable.

    For that, you can use the Cloud Run - Secret Manager integration. Instead of doing this

    gcloud 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
            --region=$_DEPLOY_REGION --update-env-vars=ENVIRONMENT=staging
            --update-env-vars=DB_REMOTE_PROD=$$MONGODB_URI --quiet
    

    You can do that (and you now longer need to set the secret as env var of your Cloud Build step)

    gcloud 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
            --region=$_DEPLOY_REGION --update-env-vars=ENVIRONMENT=staging
            --update-secrets=DB_REMOTE_PROD=mongodb_app_staging:1 --quiet