我尝试创建使用GitHubActions OIDC进行Terraform工作流的方案

首先

2021年10月27日,官方宣布GitHub Actions现已支持OpenID Connect(OIDC)。

以前,為了從GitHubActions訪問各種雲端服務,需要將永久的認證信息保存在GitHub上,這帶來了洩漏的風險。引入OIDC的支援後,使得雲端供應商和GitHub之間能夠實現無縫認證。

我希望在本篇文章中总结关于通过GitHub Actions执行Terraform并访问AWS资源时的各种设置和验证结果。

※本文不涵盖OIDC的机制。如有兴趣了解的读者,以下的文章非常值得参考。

准备

    • Terraform実行用のGitHubActionsワークフローの作成

Hashicorpが提供するサンプルがあるので、こちらをGitHubリポジトリに作成しておきます。このワークフローは、mainブランチへのpushイベントを契機として、リポジトリのルートディレクトリ配下でterraformの各種コマンドを実行します。

tfファイルの作成

検証用として、AWSのデフォルトVPCの情報を取得するmain.tfを用意しておきます。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.63.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

data "aws_vpc" "default" {
  default = true
}

output "default_vpc_cidr_block" {
  value = data.aws_vpc.default.cidr_block
}

设置步骤

我们将分别使用AWS和GitHub Actions依次执行以下设置。

AWS側の設定

Cloudformationテンプレートの作成

GitHubActions側の設定

id-tokenの許可設定を追加
アクセストークン取得処理追加

AWS的设置。

创建Cloudformation模板

将在AWS控制台上创建IAM提供程序和IAM角色。在configure-aws-credentials仓库中,提供了Cloudformation模板的示例,可以利用它来创建资源。由于我们只需要获取VPC的信息,因此将为IAM角色分配AmazonVPCReadOnlyAccess策略。

Parameters:
  GitHubOrg:
    Type: String
  RepositoryName:
    Type: String
  OIDCProviderArn:
    Description: Arn for the GitHub OIDC Provider.
    Default: ""
    Type: String

Conditions:
  CreateOIDCProvider: !Equals 
    - !Ref OIDCProviderArn
    - ""

Resources:
  Role:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: !If 
                - CreateOIDCProvider
                - !Ref GithubOidc
                - !Ref OIDCProviderArn
            Condition:
              StringLike:
                token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
      # ロールに紐づけるIAMポリシーを設定
+     ManagedPolicyArns:
+       - arn:aws:iam::aws:policy/AmazonVPCReadOnlyAccess
  GithubOidc:
    Type: AWS::IAM::OIDCProvider
    Condition: CreateOIDCProvider
    Properties:
      Url: https://token.actions.githubusercontent.com
      ClientIdList: 
        - sts.amazonaws.com
      ThumbprintList:
        - a031c46782e6e6c662c2c87c76da9aa62ccabd8e

Outputs:
  Role:
    Value: !GetAtt Role.Arn

GitHub Actions的配置

为了在GitHub Actions中实现OIDC连接,需要授予获取OIDC令牌的权限,并在工作流中编写获取访问令牌的过程。

设定id-token的权限

通过指定”permissions”键,您可以更改GITHUB_TOKEN的默认权限。通过以下描述,您可以获取OIDC的ID令牌。

permissions:
  id-token: write

新增获取访问令牌的处理方法。

通过使用aws-actions/configure-aws-credentials操作,从GitHub OIDC提供程序接收JWT并请求AWS访问令牌。在操作参数中指定以下两个参数。

role-to-assume: Cloudformationで作成されたIAMロールのARN

aws-region: AWSリージョン名

请查阅此处,以了解其他选项参数的具体操作方式。

- name: configure aws credentials
  uses: aws-actions/configure-aws-credentials@v1
  with:
    role-to-assume: arn:aws:iam::123456789012:role/OIDCTest-Role-XXXXXXXXXXXXX
    aws-region: ap-northeast-1

随着2021年11月23日的v1.6.0发布,configure-aws-credentials已被附加上v1标签。GitHub的官方文档中明确指出可以使用分支指定(@master),但也可以使用标签指定(@v1)。由于分支指定可能会受到未预期的版本更新的影响,因此我认为最好使用标签指定。

修改Terraform示例工作流程的内容。

