【问题标题】:How to authenticate to GCP from a containerized Dockerfile如何从容器化的 Dockerfile 向 GCP 进行身份验证
【发布时间】:2019-12-13 15:55:47
【问题描述】:

我正在尝试使用 Cloud Build 触发作业动态构建新的 Docker 映像,但是我看不到如何安全地检索我的凭据以使用服务帐户对 GCP 进行身份验证。

步骤如下:

  1. 使用构建 Docker 映像的步骤创建的 Dockerfile。其中一个步骤包括从 Google 存储(存储桶)下载我需要作为 GCP 服务帐户访问的文件。

  2. Docker 映像是使用 Cloud Build 触发器构建的,该触发器在链接存储库中的每次更改后触发并存储在 GCR 中。

第一步失败是因为:

1.) 默认情况下,出于某种原因,在 GCP 中运行 Dockerfile 的用户未针对 GCP 进行身份验证。它不是默认的 Google Cloud Build 帐户,而是匿名用户。

2.) 我可以作为服务帐户进行身份验证,但是

a.) 我不想将未加密的 JSON 私钥存储在本地或存储库中。 b.) 如果我将其加密存储在 GCP 存储库中,那么我需要在使用 KMS 解密之前进行身份验证。但我没有密钥,因为它仍然是加密的。所以我回到我的问题。 c.) 如果我将其存储在 GCP 存储桶中,我也需要进行身份验证。所以我回到我的问题。

还有其他方法可以让我执行云构建触发器作业并保持/获取 GCP 服务帐户上下文吗?

【问题讨论】:

  • 需要凭据的 Cloud Build 步骤是什么样的?我假设它是一个 gsutil 命令?
  • 是的,你是对的。

标签: docker google-cloud-platform dockerfile google-cloud-build


【解决方案1】:

@ParthMehta 的#1 解决方案是正确的。

