Google Cloud Build中的应用程序默认凭据

9

在我的代码中,我尝试从与Cloud Build相关的服务帐户收集应用程序默认凭据:

from google.auth import default

credentials, project_id = default()

这在我的本地空间中运行良好,因为我已经适当地设置了环境变量 GOOGLE_APPLICATION_CREDENTIALS。但是,在Cloud Build内执行此行(通过构建配置中的测试步骤)时,会出现以下错误:

google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. 
Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. 
For more information, please see https://cloud.google.com/docs/authentication/getting-started

这令我感到困惑,因为根据文档所述:
默认情况下,Cloud Build使用一个特殊的服务帐号代表您执行构建。这个服务帐号称为Cloud Build服务帐号,并且在启用Google Cloud项目中的Cloud Build API时会自动创建。 点击此处阅读 如果环境变量GOOGLE_APPLICATION_CREDENTIALS未设置,则ADC将使用附加到运行代码的资源的服务帐号。 点击此处阅读 那么为什么默认调用无法访问Cloud Build服务帐号凭据呢?

你的依赖版本是什么?你能展示一下调用Python脚本的步骤吗? - guillaume blaquiere
3个回答

17

有一个技巧:你需要在Docker构建中定义要使用的网络。使用参数--network=cloudbuild,像这样:

steps:
  - name: gcr.io/cloud-builders/docker
    entrypoint: 'docker'
    args: 
      - build
      - '--no-cache'
      - '--network=cloudbuild'
      - '-t'
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
      - .
      - '-f' 
      - 'Dockerfile'
...

你可以在这里找到文档。

4
这也是一个不错的答案,在某些情况下甚至是更好的答案。 - John Hanley
2
这是一个救命稻草!起初我还有些怀疑,但它真的很神奇。这应该成为被接受的答案。 - Andy
1
我们正在使用kaniko,但它们甚至没有包含这个标志,所以这很糟糕。当涉及到CI/CD时,Google在工作负载身份方面真的没有考虑周全。 - Nathan McKaskle
同样适用于 buildx。 - Fucio
这对我来说很有用,可以构建一个使用firebase-admin来管理用户账户的nextjs应用程序。之前在执行next build命令时一直在"生成静态页面"这一步出错。 - undefined
显示剩余2条评论

1

应用程序默认凭据(ADC)定义了搜索凭据的方法。

Cloud Build VM实例通过对169.254.169.254进行网络调用从元数据中获取凭据。您正在运行的容器无法访问主机的网络,这意味着在Docker容器内运行的代码无法访问主机的元数据。由于容器内没有其他凭据,因此ADC会出现“无法自动确定凭据”的错误消息。

解决方案:提供可在Docker容器内访问的凭据。

一种方法是将服务帐户JSON密钥文件存储在Cloud Storage中。然后配置Cloud Build以下载该文件。配置Dockerfile将文件复制到镜像中。

Cloud Build YAML:

- name: gcr.io/cloud-builders/gsutil
  args: ['cp', 'gs://bucketname/path/service-account.json', 'service-account.json']

Dockerfile:

COPY ./service-account.json /path/service-account.json

Google提供了其他服务,例如Secret Manager,也可以使用。我更喜欢Cloud Storage,因为存储和更新凭据的便利性提供了易于文档化和管理的方式。

在考虑安全、特权分离和管理问题时,Google Cloud提供了几种方法。

另一种方法是Guillaume Blaquiere发布的方法。

在安全性较低且开发人员被授予广泛权限(IAM角色)的环境中,Guillaume的答案简单易行。在严格控制安全的环境中,授予Cloud Build广泛的权限是一种安全风险。

安全通常是安全、实现和易用性之间的权衡。授予IAM角色需要仔细考虑如何使用权限以及由谁/何人使用。


1
嘿,我的朋友,每当一个解决方案使用服务账户密钥文件时,我总是持反对意见,这让我感到恶心!我已经与Cloud Build团队讨论了这个问题,并且他们已经为我提供了解决方案(在我的答案中提供),并且已经进行了奇怪的记录。无论如何,它运行得非常好! - guillaume blaquiere
@guillaumeblaquiere - 由于容器是由Cloud Build构建的,使用服务帐户JSON密钥文件是安全的 - 甚至可能更安全,因为Cloud Build在其服务帐户中需要较少的权限。但是,您是正确的,服务帐户密钥文件需要知识和管理才能正确实施。通常在安全性、可行性和便利性之间存在权衡。很遗憾我们不能将答案结合起来。 - John Hanley
不,它不安全,它将其存储在Docker镜像层中。这不是我们想要的。想法是让cloudbuild自动充当Dockerfile中脚本化的任何操作(例如ruby的bundle install,其中初始化了secrets manager)中的GOOGLE_APPLICATION_CREDENTIALS。如果Google无法解决CI/CD问题,则使用工作负载身份的整个目的将在单个步骤中失败。不幸的是,我们使用的是不包括Docker标志的kaniko。 - Nathan McKaskle
@NathanMcKaskle - 正如我的答案所解释的那样,有几种方法。关键是一些API需要私钥,而默认凭据可能无法获得。关于Docker层中的凭据,可以通过多阶段构建轻松解决。关键是要知道可用的解决方案,然后选择符合您目标的解决方案。没有一个解决方案适用于所有用例。 - John Hanley

0

Cloud Build可以通过加密您的密钥并在构建时使用Cloud KMS进行解密,来保护构建过程的安全性

设置加密密钥后,您可以通过cloudbuild.yaml中的构建步骤来检索它

steps:
- name: gcr.io/cloud-builders/gcloud
  args:
  - kms
  - decrypt
  - "--ciphertext-file=ENCRYPTED_PASSWORD_FILE"
  - "--plaintext-file=PLAINTEXT_PASSWORD_FILE"
  - "--location=global"
  - "--keyring=KEYRING_NAME"
  - "--key=KEY_NAME"
- name: gcr.io/cloud-builders/docker
  entrypoint: bash
  args:
  - "-c"
  - docker login --username=DOCKER_USERNAME --password-stdin < PLAINTEXT_PASSWORD_FILE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接