在创建GitHub Actions工作流程时,将上述两点添加到创建的工作流程中。修正后的工作流程如下所示。

Terraform执行用的GitHub Actions工作流程terraform.yml
# 这个工作流程安装最新版本的Terraform CLI,并配置Terraform CLI配置文件
# 使用一个API令牌来连接Terraform Cloud (app.terraform.io)。在拉取请求事件时,此工作流程将运行
# `terraform init`,`terraform fmt`,和`terraform plan`(通过Terraform Cloud进行规划)。在推送事件到主分支时
# 将会执行`terraform apply`。
#
# 有关`hashicorp/setup-terraform`的文档位于这里: https://github.com/hashicorp/setup-terraform
#
# 要使用此工作流程,您需要完成以下设置步骤。
#
# 1. 在该存储库的根目录下创建一个`main.tf`文件,其中包含`remote`后端和一个或多个资源定义。
# 示例 `main.tf`:
# # `remote`后端的配置。
# terraform {
# backend “remote” {
# # 您的Terraform Cloud组织的名称。
# organization = “example-organization”
#
# # 存储Terraform状态文件的Terraform Cloud工作区的名称。
# workspaces {
# name = “example-workspace”
# }
# }
# }
#
# # 一个没有任何操作的示例资源。
# resource “null_resource” “example” {
# triggers = {
# value = “一个没有任何操作的示例资源!”
# }
# }
#
#
# 2. 生成一个Terraform Cloud用户API令牌,并将其作为GitHub机密(例如TF_API_TOKEN)存储在该存储库上。
# 文档:
# – https://www.terraform.io/docs/cloud/users-teams-organizations/api-tokens.html
# – https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets
#
# 3. 在步骤中引用GitHub机密,使用`hashicorp/setup-terraform` GitHub Action。
# 示例:
# – name: 配置Terraform
# uses: hashicorp/setup-terraform@v1
# with:
# cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}

name: ‘Terraform’

on:
push:
branches:
– main

jobs:
terraform:
name: ‘Terraform’
runs-on: ubuntu-latest
environment: production

# 添加id-token的写入权限
+ permissions:
+ id-token: write

# 不论GitHub Actions runner是ubuntu-latest,macos-latest还是windows-latest,都使用Bash shell
defaults:
run:
shell: bash

steps:
# 检出存储库到GitHub Actions runner
– name: 检出
uses: actions/checkout@v2

# 安装最新版本的Terraform CLI,并使用Terraform Cloud用户API令牌配置Terraform CLI配置文件
– name: 配置Terraform
uses: hashicorp/setup-terraform@v1
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}

# 添加获取访问令牌的步骤
+ – name: 配置AWS凭证
+ uses: aws-actions/configure-aws-credentials@v1
+ with:
+ role-to-assume: arn:aws:iam::123456789012:role/OIDCTest-Role-XXXXXXXXXXXXX
+ aws-region: ap-northeast-1

# 初始化Terraform工作目录(新建或现有):创建初始文件,加载任何远程状态,下载模块等。
– name: Terraform初始化
run: terraform init

# 检查所有Terraform配置文件是否符合规范格式
– name: Terraform格式化
run: terraform fmt -check

# 为Terraform生成执行计划
– name: Terraform计划
run: terraform plan

# 在推送到主分支时,根据Terraform配置文件构建或更改基础架构
# 注意:建议在存储库中设置所需的”strict”状态检查,用于”Terraform Cloud”。有关更多信息,请参阅关于”strict”所需状态检查的文档:https://help.github.com/en/github/administering-a-repository/types-of-required-status-checks
– name: Terraform应用
if: github.ref == ‘refs/heads/main’ && github.event_name == ‘push’
run: terraform apply -auto-approve

执行Terraform

将准备好的main.tf推送到GitHub仓库的main分支。这将触发已创建的GitHub Actions工作流程执行。

执行结果

只提取了Terraform Apply步骤,但我们可以看到环境变量中已经设置了AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY和AWS_SESSION_TOKEN,并且成功获取了默认VPC的CIDR块信息并进行了正确的输出。

image.png

总结

我创建了一个使用GitHub Actions工作流的Terraform执行流程,其中包含了OIDC集成处理。希望对考虑使用Terraform创建AWS资源环境的人有所帮助。