はじめに
GitHub ActionsでOpenID Connectがサポートされましたね。
GitHub ActionsからAWSを操作するにあたって、MFA+外部IDでAssumeRoleを頑張ってましたが、
IAMユーザーの認証情報を持たせる必要がなくなるのでこれに切り替えていこうと思います。
設計方針
- GitHub OIDCプロバイダーはAWSアカウント毎に1つだけ作成する必要がある
- GitHub OIDCは1つであり、複数のIAMロールを引き受けることができるがGitHub Actionsで直接引き受けるIAMロールは1つとする
- GitHub ActionsでAWSを操作を行うためには、多段AssumeRoleさせAWSの操作権限を与える
- GitHub Actionsで引き受けるIAMロールはAWSを操作する権限を与えない(踏み台IAMロール)。
- 踏み台IAMロールで引き受けるAWS操作権限を持つIAMロールを作成する(操作用IAMロール)
- 操作用IAMロールには外部IDを設定する
- 踏み台IAMロール一時認証情報+外部IDを渡し操作用IAMロールを引き受ける
- 操作用IAMロール一時認証情報でAWS APIにリクエストする
図にするとこんな感じです
CloudFormation テンプレート
以下のサンプルを元に設計方針に沿って書き直しました。
AWSTemplateFormatVersion: 2010-09-09
Description: "GitHub Actions OIDC"
Parameters:
SystemPrefix:
Type: String
Default: "github-actions-oidc"
Env:
Type: String
Default: "stg"
AllowedValues:
- dev
- stg
- prod
Group:
Type: String
Default: "group-a"
AllowedValues:
- "group-a"
- "group-b"
GitHubOrgName:
Type: String
Default: org
OIDCProviderArn:
Description: Arn for the GitHub OIDC Provider.
Default: ""
Type: String
ExternalId:
Type: String
Description: "External ID"
Default: "example1234"
Conditions:
IsNotExistsOIDCProvider: !Equals
- !Ref OIDCProviderArn
- ""
Resources:
GitHubOIDC:
Type: AWS::IAM::OIDCProvider
Condition: IsNotExistsOIDCProvider
Properties:
ClientIdList:
- sts.amazonaws.com
Tags:
- Key: "Name"
Value: !Sub "${SystemPrefix}-${Env}-oidc"
- Key: "Env"
Value: !Ref Env
- Key: "Group"
Value: !Ref Group
ThumbprintList:
- a031c46782e6e6c662c2c87c76da9aa62ccabd8e
Url: https://token.actions.githubusercontent.com
BastionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRoleWithWebIdentity
Principal:
Federated: !If
- IsNotExistsOIDCProvider
- !Ref GitHubOIDC
- !Ref OIDCProviderArn
Condition:
StringEquals:
# audience
token.actions.githubusercontent.com:aud: sts.amazonaws.com
StringLike:
# repository
token.actions.githubusercontent.com:sub:
- !Sub repo:${GitHubOrgName}/example-github-actions:*
- !Sub repo:${GitHubOrgName}/example-github-actions-sub:*
Description: ""
# ManagedPolicyArns:
# - String
MaxSessionDuration: 3600
Path: "/github-actions/"
# PermissionsBoundary: String
Policies:
- PolicyName: assume-role-policy
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: Allow
Action:
- "sts:GetCallerIdentity"
Resource:
- "*"
-
Sid: "GitHubActionsAssumeRole"
Effect: Allow
Action:
- "sts:AssumeRole"
- "sts:TagSession"
Resource:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/${SystemPrefix}-${Env}-deploy-role"
RoleName: !Sub ${SystemPrefix}-${Env}-bastion-role
Tags:
- Key: "Name"
Value: !Sub "${SystemPrefix}-${Env}-bastion-role"
- Key: "Env"
Value: !Ref Env
- Key: "Group"
Value: !Ref Group
GitHubActionsDeployRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Sid: "AllowAssumeRole"
Effect: "Allow"
Action:
- "sts:AssumeRole"
Principal:
AWS: !GetAtt BastionRole.Arn
Condition:
StringEquals:
sts:ExternalId: !Ref ExternalId
-
Sid: "AllowPassSessionTags"
Effect: "Allow"
Action:
- "sts:TagSession"
Principal:
AWS: !GetAtt BastionRole.Arn
Description: "Allows Protected Execute AWS Access via GitHub Actions Access."
# ManagedPolicyArns:
# - arn:aws:iam::aws:policy/AdministratorAccess
MaxSessionDuration: 3600
Path: "/github-actions/"
# PermissionsBoundary: String
# Policies:
# - Policy
RoleName: !Sub "${SystemPrefix}-${Env}-deploy-role"
Tags:
- Key: "Name"
Value: !Sub "${SystemPrefix}-${Env}-deploy-role"
- Key: "Env"
Value: !Ref Env
- Key: "Group"
Value: !Ref Group
Outputs:
BastionRoleArn:
# Description: Information about the value
Value: !GetAtt BastionRole.Arn
Export:
Name: !Sub "${SystemPrefix}-${Env}-bastion-role-arn"
GitHubActionsDeployRoleArn:
# Description: Information about the value
Value: !GetAtt GitHubActionsDeployRole.Arn
Export:
Name: !Sub "${SystemPrefix}-${Env}-deploy-role-arn"
GitHub Actions Workflow サンプル
name: GitHub Actions
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@master
with:
aws-region: ap-northeast-1
role-to-assume: arn:aws:iam::{AccountID}:role/github-actions/github-actions-oidc-dev-bastion-role
- run: aws sts get-caller-identity
- name: Configure AWS Credentials2
uses: aws-actions/configure-aws-credentials@master
with:
aws-region: ap-northeast-1
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ env.AWS_SESSION_TOKEN }}
role-external-id: ${{ secrets.EXTERNAL_ID }}
role-to-assume: arn:aws:iam::{AccountID}:role/github-actions/github-actions-oidc-dev-deploy-role
role-duration-seconds: 900
- run: aws sts get-caller-identity
結果
Workflow dispatchで動作確認します。
それぞれの結果でAWSアカウント情報が取得できることを確認できました。
まとめ
GitHub Actionsで直接ロールを引き受けることなく、多段でAssumeRoleしてAWS APIにリクエストが確認できました。
MFA+外部IDでAssumeRoleを頑張ってましたが切り替えていこうかと思います。