Traffine I/O

日本語

2022-09-05

GitHub ActionsでOIDCを介したAWS ECRイメージの更新

GitHub ActionsでOIDCを介したAWS ECRイメージの更新

現代のソフトウェア開発サイクルでは、CI/CD(Continuous Integration/Continuous Deployment)が重要な役割を果たしています。このプロセスの重要な側面の1つは、Amazon Elastic Container Registry(ECR)などのクラウドベースのリポジトリにDockerイメージをデプロイすることです。この記事では、GitHub ActionsとOpenID Connect(OIDC)プロトコルを使用してECRイメージをプッシュするプロセスについて詳しく説明します。

OIDCとは

GitHub Actionsのワークフローは、AWS、Google Cloud Platform(GCP)、またはAzureなどのクラウドプロバイダーにアクセスし、ソフトウェアをデプロイしたりクラウドサービスを利用したりするために使用されることがあります。これらの異なるプラットフォーム間の安全な通信を容易にするために、OpenID Connect(OIDC)が使用されます。

OIDCは、認証サーバーによって実行された認証に基づいてエンドユーザーのアイデンティティを検証するアイデンティティ層です。これにより、ワークフローの実行時にクレデンシャルを発行し、クラウドへのデプロイ時の認証に使用することが可能になります。これらの資格情報は一時的なものであり、永続的なアクセスキーを使用する場合と比較して、漏洩した場合の悪用のリスクを減らします。

2022年9月時点で、OIDCをサポートしているクラウドプロバイダーは以下のとおりです。

  • AWS
  • Azure
  • GCP
  • HashiCorp Vault

ソースコード

ディレクトリ構造

プロジェクトのディレクトリ構造は以下のように構成されています。

.
├── .github/workflows/deploy-ecr.yml
├── Dockerfile
└── terraform
    ├── variables.tf
    ├── iam.tf
    └── ecr.tf

Terraform

以下のコードは、OIDCプロバイダー、ロール、およびECRリポジトリを定義しています。

variables.tf
variable "env" {
  default = "dev"
}

variable "github_provider" {
  default = "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
}

variable "aws_account_id" {
  default = "123456789012"
}

variable "github_org" {
  default = "mycompany-inc"
}

variable "github_repo" {
  default = "my-repo"
}
iam.tf
resource "aws_iam_openid_connect_provider" "main" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

resource "aws_iam_role" "github_actions" {
  name = "${var.env}-github-actions"
  assume_role_policy = jsonencode(
    {
      "Version" = "2012-10-17"
      "Statement" = [
        {
          "Principal" : {
            "Federated" : "arn:aws:iam::${var.aws_account_id}:oidc-provider/token.actions.githubusercontent.com"
          },
          "Action" : [
            "sts:AssumeRoleWithWebIdentity",
          ],
          "Effect" = "Allow",
          "Condition" : {
            "StringLike" : {
              "token.actions.githubusercontent.com:aud" : "sts.amazonaws.com",
              "token.actions.githubusercontent.com:sub" : "repo:${var.github_org}/${var.github_repo}:*"
            }
          },
        }
      ]
    }
  )
}

resource "aws_iam_policy" "github_actions_policy" {
  name = "${var.env}-github-actions-policy"
  policy = jsonencode(
    {
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Sid" : "ImageUploader",
          "Action" : [
            "ecr:GetDownloadUrlForLayer",
            "ecr:BatchCheckLayerAvailability",
            "ecr:PutImage",
            "ecr:InitiateLayerUpload",
            "ecr:UploadLayerPart",
            "ecr:CompleteLayerUpload",
            "ecr:GetAuthorizationToken",
          ],
          "Effect"   = "Allow",
          "Resource" = "*"
        }
      ],
  })
}

resource "aws_iam_role_policy_attachment" "github_actions_ecr_policy_attachment" {
  policy_arn = aws_iam_policy.github_actions_policy.arn
  role       = aws_iam_role.github_actions.id
}

resource "aws_iam_role_policy_attachment" "github_actions_ecs_full_access" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonECS_FullAccess"
  role       = aws_iam_role.github_actions.id
}
ecr.tf
resource "aws_ecr_repository" "main" {
  name = "my-ecr-repo"
}

Github Actions

以下のシークレットをGitHubの「Settings」>「New repository secret」から登録します。

  • AWS_GA_ROLE_ARN(Terraformで定義されたaws_iam_role.github_actionsのARN)
  • AWS_ECR_REPO_NAME(Terraformで定義されたECRリポジトリ名)

Secret setting

そして、リポジトリ内の.github/workflows/deploy.ymlに以下のYMLファイルを記述します。

.github/workflows/deploy-ecr.yml
name: Deploy ECR Image

on:
  push:
    branches:
      - develop

permissions:
  id-token: write
  contents: read

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_GA_ROLE_ARN }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Build and push Docker image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY . --no-cache
          docker push $ECR_REGISTRY/$ECR_REPOSITORY

参考

https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services
https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-push.html
https://github.blog/changelog/2022-01-13-github-actions-update-on-oidc-based-deployments-to-aws/
https://go-journey.club/archives/17053
https://zenn.dev/yukin01/articles/github-actions-oidc-provider-terraform
https://book.st-hakky.com/docs/github-actions-oidc-for-ecr-and-ecs

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!