在调用 Docker Build 之前,在您的 Cloud Build 中添加此步骤,用于使用 Cloud Build 环境的权限从 Cloud Storage 下载文件(服务帐号如下:<PROJECT_NUMBER>@cloudbuild.gserviceaccount.com

- name: gcr.io/cloud-builders/gsutil
  args: ['cp', 'gs://mybucket/my_file', 'my_file']

文件复制到 Cloud Build 执行的当前目录/workspace。然后通过在您的Dockerfile 中添加一个简单的COPY 将文件添加到您的容器中

....
COPY ./my_file ./my_file
....

一般来说,当您在 GCP 环境中工作时,您永远不必使用 JSON 密钥文件。

【讨论】:

    【解决方案2】:
    1. 您可以让 cloud build 为您从云存储下载文件,并让 docker 访问该目录,以便它可以使用该文件。您需要允许云构建服务帐户访问您的存储桶。

      见:https://cloud.google.com/cloud-build/docs/securing-builds/set-service-account-permissions

    1. 使用gcloud auth configure-docker,然后您可以使用 --impersonate-service-account 模拟服务帐户并访问存储桶,因此docker用户有足够的访问权限来下载文件

      见:https://cloud.google.com/sdk/gcloud/reference/auth/configure-docker

    【讨论】:

      【解决方案3】:

      老问题,但上面的答案对我来说都不满意,因为我需要从 Artifact Registry 中提取私有包。经过大量试验和错误后,我找到了使用短期访问令牌和服务帐户模拟的解决方案,我正在分享该解决方案,以防其他人遇到同样的问题。

      具体来说,我使用 Cloud Build 和 Docker 容器在部署 Node 应用程序之前对其进行转译。构建过程需要从 Artifact Registry 中拉取私有 NPM 包,但没有工作,因为它未经授权。

      工作解决方案

      1. 首先创建一个可以访问您需要的任何 GCP 服务的服务帐号。在我的例子中,我创建了artifact-registry-reader@<PROJECT>.iam.gserviceaccount.com,并授予它作为“工件注册表阅读器”访问工件注册表存储库的权限。在您的情况下,您将授予它访问该存储桶的权限。

      2. 编辑新创建的服务帐户并在权限下将您的 Cloud Builder 服务帐户 (<PROJECT_ID>@cloudbuild.gserviceaccount.com) 添加为委托人,并授予其“服务帐户令牌创建者”角色。

      3. 接下来,您的 cloudbuild.yaml 文件应如下所示:

      steps:
        # Step 1: Generate an Access Token and save it
        #
        # Here we call `gcloud auth print-access-token` to impersonate the service account 
        # we created above and to output a short-lived access token to the default volume 
        # `/workspace/access_token`.  This is accessible in subsequent steps.
        #
        - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
          args:
            - '-c'
            - >
              gcloud auth print-access-token --impersonate-service-account
              artifact-registry-reader@<PROJECT>.iam.gserviceaccount.com >
              /workspace/access_token
          entrypoint: sh
        # Step 2: Build our Docker container
        #
        # We build the Docker container passing the access token we generated in Step 1 as 
        # the `--build-arg` `TOKEN`.  It's then accessible within the Dockerfile using
        # `ARG TOKEN`
        #
        - name: gcr.io/cloud-builders/docker
          args:
            - '-c'
            - >
              docker build -t us-docker.pkg.dev/<PROJECT>/services/frontend:latest
              --build-arg TOKEN=$(cat /workspace/access_token) -f
              ./docker/prod/Dockerfile . &&
      
              docker push us-docker.pkg.dev/<PROJECT>/services/frontend
          entrypoint: sh
      
      1. 下一步特定于 Artifact Registry 中的私有 npm 包,但我创建了一个包含以下内容的部分 .npmrc 文件(缺少 :_authToken 行):
      @<NAMESPACE>:registry=https://us-npm.pkg.dev/<PROJECT>/npm/
      //us-npm.pkg.dev/<PROJECT>/npm/:username=oauth2accesstoken
      //us-npm.pkg.dev/<PROJECT>/npm/:email=artifact-registry-reader@<PROJECT>.iam.gserviceaccount.com
      //us-npm.pkg.dev/<PROJECT>/npm/:always-auth=true
      
      1. 最后,我的 Dockerfile 使用铸造令牌更新我的 .npmrc 文件,使其能够从 Artifact Registry 中提取私有 npm 包。
      ARG NODE_IMAGE=node:17.2-alpine
      
      FROM ${NODE_IMAGE} as base
      
      ENV APP_PORT=8080
      
      ENV WORKDIR=/usr/src/app
      ENV NODE_ENV=production
      
      FROM base AS builder
      
      # Create our WORKDIR
      RUN mkdir -p ${WORKDIR}
      
      # Set the current working directory
      WORKDIR ${WORKDIR}
      
      # Copy the files we need
      COPY --chown=node:node package.json ./
      COPY --chown=node:node ts*.json ./
      COPY --chown=node:node .npmrc ./
      COPY --chown=node:node src ./src
      
      #######################
      # MAGIC HAPPENS HERE
      # Append our access token to the .npmrc file and the container will now be 
      # authorized to download packages from the Artifact Registry
      # 
      # IMPORTANT! Declare the TOKEN build arg so that it's accessible
      #######################
      
      ARG TOKEN
      RUN echo "//us-npm.pkg.dev/<PROJECT>/npm/:_authToken=\"$TOKEN\"" >> .npmrc
      
      RUN npm install
      
      RUN npm run build
      
      EXPOSE ${APP_PORT}/tcp
      
      CMD ["cd", "${WORKDIR}"]
      ENTRYPOINT ["npm", "run", "start"]
      

      显然,在您的情况下,您将使用 GCS 以不同的方式使用访问令牌进行身份验证,但整体概念应该很好地转化为任何类似情况。

      【讨论】:

        猜你喜欢
        • 2021-10-21
        • 2020-09-06
        • 2015-05-31
        • 2020-07-20
        • 2021-07-15
        • 1970-01-01
        • 1970-01-01
        • 2011-04-30
        • 1970-01-01
        相关资源
        最近更新 更多