はじめに
GitHub Actions から Terraform で AWS を操作する CD を組みました。CI に AWS のアクセスキー(長期キー)を Secrets で置くのは避けたかったので、OIDC で一時的な認証にする方針です。
ここまでは公式どおりに進んで、鍵なしで AWS に入れるようになりました。ところが、apply の前に人間の承認をはさむために GitHub の Environment へ「承認者(required reviewers)」を設定しようとしたら——自分の名前を入れても候補に出てこない。これでしばらく止まりました。
先に結論:候補に出ないときは、プロフィールの表示名ではなく、GitHub の「ユーザー名(ログイン ID)」で検索してみる。私の環境ではこれで候補に出ました。
環境
- GitHub Actions(OIDC)
- Terraform(AWS プロバイダ)で
plan/applyを実行 - AWS IAM OIDC プロバイダ + ロール2つ(plan 用 / apply 用)
- リージョン: ap-northeast-1(東京)
設計:鍵を置かず、plan と apply を分ける
つまずきの前に、土台だけ簡単に。長期キーを置かないために、AWS 側に GitHub の OIDC プロバイダを登録し、用途別に IAM ロールを2つ用意しました。
# OIDC プロバイダ(thumbprint は省略可=AWS が自動取得)
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
}
-
plan ロール:PR と main からの実行(
...:pull_requestと...:ref:refs/heads/main)だけ引き受けられる。権限は ReadOnlyAccess(読むだけ=壊せない)。 -
apply ロール:
prodEnvironment を参照する job からだけ引き受けられる。こちらに変更権限を持たせる。
信頼ポリシーは、aud(受け手)と sub(どの実行か)で絞ります(抜粋)。
# apply ロールの信頼条件(イメージ・現行の一般的な形式)
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:aud"
values = ["sts.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:<owner>/<repo>:environment:prod"]
}
補足として、この sub はジョブの実行文脈で形が変わります(GitHub 公式の例より)。
| ジョブの指定 |
sub の形 |
|---|---|
| ブランチ実行 | repo:<owner>/<repo>:ref:refs/heads/main |
| プルリクエスト | repo:<owner>/<repo>:pull_request |
environment: prod |
repo:<owner>/<repo>:environment:prod |
つまり、ジョブに environment: prod を付けて初めて sub が ...:environment:prod になり、apply ロールの信頼ポリシーと一致します。
ここで信頼ポリシーが直接見ているのは「承認されたか」そのものではなく、prod Environment を参照した job が発行した OIDC トークンかという点です。Environment 側の Required reviewers が通るまで、その job は実行や認証情報の取得へ進めません。だから結果として「承認されない限り apply ロールは使われない」という関門になります。その承認を担うのが、次の Required reviewers でした。
補足:
subの形式は、リポジトリによっては今後 owner/repository 部分が ID 付きになる(immutable subject claims)案内が GitHub から出ています。上の例は現行の一般的な形式として読んでください。
起きたこと:承認者に自分を選べない
GitHub のリポジトリ設定 → Environments → prod の Required reviewers に、自分を承認者として追加しようとしました。検索欄にプロフィールの表示名を入れたのですが、いくら打っても候補に出てきません。
「アカウントの権限が足りない?」「Environment の種類が違う?」と少し疑いましたが、原因はもっと単純でした。
原因:表示名とユーザー名は別物だった
GitHub のユーザーには、プロフィールに出る表示名と、**ログインに使うユーザー名(@で始まる ID)**の2つがあり、この2つは別物です。表示名は自由に変えられます。
私は表示名のつもりの文字列を入れていたので一致せず、候補に出ていませんでした。仕様として「検索は必ずユーザー名だけを見る」と断言はしませんが、私の環境では、表示名では出ず、ユーザー名で検索すると候補に出ました。
対処:ユーザー名で入れたら選べた
自分の GitHub の**ユーザー名(ログイン ID)**で検索し直したら、すぐ候補に出て、承認者に追加できました。これで「apply は承認者が承認してから動く」という関門が機能するようになりました。
設定後の流れはこうです。
PR を作成 → plan ロール(ReadOnly)で terraform plan
prod 環境へ apply → Required reviewers が承認するまで待機
承認 → apply ロールで terraform apply
鍵を1つも置かずに、しかも apply には人間の承認をはさむ——という形にできました。
いくつか補足です。
- 自分を承認者にする場合の注意:1人運用の学習用リポジトリでは自分を reviewer にして自分で承認できます。ただし Environment の Prevent self-review を有効にすると、workflow を起動した本人は承認できなくなるので注意。
- 複数人を登録しても「全員承認」ではない:Required reviewers は複数(最大6人/チーム)登録できますが、標準では登録者のうち1人の承認で先に進みます。
-
environment だけではブランチ制限にならない:
environment:prodのsubは標準形ではブランチ名を含みません。つまり信頼ポリシーで Environment を見ていても、それだけでは「main からの apply だけ」にはなりません。main に限定したいなら、Environment の deployment branch rules で main を許可対象にするか、workflow のon/ ジョブのifで別途縛ります。
学び
- CI から AWS に入るのに、長期キーを Secrets に置かなくていい(OIDC で一時認証。
id-token: writeが必要)。 - OIDC の
subは ジョブの実行文脈で形が変わる。environment:を付けると...:environment:<name>になる。 - 権限は用途で分ける:plan は ReadOnly、apply は
prodEnvironment を参照する job からのみ。audとsubで実行元を絞る。 - 信頼ポリシーが見ているのは「承認済みか」ではなく「その Environment を参照した job のトークンか」。承認は Environment 側の保護ルールが担保する。
-
environment:prodだけではブランチ制限にならない。main 限定は deployment branch rules か workflow 側で別途。 - GitHub の 表示名とユーザー名は別物。reviewer が候補に出ないときはユーザー名で検索してみる。
- 自分を reviewer にするなら Prevent self-review の有無に注意。複数登録しても1人の承認で進む。
おわりに
OIDC の設定よりも、最後の「承認者が選べない」で一番つまずきました😅 表示名とユーザー名の違いという、言われれば当たり前のところでしたが、同じく Environment の reviewer 設定で固まった人の助けになれば嬉しいです🙌
参考
- GitHub公式: Configuring OpenID Connect in Amazon Web Services
https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services - GitHub公式: About security hardening with OpenID Connect(example subject claims・immutable subject claims)
https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect - GitHub公式: OpenID Connect reference(subject claim の構成・カスタマイズ)
https://docs.github.com/actions/reference/openid-connect-reference - GitHub公式: Managing environments for deployment(Required reviewers / Prevent self-review / deployment branches)
https://docs.github.com/en/actions/deployment/targeting-different-environments/managing-environments-for-deployment