こんにちは。みらい翻訳のクラウド AI 翻訳サービス MiraiTranslator 開発チーム SRE の jeff です。
MiraiTranslator はサービスを AWS に構築しており、CI の一部に Github Actions を使用しています。少し前になりますが Github Actions で OIDC(OpenID Connect)認証ができるようになりました。これまで CI で AWS 上のリソースを参照・更新するときには基本的に IAM User のクレデンシャルを Github のシークレット登録し、それを使う形で認証を得ていました。
https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#requesting-the-access-tokendocs.github.com
今回の OIDC 認証対応でクレデンシャルを管理から解放され、IAM ロールと ID プロバイダーの設定をしておけば IAM User より気軽に、また柔軟に認証することができるようになりました。
実際に OIDC 認証を試してみて簡単な tips を記事に書いていこうと思います。
AWS 側の設定
AWS の ID プロバイダ設定とそれを信頼関係に設定した IAM ロールを作成します。
ID プロバイダ
以下 terraform 形式のコードです。
resource "aws_iam_openid_connect_provider" "github_actions_oidc" { url = "https://token.actions.githubusercontent.com" client_id_list = [ "sts.amazonaws.com" ] thumbprint_list = [ "6938fd4d98bab03faadb97b34396831e3780aea1" ] }
画面から作成する場合は AWS マネジメントコンソールで IAM 管理画面を開き [ID プロバイダ] → [プロバイダを追加] で以下の情報を入力して作成します。
プロバイダのタイプ: OpenID Connect プロバイダの URL: https://token.actions.githubusercontent.com # プロバイダの URL 入力後に [サムプリントを取得] をクリック 対象者: sts.amazonaws.com
「対象者」については 公式 action を使用する場合は sts.amazonaws.com
を指定する必要があります。
こちら のように自前で OIDC 認証したい場合は https://github.com/{オーガニゼーション or ユーザー名}
を指定します。両方とも設定することも可能です。
IAM ロール
以下 terraform 形式のコードです。
resource "aws_iam_role" "test-githubactions-role" { name = "test-githubactions-role" assume_role_policy = jsonencode({ statement { sid = "" effect = "Allow" actions = [ "sts:AssumeRoleWithWebIdentity" ] principals { type = "Federated" identifiers = [ aws_iam_openid_connect_provider.github_actions_oidc.arn ] } condition { test = "StringLike" variable = "token.actions.githubusercontent.com:sub" values = [ "repo:org/repo:*" ] } } }) }
画面から作成する場合は AWS マネジメントコンソールで IAM 管理画面を開き [ロール] → [ロールを作成] で以下の情報を入力して作成します。
信頼されたエンティティの種類を選択: ウェブ ID ID プロバイダー: token.actions.githubusercontent.com:aud Audience: sts.amazonaws.com
画面から作成した場合は IAM ロールの信頼関係の条件に自動的に Audience が設定されてしまいます。このままだと認証時に失敗してしまうので、ロールを作成したら作成したロールの管理画面を開き [信頼関係]タブ → [信頼関係の編集] で Condition の部分を修正します。
リポジトリ全体のアクションを許可したい場合は Condition 以下を↓のようにする(org は自身のオーガニゼーション or ユーザー名、repo は許可したいリポジトリ名を設定してください)
"Condition": { "StringLike": { "token.actions.githubusercontent.com:sub": "repo:org/repo:*" } }
特定のブランチを許可したい場合は以下のようにします(branch は認証を許可したいブランチ名を設定してください)
"Condition": { "StringEquals": { "token.actions.githubusercontent.com:sub": "repo:org/repo:ref:refs/heads/branch" } }
Condition は指定しなくても認証は通ります。 ですが IAM ロールを使い回すのはリポジトリごとに必要最低限のポリシーを与えられなかったり、あるリポジトリのために付与したポリシーが他のリポジトリに影響して CI が上手く動かなくなったりするなど、セキュリティ的にもよろしくありませんし思わぬバグを生む可能性もあります。 そのため Condition で最低でもリポジトリを絞って1リポジトリ1ロールで運用する方が良いと考えます。
Github Actions 設定
IAM ロールを作成したら適当なポリシーをロールに設定し、 Github Actions で実際に試してみましょう。
作成した IAM ロールに S3 の Read ポリシーを付けると aws s3 ls
でバケットリストが取れるかと思います。
name: workflow on: push: branches: - main jobs: build: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - name: checkout repo uses: actions/checkout@v2 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-region: ap-northeast-1 role-to-assume: # {IAM ロールARN を指定} role-session-name: ${{ github.sha }} - name: List s3 bucket run: | aws s3 ls
Github Actions で気にするのが IAM ロールだけなのは素晴らしいですね。
一時的な認証でプロファイル付きで awscli を使う
弊社であったケースで、一部ツールに awscli のプロファイルを指定して CI で使用しているものがあります。 OIDC 認証の場合以下のような形でプロファイル指定できるようにしました。
name: workflow on: push: branches: - main jobs: build: runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - name: checkout repo uses: actions/checkout@v2 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-region: ap-northeast-1 role-to-assume: # {IAM ロールARN を指定} role-session-name: ${{ github.sha }} - name: Set awscli credential run: | mkdir -p ~/.aws echo "[profile]" >> ~/.aws/credentials echo "aws_access_key_id = ${{ env.AWS_ACCESS_KEY_ID }}" >> ~/.aws/credentials echo "aws_secret_access_key = ${{ env.AWS_SECRET_ACCESS_KEY }}" >> ~/.aws/credentials echo "aws_session_token = ${{ env.AWS_SESSION_TOKEN }}" >> ~/.aws/credentials - name: Set awscli config run: | echo "[profile]" >> ~/.aws/config echo "region = ${{ env. AWS_REGION }}" >> ~/.aws/config - name: List s3 bucket run: | aws s3 ls --profile profile
aws-actions/configure-aws-credentials
を使うと GITHUB_ENV
に自動的に AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN
が登録されます。しかも内部的にマスクしてくれてます。
これを awscli で参照するクレデンシャル設定ファイルに書き込みます。一時的な認証のため aws_session_token
の指定も必須となります。
echo "[profile]" >> ~/.aws/credentials echo "aws_access_key_id = ${{ env.AWS_ACCESS_KEY_ID }}" >> ~/.aws/credentials echo "aws_secret_access_key = ${{ env.AWS_SECRET_ACCESS_KEY }}" >> ~/.aws/credentials echo "aws_session_token = ${{ env.AWS_SESSION_TOKEN }}" >> ~/.aws/credentials
リージョンを config に設定しないとコマンド実行時にエラーになるのでこちらも忘れずに設定します(awscli 使用時に --region
を指定しても良いです)。
echo "[profile]" >> ~/.aws/config echo "region = ${{ env. AWS_REGION }}" >> ~/.aws/config
以上の設定で --profile
を指定して aws コマンドを実行することができるようになります。
プロファイル名は環境に合わせて指定してください。
aws s3 ls --profile profile
おまけ
CircleCI も近々 OpenID Connet に対応するそうです。 MiraiTranslator では一部 CircleCI も使用しているため AWS を呼び出している部分は OIDC に変えて IAM ユーザークレデンシャルを撲滅したいと思います。
みらい翻訳ではSREを募集しています
デプロイ改善に興味がある方、その他運用改善などSREに興味がある方を募集しております。 ご興味がおありの方は下記のリンクからご応募・お問い合わせをお待ちしております。