如何在不使用密钥的情况下将 GitHub 操作与 AWS 部署连接?

Posted

技术标签:

【中文标题】如何在不使用密钥的情况下将 GitHub 操作与 AWS 部署连接?【英文标题】:How can I connect GitHub actions with AWS deployments without using a secret key? 【发布时间】:2021-11-13 12:30:20 【问题描述】:

我希望能够使用 GitHub Actions 来通过 AWS 部署资源,但无需使用硬编码用户。

我知道可以创建具有固定凭据的 IAM 用户,并且可以将其导出到 GitHub Secrets,但这意味着如果密钥泄露,我手头会有很大的问题,而轮换此类密钥具有挑战性如果忘记了。

有什么方法可以启用无密码身份验证流程以将代码部署到 AWS?

【问题讨论】:

【参考方案1】:

是的,现在 GitHub 可能已经发布了他们的 Open ID Connector for use with GitHub Actions。您可以将 Open ID 连接器配置为 AWS 中的身份提供者,然后将其用作您希望启用的任何角色的访问点。然后,您可以将操作配置为使用在作业期间获取的凭据,当作业完成时,凭据会自动撤销。

要在 AWS 中进行设置,您需要使用 instructions at AWS 或使用类似于以下内容的 Terraform 文件创建 Open Identity Connect 提供程序:

resource "aws_iam_openid_connect_provider" "github" 
  url = "https://token.actions.githubusercontent.com"
  client_id_list = [
    // original value "sigstore",
    "sts.amazonaws.com", // Used by aws-actions/configure-aws-credentials
  ]
  thumbprint_list = [
    // original value "a031c46782e6e6c662c2c87c76da9aa62ccabd8e",
    "6938fd4d98bab03faadb97b34396831e3780aea1",
  ]

客户 ID 列表是用于访问此内容的“受众”——您可以对其进行更改,前提是您在所有正确的位置进行更改。指纹是 Open ID 连接器的哈希/证书,6938...aea1 是 GitHub Actions 当前使用的指纹——您可以通过 following AWS' instructions 计算/验证该值。 thumbprint_list 最多可以容纳 5 个值,因此可以在提前提供新版本时附加它们,同时继续使用旧版本。

如果您对这个神奇值的来源感兴趣,可以在How can I calculate the thumbprint of an OpenID Connect server? 找到

