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!