この記事はZOZO AdventCalender 2023シリーズ9の15日目の記事です。
はじめに
- 本記事は以下のようなケースを想定しています。
- 何らかの理由によってOrganizationsが使えない。
- マルチアカウント構成におけるユーザ権限を良い感じに管理したい。
- Organizationsを使わないことを推奨するものではありません、使える場合には迷うことなく使いましょう。
- 例えば、ルートユーザに対して制限を加えたい場合にはOrganizationsによるSCPが必要です。
- こういった作り方もあるよねという一例として見てもらえればと思います。
前提条件
本記事における前提条件を記載します。
- AWSアカウントは3つ(管理用アカウント、開発用アカウント1、開発用アカウント2)
- 管理用アカウント
- IAMユーザの管理
- 後述するStackSetsの管理用アカウント
- 開発用アカウント1、開発用アカウント2
- 開発者の作業用
- 管理用アカウント
- 開発用アカウントには、以下3つの役割でアクセスする想定。
- 管理者
- 全ての権限を持つ(AdministratorAccess相当)
- 開発者
- 一部を除いて全ての権限を持つ(基本はAdministratorAccess相当)
- CloudTrailに対する書き込み系の操作は禁止
- 自身の権限を変更することは禁止(権限昇格の防止)
- 監査者
- 閲覧権限のみを持つ(ReadOnlyAccess相当)
- 管理者
アーキテクチャ
アーキテクチャは以下の通りです。
IAMユーザは管理アカウントに作成します。
一方で、開発用アカウントには役割毎に適切なポリシーを付与したIAMロールを作成し、管理アカウントからスイッチロール出来るようにします。
IAMユーザにはスイッチロールするためのAssumeRole権限が必要となるため、役割毎に用意したIAMグループに対して、当該操作を許可するポリシーを割り当てます。
設定の配布方法
設定の配布は以下のイメージで行います。
各AWSアカウントに設定を配布する際には、CloudFormation StackSetsを用いて一元管理します。
また、StackSetsで作成されたリソースにはManagedResource
という名前のタグで目印をつけます(タグの名前は任意で良いです)。
タグがついたリソースに対するポリシーを各IAMロールへ適切に設定することで、勝手に権限が変更されないようにします。
作り方
まず、AWSアカウントを3つ作成します。
作成方法は以下をご確認ください。
続けて、以下の流れで設定を行なっていきます。
- 開発用アカウントの設定(StackSets用)
- 管理アカウントの設定(StackSets用)
- 管理アカウントの設定(IAMグループの作成)
- スイッチロール用IAMロールの作成
- IAMユーザの作成
本手順で記載されている内容は最低限の設定のみを実施しています。
実際に運用する際にはセキュリティを考慮した上で適宜判断してください。
1. 開発用アカウントの設定(StackSets用)
StackSetsの実行に使用するターゲットアカウント側のIAMロールを作成します。
このIAMロールはAWSCloudFormationStackSetExecutionRole
という名前である必要があります。
詳細は、以下をご確認ください。
信頼されたエンティティタイプ
としてAWSアカウント
を選択し、別のAWSアカウント
に管理用アカウントのアカウントIDを入力します。
許可ポリシーとしてAdministratorAccess
を選択します。
ロール名をAWSCloudFormationStackSetExecutionRole
として作成します。
同様の手順を、もう一方の開発用アカウントに対しても実施します。
2. 管理アカウントの設定(StackSets用)
StackSetsの実行に使用する管理者アカウント側のIAMロールを作成します。
このIAMロールはAWSCloudFormationStackSetAdministrationRole
という名前である必要があります。
詳細は、以下をご確認ください。
ロールを作成
します。
信頼されたエンティティタイプ
としてAWSのサービス
を選択し、サービスまたはユースケース
としてCloudFormationを選択します。
許可を追加
では何もせずに次へ進みます。
ロール名をAWSCloudFormationStackSetAdministrationRole
として作成します。
続けて、作成したAWSCloudFormationStackSetAdministrationRole
ロールを選択し、許可を追加
からインラインポリシーを作成
します。
以下のルールでポリシーを作成します(ポリシー名は任意です)。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Resource": [
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole"
],
"Effect": "Allow"
}
]
}
3. 管理アカウントの設定(IAMグループの作成)
管理アカウントに対して、役割毎のIAMグループを作成します。
今回は、以下のCloudFormationテンプレートを用意します。
AWSTemplateFormatVersion: "2010-09-09"
Description: create iam group
Resources:
# ---------------------------------------------
# Group
# ---------------------------------------------
GroupAdministrator:
Type: AWS::IAM::Group
Properties:
GroupName: group-administrator
GroupDeveloper:
Type: AWS::IAM::Group
Properties:
GroupName: group-developer
GroupAudit:
Type: AWS::IAM::Group
Properties:
GroupName: group-audit
# ---------------------------------------------
# Policy
# ---------------------------------------------
PolicyAdministrator:
Type: AWS::IAM::Policy
Properties:
Groups:
- !Ref GroupAdministrator
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "sts:AssumeRole"
Resource:
- "arn:aws:iam::*:role/role-administrator"
PolicyName: policy-administrator
PolicyDeveloper:
Type: AWS::IAM::Policy
Properties:
Groups:
- !Ref GroupDeveloper
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "sts:AssumeRole"
Resource:
- "arn:aws:iam::*:role/role-developer"
PolicyName: policy-developer
PolicyAudit:
Type: AWS::IAM::Policy
Properties:
Groups:
- !Ref GroupAudit
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "sts:AssumeRole"
Resource:
- "arn:aws:iam::*:role/role-audit"
PolicyName: policy-audit
CloudFormationから当該テンプレートを適用します。
スタックの作成
を押下します。
スタックの作成が完了したら次の手順へ進みます。
4. スイッチロール用IAMロールの作成
管理アカウントから開発アカウントに対してスイッチロール用IAMロールを作成します。
今回は、以下のCloudFormationテンプレートを用意します。
AWSTemplateFormatVersion: "2010-09-09"
Description: create switchrole
Parameters:
ManagementAWSAccountId:
Type: String
Description: AWS Account ID of Management Account
Resources:
# ---------------------------------------------
# Role
# ---------------------------------------------
RoleAdministrator:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- !Ref ManagementAWSAccountId
Action:
- 'sts:AssumeRole'
Description: Administrator Role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
RoleName: role-administrator
RoleDeveloper:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- !Ref ManagementAWSAccountId
Action:
- 'sts:AssumeRole'
Description: Developer Role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
RoleName: role-developer
RoleAudit:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- !Ref ManagementAWSAccountId
Action:
- 'sts:AssumeRole'
Description: Audit Role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/ReadOnlyAccess
RoleName: role-audit
# ---------------------------------------------
# Policy
# ---------------------------------------------
PolicyAdministratorRestriction:
Type: AWS::IAM::Policy
Properties:
Roles:
- !Ref RoleAdministrator
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Action:
- "*"
Resource:
- "*"
Condition:
StringEquals:
aws:ResourceTag/ManagedResource: "true"
PolicyName: policy-administrator-restiction
PolicyDeveloperRestriction:
Type: AWS::IAM::Policy
Properties:
Roles:
- !Ref RoleDeveloper
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Action:
- "*"
Resource:
- "*"
Condition:
StringEquals:
aws:ResourceTag/ManagedResource: "true"
- Effect: Deny
Action:
- "cloudtrail:Cancel*"
- "cloudtrail:Create*"
- "cloudtrail:Delete*"
- "cloudtrail:Enable*"
- "cloudtrail:Put*"
- "cloudtrail:Start*"
- "cloudtrail:Stop*"
- "cloudtrail:Update*"
- "cloudtrail:Deregister*"
- "cloudtrail:Register*"
- "cloudtrail:Disable*"
- "cloudtrail:Restore*"
Resource:
- "*"
PolicyName: policy-developer-restiction
PolicyAuditRestriction:
Type: AWS::IAM::Policy
Properties:
Roles:
- !Ref RoleAudit
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Deny
Action:
- "*"
Resource:
- "*"
Condition:
StringEquals:
aws:ResourceTag/ManagedResource: "true"
PolicyName: policy-audit-restiction
CloudFormation StackSetsから当該テンプレートを適用します。
StackSetsの作成
を押下します。
IAM管理ロール
として、先に作成したAWSCloudFormationStackSetAdministrationRole
を選択します。
また、実行ロール名にはターゲットアカウント側に作成したAWSCloudFormationStackSetExecutionRole
を入力します。
任意の名前を入力し、パラメータ(管理用アカウントのAWSアカウントID)を入力して次へ。
スタックオプションの設定
では、タグ(キー:ManagedResource、値:true)を指定します。
ここで指定したタグがCloudFormationで作成されるリソースに付与され、先に用意したIAMロールによる制御対象とすることが出来ます。
デプロイオプションの設定
では、デプロイ先のAWSアカウントIDとリージョンを指定します。
AWSアカウントIDには開発用アカウントのAWSアカウントID×2、リージョンは利用するリージョン(今回は東京リージョンとします)を指定します。
スタックの作成が完了したら次の手順へ進みます。
5. IAMユーザの作成
管理用アカウントにIAMユーザを作成します。
今回は、例として先のアーキテクチャ図で記載したsaburo
さん(開発者ロール)を作成します。
ユーザ名にsaburo
と入力し、AWSマネジメントコンソールへのアクセスにチェックを入れて次へ。
先に作成した開発者用のIAMグループ(group-developer)を選択して次へ。
作成したsaburo
ユーザでAWSマネジメントコンソールへログインします。
画面右上のロールの切り替え
からスイッチロール出来ることを確認します。
スイッチロール先のAWSアカウントIDとロール名を入力して、ロールの切り替え
を押下。
動作確認
前の手順でスイッチロールした状態で、許可されていない操作が出来ないことを確認します。
まず、自分の権限の変更を試してみます。
自分のIAMロール(role-developer)を参照しようとした時点で権限がないことが確認出来ます。
次に、StackSetsで作成されたCloudFormationスタックが削除出来るか確認します。
先の例と同じようにStackSetsで作成されたスタックを参照しようとした時点で権限がないことが確認出来ます。
最後に、CloudTrail証跡の削除を試みました(記事には記載していませんが、あらかじめ有効にしておきました)。
上部に黄色く表記されていますが、削除権限が無いことが確認出来ます。
このように、スイッチロール先のIAMロールに対してポリシーを適切に設定することで、OrganizationsにおけるSCPのように
ブラックリスト的な操作を指定することが出来ます。
最後に
- AWSを使ってマルチアカウント構成を取る場合にはOrganizationsを使うことが広く知られており、本記事のような手順を採用することはレアかと思いますが、敢えてそれを使わない方法をまとめてみました。
- 面倒な方法を試してみることで、サービスの持つ良し悪しがより分かる気がします。