启用身份提供者后,您可以使用它来创建一个或多个自定义角色(替换为:

data "aws_caller_identity" "current" 
resource "aws_iam_role" "github_alblue" 
  name = "GitHubAlBlue"
  assume_role_policy = jsonencode(
    Version = "2012-10-17",
    Statement = [
      Action = "sts:AssumeRoleWithWebIdentity"
      Effect = "Allow"
      Principal = 
        Federated = "arn:aws:iam::$data.aws_caller_identity.current.account_id:oidc-provider/token.actions.githubusercontent.com"
      
      Condition = 
        StringLike = 
          "token.actions.githubusercontent.com:aud" :  ["sts.amazonaws.com" ],
          "token.actions.githubusercontent.com:sub" : "repo:alblue/*"
        
      
    ]
  )

您可以根据需要创建任意数量的不同角色,甚至可以按受众(例如“生产”、“开发”)将它们分开。如果该帐户信任 OpenID 连接器的受众,那么您就可以开始了。 (您可以使用它来确保开发帐户中的 OpenID 连接器不信任生产帐户中的角色,反之亦然。)例如,您可以拥有一个只读角色来执行terraform validate,然后terraform apply 的另一个角色。

主题是从 GitHub 传递的,但看起来像:

repo:<organization>/<repository>:ref:refs/heads/<branch>

以后可能会出现不同的格式。例如,如果您使用 :ref:refs/pulls/*,您可以拥有专门针对 PR 的操作/角色,并为 :ref:refs/heads/production/* 拥有另一个角色。

最后一步是将您的 GitHub Actions 配置为使用从 AWS/OpenID Connect 返回的令牌:

标准方式

jobs:
  terraform-validate:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Configure AWS credentials from Test account
        uses: aws-actions/configure-aws-credentials@master
        with:
          role-to-assume: arn:aws:iam::<accountid>:role/GitHubAlBlue
          aws-region: us-east-1
      - name: Display Identity
        run: aws sts get-caller-identity

手动方式

幕后实际发生的事情是这样的:

jobs:
  terraform-validate:
    runs-on: ubuntu-latest
    env:
      AWS_WEB_IDENTITY_TOKEN_FILE: .git/aws.web.identity.token.file
      AWS_DEFAULT_REGION: eu-west-2
      AWS_ROLE_ARN: arn:aws:iam::<accountid>:role/GitHubAlBlue
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Configure AWS
        run: |
          sleep 3 # Need to have a delay to acquire this
          curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
            "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com" \
            | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
          aws sts get-caller-identity

您需要确保您的 AWS_ROLE_ARN 与您的 AWS 账户中定义的相同,并且受众与 OpenID Connect 和角色名称所接受的受众相同。

本质上,在作业开始和令牌的有效性之间存在竞争条件,直到 GitHub 确认作业已经开始之后才会出现;如果 AWS_WEB_IDENITY_TOKEN_FILE 的大小小于 10 个字符,则可能是一个错误,并且 sleep/spinning 会在之后为您获取值。

AWS_WEB_IDENTITY_TOKEN_FILE 的名称并不重要,只要一致即可。如果您使用的是 docker 容器,则将其存储在例如/tmp 意味着它在任何正在运行的容器中都不可用。如果您将它放在工作区中的.git 下,那么 git 不仅会忽略它(如果您正在执行任何哈希计算),而且它还会出现在您稍后执行的任何其他 docker run 操作中。

您可能希望配置您的角色,以限制所用期限的有效性;一旦您拥有 Web 令牌,它在作业结束前一直有效,但请求的令牌的生命周期为 15 分钟,因此运行时间较长的作业可能会暴露它。

GitHub 很可能会在不久的将来发布一篇关于如何配置/使用它的博文。以上信息的灵感来自https://awsteele.com/blog/2021/09/15/aws-federation-comes-to-github-actions.html,如果您喜欢的话,他会在 CloudFormation 模板中提供一些示例。

更新 GitHub(不小心)changed their thumbprint,示例已更新。有关更多信息,请参阅。新的指纹是 6938fd4d98bab03faadb97b34396831e3780aea1,但 IAM OpenID 连接器中可能有多个指纹。

【讨论】:

我开始在这个问题中添加有关如何计算指纹的信息,但它过于详细,可能会劝阻人们阅读它,所以我将它作为另一个问题添加到***.com/questions/69247498/… 您能否阐明 OIDC 提供程序中 client_id_list 的可能值?我看到 Aidan 使用了 repo 名称(对我有用),而您使用了“githubactions”。我想将其范围限定为 GitHub 帐户,就像我对我的角色的信任策略所做的那样。 问题出在 OIDC 提供商的 client_id_list 上。必须指定(至少在 TF 资源中)并且必须与受众匹配。如果您不指定“sigstore”的受众,它也将设置为 HTTPS 存储库 URL。所以看起来选择是(1)不指定受众,在你的client_id_list中保留一个repos列表,并在OIDC级别过滤,或者(2)使用“sigstore”作为受众,将“sigstore”添加到client_id_list,并且不要在 OIDC 级别进行过滤。无论哪种方式,您都可以按照您的说明过滤信任策略。可能值得在答案中添加其中一些细节。 ACTIONS_ID_TOKEN* 变量由 GitHub Actions 运行程序提供。 GitHub issue 更新后,client_id_list 和 iam_role 中也不再需要 sigstore。 GHActions 任务也不需要audience: sigstore【参考方案2】:

Github 最近更新了他们的证书链,指纹从上面提到的a031c46782e6e6c662c2c87c76da9aa62ccabd8e 变成了6938fd4d98bab03faadb97b34396831e3780aea1

Github 问题:https://github.com/aws-actions/configure-aws-credentials/issues/357

【讨论】:

谢谢,已更新示例。【参考方案3】:

出于某种原因,我不断收到 AlBlue 提供的答案:

"message":"Can't issue ID_TOKEN for Audience 'githubactions'。"

部署this post 中提供的堆栈确实有​​效。

【讨论】:

这可能应该是对现有答案的评论而不是新答案,但这看起来您的工作在工作配置中没有“权限”部分。 请在您的答案中包含链接中的相关信息。链接的内容将来可能会发生变化,如果您的答案不再有用。 感谢@AlBlue,但我不能,因为我为此创建了一个 *** 帐户。我的工作具有相同的权限。即使使用 cfn oidc 提供程序和角色,也可以。

以上是关于如何在不使用密钥的情况下将 GitHub 操作与 AWS 部署连接?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用数据框的情况下将一行分解为多行?

如何在不泄露敏感信息的情况下将 Node-Red 推送到 GitHub?

如何在不包含节点模块文件夹的情况下将我的 React 项目上传到 GitHub [重复]

如何在不公开 API 密钥的情况下发出 POST 请求?

如何在不使用界面生成器的情况下将视图与控制器分离

如何在不创建 Mongoose 模型的情况下将 GraphQL 与 Mongoose 和 MongoDB 一起使用