1
votes

I've been using the @google-cloud/secret-manager plugin inside my Node application, previously hosted on Google App Engine.

It was working perfectly fine until I moved my code to Cloud Run. I am now getting the following error: error:

Error: 500 undefined: Getting metadata from plugin failed with error: Could not refresh access token: Unsuccessful response status code.

Here is an example of my code:

import { SecretManagerServiceClient } from '@google-cloud/secret-manager';

const SECRET = {
  FOO_KEY: 'foo_key',
  BAR_KEY: 'bar_key',
};

const buildSecretName = keyName => {
  const project = process.env.PROJECT_ID;
  return `projects/${project}/secrets/${keyName}/versions/latest`;
};

const accessSecret = async keyName => {
  const client = new SecretManagerServiceClient();
  const name = buildSecretName(keyName);
  
  const [version] = await client.accessSecretVersion({
    name,
  });

  return version.payload.data.toString('utf8');
};

const accessFooKey = async () => {
  const secret = await accessSecret(SECRET.FOO_KEY);
  return secret;
};

After debugging, the Exception seems to be thrown when running the accessSecretVersion function. It looks like the secret-manager plugin can not retrieve the current service account, is it because I am running my code inside a Docker image ?

Here is the content of my Dockerfile

FROM node:12

ARG NODE_ENV=production
ENV NODE_ENV ${NODE_ENV}

ARG PROJECT_ID=my-project
ENV PROJECT_ID ${PROJECT_ID}

WORKDIR /usr/src

COPY package.json ./
COPY yarn.lock ./

RUN yarn

COPY . .

RUN yarn api:clean
RUN yarn api:build

EXPOSE 3000
CMD ["yarn", "api:start"]

It is deployed via a trigger build using the following cloudbuild.yaml file

steps:
  - id: build API image
    name: gcr.io/cloud-builders/docker
    args:
      - build
      - -t
      - eu.gcr.io/${_TARGET_PROJECT_ID}/${_SERVICE_NAME}
      - .

  - id: publish API image
    name: gcr.io/cloud-builders/docker
    args:
      - push
      - eu.gcr.io/${_TARGET_PROJECT_ID}/${_SERVICE_NAME}

  - id: deploy
    name: gcr.io/google.com/cloudsdktool/cloud-sdk
    args:
      - gcloud
      - run
      - deploy
      - ${_SERVICE_NAME}
      - --image=eu.gcr.io/${_TARGET_PROJECT_ID}/${_SERVICE_NAME}
      - --project=${_TARGET_PROJECT_ID}
      - --platform=${_RUN_PLATFORM}
      - --region=${_REGION}

images:
  - eu.gcr.io/${_TARGET_PROJECT_ID}/${_SERVICE_NAME}

timeout: 1200s

For information, my secrets are readable by the Cloud Run custom service account, they all have the Secret Manager Secret Accessor access right.

Thanks a lot for your help!

1
Can you share your Dockerfile and the rest of your code? How are you calling "accessSecret"? How have you deployed your service to Cloud Run?sethvargo
I edited my answer with the info you asked, thanks for your timerguerin
Double-check the service account assigned to Cloud Run.John Hanley

1 Answers

5
votes

As John Hanley stated, I didn't specify any particular service account while deploying my Docker image. The default service account is the Compute Engine account ([email protected]) which was disabled by my company to prevent security issues.

Using a custom service account while running the gcloud run deploy command solved the problem. My deploy step now looks like this:

  - id: deploy
    name: gcr.io/google.com/cloudsdktool/cloud-sdk
    args:
      - gcloud
      - run
      - deploy
      - ${_SERVICE_NAME}
      - --image=eu.gcr.io/${_TARGET_PROJECT_ID}/${_SERVICE_NAME}
      - --project=${_TARGET_PROJECT_ID}
      - --platform=${_RUN_PLATFORM}
      - --region=${_REGION}
      - --service-account=custom-service@my-project.iam.gserviceaccount.com

Thank y'all for your help