GitHub Actionsで使用するAWSクレデンシャルをより安全なOIDC方式(AWS IDプロバイダ)に切り替えた
はじめに
レスキューナウでは、Cloud環境へのデプロイにおいてGitHub Actionsを活用しています。
パイプラインの構築にはGitHubのSecretsにAWSのクレデンシャルとしてAWS_ACCESS_KEYとAWS_SECRET_KEYを登録して使用するケースは実装も簡単でよく使われていると思います。

しかし、この方法には長期間有効なAWSのクレデンシャル情報を保有し続けるという、セキュリティ上の懸念が存在するため、より安全な状態にするため、OIDC(OpenID Connect)を使用する方法に切り替えました。
OIDCを使うメリットはこちらが参考になりました
AWS IDプロバイダの作成

AWSコンソール画面を開き、左側のメニューから IDプロバイダを選択します
プロバイダを追加ボタンを押して プロバイダ設定画面を開きます
GitHubのドキュメントを参考にプロバイダのURLと対象者情報を入力します
プロバイダー URL の場合: https://token.actions.githubusercontent.com を使います
"Audience" の場合: 公式のアクションを使っている場合は、sts.amazonaws.com を使います。
ロールを作成する
AWSコンソール画面を開き、左側のメニューから ロールを選択します
ロールを作成を選択して カスタム信頼ポリシーを選択します
カスタム信頼ポリシーには以下のような情報を入力します
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::アカウントID:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:octo-org/octo-repo:*"
},
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}
Federatedフィールドには、先ほど作成したOIDCプロバイダのARN(Amazon Resource Name)を指定します。
Conditionフィールドでは、OIDCで検証する条件を指定します。GitHub公式の例では、2つの条件が指定されています。
token.actions.githubusercontent.com:subは、GitHubのリポジトリを特定するための条件です。GitHubActionsを実行するRepositoryを指定します
"octo-org/octo-repo"という名前のGitHubリポジトリに対してのみ認証を許可設定していて、この条件に一致しない場合は認証は拒否されます。
token.actions.githubusercontent.com:audは、トークンの発行先を検証するための条件です。ここでは、sts.amazonaws.comという値が指定されており、トークンがAWS Security Token Service (STS) によって発行されたものであることを確認しています。
この条件に一致しない場合は認証されません
このカスタム信頼ポリシーの設定により、GitHub Actionsからのリクエストが特定のGitHubリポジトリに関連付けられ、かつAWS STSによって発行されたトークンである場合にのみ、IAMロールへのアクセスが許可されます。
許可ポリシーの作成
今回は動作確認用にGetCallerIdentityを設定します
左側のメニューから ポリシーを選択します
stsを選択して読み取り項目にあるGetCallerIdentityを選択してください

許可を追加
作成したロールに許可ポリシーをアタッチします

GetCallerIdentity は呼出し元のIAMユーザーまたはロールの情報を返却します
作成
ロール名を設定してIAMロールを作成します
カスタム信頼ポリシーと許可ポリシーが正しいことを確認してください

作成されたロール情報を確認します

ここで確認できるARN情報をGitHubのSecret情報に登録してGitHubActionsから呼出します。
これでGetCallerIdentity の権限を持ったID プロバイダが作成できました
上記の手順をCloudFormationで実行する
本番/開発など色々な環境で用意する可能性があるので
上記のAWSコンソールで行った手順をCloudFormationで構築できるようにします
AWSTemplateFormatVersion: 2010-09-09
Parameters:
Thumbprint:
Type: String
Default: '6938fd4d98bab03faadb97b34396831e3780aea1'
Resources:
GitHubActionsOidcProvider:
Type: AWS::IAM::OIDCProvider
Properties:
Url: https://token.actions.githubusercontent.com
ClientIdList:
- sts.amazonaws.com
ThumbprintList:
- !Ref Thumbprint
RoleGitHubActions:
Type: AWS::IAM::Role
Properties:
RoleName: oidc-get-caller-Identity
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRoleWithWebIdentity
Principal:
Federated: !Sub arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com
Condition:
StringEquals:
token.actions.githubusercontent.com:aud: sts.amazonaws.com
StringLike:
token.actions.githubusercontent.com:sub: repo:octo-org/octo-repo:*
Policies:
- PolicyName: GetCallerIdentity
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- sts:GetCallerIdentity
Resource: '*'
Outputs:
Role:
Value: !GetAtt RoleGitHubActions.Arn
GitHubActionsに登録する
GitHubActionsのワークフローを設定します
GitHubActionsを実行したいRepositoryのSeacret情報に
secrets.AWS_ROLE_ARNとして、作成したロールのARNを登録します.

作成したAWSのIDプロバイダをconfigure-aws-credentialsを使用して認証情報を取得します
name: sts:GetCallerIdentity
on: workflow_dispatch
permissions:
id-token: write
contents: read
jobs:
get-caller-identity:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-1
- run: aws sts get-caller-identity
configure-aws-credentialsからAssumeRoleWithWebIdentityを呼出すことで
AWSから一時的な認証情報を取得しています、この機能により有効期限が長いAWS_ACCESS_KEYとAWS_SECRET_KEYを使用することなくAWSのAPIを呼び出すことができます。
実行結果
ワークフローを実行するとget-caller-identityから実行したロール情報が取得されていることが確認できました

まとめ
AWSのクレデンシャル情報の利用をやめて、OIDCを経由して一時的に認証することができました
実装としてはconfigure-aws-credentialsのrole-to-assumeにロールのARNを設定するだけで
OIDC の概要にに記載されている流れを実現できるのは非常に便利だと思います。
Discussion