⛑️

GitHub Actionsで使用するAWSクレデンシャルをより安全なOIDC方式(AWS IDプロバイダ)に切り替えた

2023/05/31に公開

はじめに

レスキューナウでは、Cloud環境へのデプロイにおいてGitHub Actionsを活用しています。

パイプラインの構築にはGitHubのSecretsにAWSのクレデンシャルとしてAWS_ACCESS_KEYAWS_SECRET_KEYを登録して使用するケースは実装も簡単でよく使われていると思います。

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

OIDCを使うメリットはこちらが参考になりました
https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#benefits-of-using-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で構築できるようにします

GitHubActionsOidcProvider
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を使用して認証情報を取得します

GetCallerIdentity
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_KEYAWS_SECRET_KEYを使用することなくAWSのAPIを呼び出すことができます。

実行結果

ワークフローを実行するとget-caller-identityから実行したロール情報が取得されていることが確認できました

まとめ

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

レスキューナウテックブログ

Discussion