GitHub ActionsでAWS SAMアプリケーションをデプロイするときの権限を考えてみた
AWS SAMアプリケーションをGitHub Actionsでデプロイする場合のIAM権限を考えたい
おのやんです。
みなさん、AWS SAMアプリケーションをGitHub Actionsでデプロイする場合にIAM権限をどうするか考えたことはありませんか?私はあります。
このIAM権限まわりを設定する機会がありましたので、今回紹介していきます。
アーキテクチャ
GitHub ActionsからSAMアプリケーションをデプロイする場合、GitHub Actions上でsam deploy
を実行します。またSAMアプリケーションデプロイ時には、内部でAWS CloudFormation(以下、CFn)を使ってAWSリソースを作成します。
GitHub Actionsが操作できる範囲は、AWS上で作成するOIDCプロバイダをPrincipalとしたIAMロールで制御できます。またCFnがスタックを作成する場合、CFnのサービスロールを使用して作成可能なリソースを制御できます。
したがって、次の2つのIAMロールを使えば、権限を分散したアクセス制御ができると考えました。
- GitHub ActionsからSAMの操作を行うのに必要な権限を設定したIAMロール(図中だと「OIDC用IAMロール」)
- CFnからAWSのリソースを作成するのに必要な権限を設定したIAMロール(図中だと「CloudFormation用サービスロール」)
OIDC用IAMロール
OIDC用IAMロールは、GitHub ActionsからSAMの操作を行うのに必要な権限を設定したIAMロールです。GitHub Actionsではsam deploy
などの操作を行うのみですので、基本はSAMデプロイ関係の権限をつけることになります。
今回のケースで必要な「SAMデプロイ関係の権限」は、公式ドキュメントで調べた限りですとAWSCloudFormationFullAccess
とAmazonS3FullAccess
です。
たとえば、サンプルの Hello World アプリケーションをデプロイするには、次の AWS 管理ポリシーで十分です。
- AWSCloudFormationFullAccess
- IAMFullAccess
- AWSLambda_FullAccess
- AmazonAPIGatewayAdministrator
- AmazonS3FullAccess
- AmazonEC2ContainerRegistryFullAccess
ですので、OIDC用IAMロールをCFnテンプレートで記述するとこんな感じになります。ポイントとしては次の点が挙げられます。
- マネージドポリシーとして
AWSCloudFormationFullAccess
とAmazonS3FullAccess
をつけている - CfnサービスロールをPassRoleする際、PassRoleの対象にできるAWSサービスをCFnに限定
AWSTemplateFormatVersion: 2010-09-09
Description: IAM Role for OIDC
Resources:
AWSTestGitHubActionsOICDRole:
Type: AWS::IAM::Role
Properties:
RoleName: aws-test-github-actions-oicd-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Federated: arn:aws:iam::xxxxxxxxxxxx:oidc-provider/token.actions.githubusercontent.com
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
token.actions.githubusercontent.com:aud: sts.amazonaws.com
StringLike:
token.actions.githubusercontent.com:sub: repo:aws-test-organization/aws-test-github-repository:*
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Policies:
- PolicyName: aws-test-github-actions-oicd-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- iam:PassRole
Resource: !GetAtt AWSTestCloudFormationServiceRole.Arn # 後述します
Condition:
StringEqualsIfExists:
iam:PassedToService: cloudformation.amazonaws.com
CloudFormation用サービスロール
CloudFormation用サービスロールは、CFnからAWSのリソースを作成するのに必要な権限を設定したIAMロールです。sam deploy
の実行役としてCFnが動作しますので、ここには構築最小となるAWSサービスについて一通り許可していくことになります。
AWSTemplateFormatVersion: 2010-09-09
Description: IAM Role for AWS CloudFormation
Resources:
AWSTestCloudFormationServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: aws-test-cfn-service-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
- arn:aws:iam::aws:policy/AmazonSQSFullAccess
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
- arn:aws:iam::aws:policy/AmazonECS_FullAccess
CFnテンプレート全体
冒頭で示したアーキテクチャのIAMロールをひとつのCFnテンプレートに記載すると、次のようになります。
AWSTemplateFormatVersion: 2010-09-09
Description: IAM Role for OIDC
#====================================#
# GitHub Actions OICD 用 IAM ロールと
# Cloud Formation 用 サービスロールの
# 合計2ロール
#====================================#
Resources:
#====================================#
# GitHub Actions OICD 用 IAM ロール
#====================================#
AWSTestGitHubActionsOICDRole:
Type: AWS::IAM::Role
Properties:
RoleName: aws-test-github-actions-oicd-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Federated: arn:aws:iam::xxxxxxxxxxxx:oidc-provider/token.actions.githubusercontent.com
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
token.actions.githubusercontent.com:aud: sts.amazonaws.com
StringLike:
token.actions.githubusercontent.com:sub: repo:aws-test-organization/aws-test-github-repository:*
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Policies:
- PolicyName: aws-test-github-actions-oicd-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- iam:PassRole
Resource: !GetAtt AWSTestCloudFormationServiceRole.Arn # 後述します
Condition:
StringEqualsIfExists:
iam:PassedToService: cloudformation.amazonaws.com
#====================================#
# Cloud Formation 用 サービスロール
#====================================#
AWSTestCloudFormationServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: aws-test-cfn-service-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess
- arn:aws:iam::aws:policy/AmazonSQSFullAccess
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
- arn:aws:iam::aws:policy/AmazonECS_FullAccess
「最小権限」というのにFullAccess付与は大丈夫なの?
AWSのベストプラクティスに従うと、IAMロールには最小権限を付与するべきです。しかし、CFn用サービスロールには構築対象のAWSサービスのFullAccess権限を付与しています。これを持って「最小権限」と言っていいのか、疑問に思うこともあるかと思います。
今回に関しては「デプロイ用のIAMロールなので、AdministratorAccessを付与するよりはいい」という落とし所です。デプロイ用ロールですので、どんなサービスもデプロイできるよう、ほとんどの場合、実質的なAdministratorAccessが求められることになります。しかし、AdministratorAccessをそのまま付与するのはさすがに危険です。
そこから、「せめて構築対象のAWSサービスに絞ろう」という流れで今回のFullAccess付与に落ち着いています。デプロイ対象のAWSサービスが新しく追加されるタイミングで、IAMロールにもそのサービスのFullAccess権限をつける、という運用になるでしょう。
OIDC用ロールでも、どのサービスに対してPassRoleできるかはConditionで指定しています。
Condition:
StringEqualsIfExists:
iam:PassedToService: cloudformation.amazonaws.com
この考えは、いわば「運用負荷とセキュリティのバランスを考えた案」です。セキュリティ要件をより重視する場合は、AWSサービスをデプロイする際に必要なアクションを細かく調べ上げ、本当の意味で最小権限にする選択肢もあります。このアプローチは、セキュリティ的に最も安全でしょう。構築対象のAWSサービス増加にともない、デプロイ時に必要なアクションが増える場合は、そのアクションを再度調べ、アタッチし、意図したデプロイ動作になるか細かく検証することになるかと思います。運用の負荷は増えますが、セキュリティ面ではより安全な権限設定になります。
権限の設定は難しい
CFnのサービスロールに付与する権限は悩みました。現状は運用不可と天秤にかけてこの構成をとっていますが、今後の運用方法は変わっていくかもしれません。
より適した運用案が出てきた場合は、またブログで共有したいと思います。