Push container images more securely with GitHub Actions

DevOps

On 10/27/2021, OpenID Connect (hereafter OIDC) support was officially announced in Github Actions.

Originally, IAM User’s confidential information (access key & secret key) was used to build & push container images in Github Actions, but by using IAM User’s confidential information, it is possible to accidentally push confidential information to the Github repository. Therefore, I would like to use temporary credentials to access and manipulate AWS resources by the OICD specification.

Configuration in AWS
First, create some roles in IAM to access AWS with OIDC from Github Actions.

You can also create them from the AWS console, but I would like to create AWS resources in Terraform to manage the created resources.

You can apply the following Terraform tf file to create the AWS resources you need at once.

Setup in AWS

First, we will create some IAM roles, etc. so that we can access AWS with OIDC from Github Actions.

You can also create them from the AWS console, but we would like to create AWS resources in Terraform to manage the resources we have created.

You can apply the following Terraform tf file to create the AWS resources you need at once.

# ----- GitHub Action -----
##########################
# IAM identity providers (Register an OIDC provider with AWS provided by Github)
##########################
# Needed to calculate the thumbprint of the OIDC's ID propider in GitHub Actions
data "http" "github_actions_openid_configuration" {
  url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration"
}

# Needed to calculate the thumbprint of the OIDC's ID propider in GitHub Actions
data "tls_certificate" "github_actions" {
  url = jsondecode(data.http.github_actions_openid_configuration.body).jwks_uri
}

resource "aws_iam_openid_connect_provider" "github_oidc" {
  url = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  # https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html
  thumbprint_list = [data.tls_certificate.github_actions.certificates[0].sha1_fingerprint]
}

##########################
# IAM Role (Create an IAM role that registers a trust relationship and issues access tokens to temporary AWS resources)
##########################
data "aws_iam_policy_document" "github_actions_assume_role_policy" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]
    principals {
      type       = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github_oidc.arn]
    }

    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = ["repo:【SampleOrg/SampleRepo(※Please change according to your environment.)】:*"]
    }
  }
}

resource "aws_iam_role" "github_actions" {
  name               = "iam_role_for_github_actions"
  assume_role_policy = data.aws_iam_policy_document.github_actions_assume_role_policy.json
}

##########################
# IAM Policy (Define the necessary permissions to push container images to AWS ECR as a policy)
##########################
data "aws_iam_policy_document" "github_actions_resource_role_policy" {
  statement {
    actions = [
      "ecr:BatchCheckLayerAvailability",
      "ecr:PutImage",
      "ecr:InitiateLayerUpload",
      "ecr:UploadLayerPart",
      "ecr:CompleteLayerUpload",
      "ecr:GetAuthorizationToken"
    ]
    resources = ["*"]
    effect    = "Allow"
  }
}

resource "aws_iam_policy" "github_actions" {
  name        = "iam_policy_for_github_actions"
  path        = "/"
  description = "IAM Policy for GitHub Actions"
  policy      = data.aws_iam_policy_document.github_actions_resource_role_policy.json
}

# Associate the created IAM roles with IAM policies
resource "aws_iam_role_policy_attachment" "github_actions" {
  role       = aws_iam_role.github_actions.name
  policy_arn = aws_iam_policy.github_actions.arn
}
# ----- GitHub Action -----

Set up Github Actions

Create a workflow to build & push a container image when you push a tag in Github Actions.

As a prerequisite, set the following in Secrets of Github Actions.

AWS_ACCOUNT_ID:AWS account ID
AWS_ECR_REPOSITORY:Repository to push container images

name: Build Backend

on:
  push:
    tags:
      - v*

jobs:
  backend-build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
      actions: read

    steps:
      - uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1.6.1
        with:
          aws-region: ap-northeast-1
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/iam_role_for_github_actions
          role-session-name: iam_role_for_github_actions

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

      - name: Build app and push image to AWS ECR
        env:
          AWS_ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          AWS_ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPOSITORY }}
        run: |
          IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")
          docker build -t $AWS_ECR_REGISTRY/$AWS_ECR_REPOSITORY:$IMAGE_TAG .
          docker push $AWS_ECR_REGISTRY/$AWS_ECR_REPOSITORY:$IMAGE_TAG

Finally

Once the above Github Actions have been successfully executed, do the followings

1 Delete AWS credentials from Secrets in Github Actions
2 Delete the IAM user with the deleted credentials

Now you can use GitHub Actions more securely.

コメント

タイトルとURLをコピーしました