AWS CloudFormation StackSets を使ったマルチアカウントのスイッチロール実装
2023.8.30
はじめに
マルチアカウントの環境で、IAM User を使用してすべての環境にログインをしている場合は、管理する IAM User が大量になり管理が煩雑になります。
また、ログインする側としても毎回コンソールを切り替える必要があるためかなり大変です。
その課題を解決するために、スイッチロールが有用ですが、それだけではなく CloudFormation StackSets を使うことでより簡単に実装することができます。
本記事では、CloudFormation StackSets を使ってマルチアカウントのスイッチロールを実装について記述します。
まずは、2 つほど重要なキーワードがあるので以下にて軽く説明します。
- スイッチロール
- CloudFormation StackSets
スイッチロールとは
IAM Role を使ったログイン方法です。
認証された IAM Role を使って AWS アカウントにログインすることができます。
メリット
- IAM User を作らなくても良い
- 特定のアカウントだけが IAM Role にアクセスするように制御することができる
- スイッチロール先のアカウント側で権限を管理できる
ロールの切り替え (コンソール) – AWS Identity and Access Management
CloudFormation StackSets とは
CloudFormation はリージョンサービスです。
マルチリージョンでデプロイしようとしたり、他の AWS アカウントに対してデプロイする場合は同じ作業を繰り返すことになるためかなり手間になります。
この StackSets を使うことで一つのテンプレートを使ってマルチリージョンやマルチアカウントのデプロイを簡略化できます。
メリット
- マルチリージョン・マルチアカウントで CloudFormation をデプロイできる
- 同じ作業を繰り返さなくてよくなる
StackSets の概念 – AWS CloudFormation
マルチアカウントの課題
AWS Well-Architected にはマルチアカウント戦略があります。
詳細は省きますが、環境に応じて AWS アカウントを分けましょうという話です。
SEC01-BP01 アカウントを使用してワークロードを分ける: – セキュリティの柱
そこで、実際に本番環境、ステージング環境、テスト環境などと AWS アカウントをただ分けると以下のような課題が浮き彫りになります。
- マルチアカウントの IAM User の管理 → 管理者の課題
- 環境ごとにログインを切り替える手間 → 開発者の課題
イメージとしては以下のような構成です。
「マルチアカウントの IAM User の管理」の課題は、どの AWS アカウントにどの IAM User が存在して、どのロールを保持しているかを把握するときに、1 ユーザーに対して IAM User が複数ある場合調査対象がかなり多くなります。
また、人や AWS アカウントが増えていけばいくほど管理対象が増えるため管理コストが増加します。
「環境ごとにログインを切り替える手間」の課題は、原則として一つのブラウザでログインできる AWS アカウントは一つです。
そのため、複数環境に同時にログインしたい場合は別ブラウザを使います。
その際に、毎回ログインが発生して、ユーザー名やパスワードを入力しているとかなり手間が発生します。
さらに、セキュリティ向上のために各 AWS アカウントで、MFA を設定すると更にログイン時に手間が増えます。
これらの課題を解決するために、「マルチアカウントのスイッチロール」を実装します。
そうすることにより、管理アカウントで IAM User を一括管理することができ、複数環境に渡っていた IAM User が減るため管理コストを減らせます。
イメージとしては以下のような構成です。
ただ、ログインする際の手間は減らせても、管理する側の手間はあまり減りません。
そのため、さらに手間を削減するために StackSets を使用して一元管理でデプロイを行います。
CloudFormation StackSets でスイッチロールを実装
じゃあ、実際にどう実装していくのかを本セクションで解説をします。
今回は以下の構成を実装いたします。
スイッチロール先の AWS アカウントは 1 つですが、これが 2 つ 3 つと増えてもやることは、該当のコード部分を増やすだけなのであまり変わりません。
AWS アカウントが増えてもわかりやすいように、「CloudFormation テンプレートの構成」セクションでは複数のアカウントの場合を想定してテンプレート作成をしています。
実際のデプロイについては、上記構成の通りにテンプレートを作成しています。
CloudFormation テンプレートの構成
先に今回使用する CloudFormation テンプレートの解説を行います。
使用するテンプレートは大きく 2 つに分けてます。
- 接続先アカウントにスイッチロールを作成するテンプレート
- 管理アカウントに IAM User とスイッチロール権限を付与するテンプレート
スイッチロール先アカウント用 IAM ロール作成用
本テンプレートでは各 AWS アカウントごとに Mappings を設定して環境名を変えています。
Mappings :キーと名前付きの一連の値
Mappings – AWS CloudFormation
本記事の例では、4 つの AWS アカウントで、2 つのプロジェクトを管理し、それぞれ本番環境とステージング環境が存在する設定とします。
以下、AWS アカウントのサンプル構造です。
- ProjectA
- 本番:A アカウント
- ステージング:B アカウント
- ProjectB
- 本番:C アカウント
- ステージング:D アカウント
今回は、上記 4 つの AWS アカウントに対して開発者権限のみを与えた IAM Role でスイッチロールすることを想定しています。
AWSTemplateFormatVersion: 2010-09-09 Description: SwitchRole CFn StackSets Mappings: AccountMap: "AアカウントID": Env: Prod Prefix01: ProjectA "BアカウントID": Env: Stg Prefix01: ProjectA "CアカウントID": Env: Prod Prefix01: ProjectB "DアカウントID": Env: Stg Prefix01: ProjectB Parameters: RootAccountId: Type: String Default: "管理アカウントID" Resources: Developer: Type: "AWS::IAM::Role" Properties: RoleName: !Sub - "${Prefix01}${Env}SwitchDeveloper" - Prefix01: !FindInMap [AccountMap, !Ref "AWS::AccountId", Prefix01] Env: !FindInMap [AccountMap, !Ref "AWS::AccountId", Env] AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: AWS: !Sub arn:aws:iam::${RootAccountId}:root Action: - "sts:AssumeRole" Path: "/" ManagedPolicyArns: - arn:aws:iam::aws:policy/ReadOnlyAccess - arn:aws:iam::aws:policy/AmazonEC2FullAccess
ポイント
- 組み込み関数 !Sub を使って各値を参照しながら結合してます
- 組み込み関数 !FindInMap Mappings セクションで宣言された 2 つのレベルのマッピングのキーに対応する値を返します
- 組み込み関数 !Ref と擬似パラメータ参照で “AWS::AccountId”を使用して AWS アカウント ID を参照してます
管理アカウント用 IAM User・Group 作成用
このテンプレートでは、以下のリソースを作成します。
- IAM Policy
- 対象のスイッチロールに AssumeRole できる権限を付与
- IAM Group
- スイッチロールポリシーをアタッチし複数ユーザーで権限を共有
- IAM User
- 管理アカウントに接続するユーザー
一つのテンプレートにまとめると見づらいので、後述する例では 以下 2 つのテンプレートに区分しています。
- IAM Group と IAM Policy
- IAM User
IAM Group と IAM Policy
やっていることはスイッチロールテンプレートとあまり変わらないです。
注意点としては、IAM Policy でスイッチロールするロールと対象の AWS アカウントとを指定していることです。
AWSTemplateFormatVersion: 2010-09-09 Description: Group Policy Parameters: Prj01: Type: String Default: ProjectA Prj02: Type: String Default: ProjectB Env01: Type: String Default: Prod Env02: Type: String Default: Stg ProjectAProdAccountID: Type: String Default: "AアカウントID" ProjectAStgAccountID: Type: String Default: "BアカウントID" Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Prefix Parameters: - Prj01 - Prj02 - Label: default: Env Parameters: - Env01 - Env02 Resources: ProjectAProdSwitchDeveloper: Type: AWS::IAM::Group Properties: GroupName: !Sub "${Prj01}${Env01}SwitchDeveloper" ProjectAProdSwitchDeveloperPolicy: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "${Prj01}${Env01}SwitchDeveloperPolicy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - sts:AssumeRole Resource: !Sub "arn:aws:iam::${ProjectAProdAccountID}:role/${Prj01}${Env01}SwitchDeveloper" Groups: - !Ref ProjectAProdSwitchDeveloper Outputs: ProjectAProdSwitchDeveloper: Description: Information about the value Value: !Ref ProjectAProdSwitchDeveloper Export: Name: ProjectAProdSwitchDeveloper
テンプレートを分けているので、IAM User テンプレートで値を参照するためオプションの Outputs セクションでグループ名を出力しています。
[Outputs] (出力) – AWS CloudFormation
IAM User
こっちはもっとシンプルで IAM User を作成して Outputs した IAM Group を参照します。
AWSTemplateFormatVersion: 2010-09-09 Description: user creation Parameters: InitialPassword: Type: String NoEcho: True Resources: User1: Type: "AWS::IAM::User" Properties: Groups: - !ImportValue ProjectAProdSwitchDeveloper - !ImportValue ProjectAStgSwitchDeveloper LoginProfile: Password: !Ref InitialPassword PasswordResetRequired: true UserName: sample.user
アクセスする環境を増やしたい場合は、権限を追加した Group に IAM User を追加していくだけです。
デプロイ手順
準備が整ったので作成したテンプレートを元にデプロイしていきます。
デプロイ手順は以下の通りです。
- 各アカウントで StackSets 用の IAM Role 作成
- IAM Group を作成 → CloudFormation を使ってデプロイ
- 各アカウントの IAM Role にスイッチロールする権限をアタッチ
- 管理用アカウントに IAM User を作成 → CloudFormation を使ってデプロイ
- 必要なメンバーをグループに追加
- StackSets で各アカウントに IAM Role を作成 → CloudFormation StackSets を使ってデプロイ
1. 各アカウントで CloudFormation StackSets 用の IAM Role 作成
はじめに、CloudFormation StackSets を使うには準備が必要です。
少し複雑な話ですが、CloudFormation StackSets は 2 つの以下方法でアクセス許可を与えてやる必要があります。
- セルフマネージド型(IAM Role)のアクセス許可
- サービスマネージド型(AWS Organizations)のアクセス許可
今回は弊社のリセール環境下で検証を行う都合上の理由で、「セルフマネージド型(IAM Role)のアクセス許可」で StackSets をデプロイします。
もう一つの「サービスマネージド型(AWS Organizations)のアクセス許可」を利用する場合は、本セクションの内容は不要です。
ただし、後述する手順に差異がある可能性がありますのでご了承ください。
「セルフマネージド型(IAM Role)のアクセス許可」を簡単に説明すると、スイッチロール先アカウントで CloudFormation を実行する権限を IAM Role を使って管理アカウントに委譲します。
そのために準備・作成する IAM Role は以下の 2 つです。
- AWSCloudFormationStackSetAdministrationRole
- AWSCloudFormationStackSetExecutionRole
なお、本記事では詳細な手順は記載いたしません。
作成するための CloudFormation テンプレートが以下ドキュメントにあるので詳細はそちらでご確認下さい。
セルフマネージド型のアクセス許可を付与する – AWS CloudFormation
この作成したロールを指定して後述の CloudFormation テンプレートをデプロイします。
2. IAM Group を作成
ここからが実際のデプロイ作業になります。
テンプレートを区分しているため先に IAM Group を作成します。
このテンプレートは、管理アカウントに対してデプロイするため StackSets ではなく CloudFormation でデプロイします。
上述したテンプレートに実際に値を設定しています。
AWSTemplateFormatVersion: 2010-09-09 Description: Group Policy Parameters: Prj01: Type: String Default: ProjectA Env01: Type: String Default: Prod ProjectAProdAccountID: Type: String Default: "031125416455" Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Prefix Parameters: - Prj01 - Label: default: Env Parameters: - Env01 Resources: ProjectAProdSwitchDeveloper: Type: AWS::IAM::Group Properties: GroupName: !Sub "${Prj01}${Env01}SwitchDeveloper" ProjectAProdSwitchDeveloperPolicy: Type: "AWS::IAM::ManagedPolicy" Properties: ManagedPolicyName: !Sub "${Prj01}${Env01}SwitchDeveloperPolicy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - sts:AssumeRole Resource: !Sub "arn:aws:iam::${ProjectAProdAccountID}:role/${Prj01}${Env01}SwitchDeveloper" Groups: - !Ref ProjectAProdSwitchDeveloper Outputs: ProjectAProdSwitchDeveloper: Description: Information about the value Value: !Ref ProjectAProdSwitchDeveloper Export: Name: ProjectAProdSwitchDeveloper
デプロイした後の出力結果です。
この値を次の IAM User のテンプレートで参照します。
3. 管理用アカウントに IAM User を作成
続いては IAM User 作成して、先程出力した IAM Group 名を参照しています。
こちらのテンプレートも先程同様に、管理アカウントに対してデプロイするため StackSets ではなく CloudFormation でデプロイします。
AWSTemplateFormatVersion: 2010-09-09 Description: user creation Parameters: InitialPassword: Type: String NoEcho: True Resources: User1: Type: "AWS::IAM::User" Properties: Groups: - !ImportValue ProjectAProdSwitchDeveloper LoginProfile: Password: !Ref InitialPassword PasswordResetRequired: true UserName: sample.user
しっかりとポリシーがアタッチされています。
4. StackSets で各アカウントに IAM Role を作成
では、最後に大本命の CloudFormation StackSets 作業を行います。
AWSTemplateFormatVersion: 2010-09-09 Description: SwitchRole CFn StackSets Mappings: AccountMap: "031125416455": Env: Prod Prefix01: ProjectA Parameters: RootAccountId: Type: String Default: "375845453107" Resources: Developer: Type: "AWS::IAM::Role" Properties: RoleName: !Sub - "${Prefix01}${Env}SwitchDeveloper" - Prefix01: !FindInMap [AccountMap, !Ref "AWS::AccountId", Prefix01] Env: !FindInMap [AccountMap, !Ref "AWS::AccountId", Env] AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: AWS: !Sub arn:aws:iam::${RootAccountId}:root Action: - "sts:AssumeRole" Path: "/" ManagedPolicyArns: - arn:aws:iam::aws:policy/ReadOnlyAccess - arn:aws:iam::aws:policy/AmazonEC2FullAccess
上記のテンプレートでデプロイを行います。
設定を進めていくとまずは、アクセス許可の設定があり一番最初に作った IAM Role をここで選択します。
その後必要な値を入力していきます。
ここは CloudFormation スタックと変わりないです。
ここは StackSets 特有の設定になってます。
デプロイする AWS アカウントやリージョンをここで選択します。
ただ、リージョンについては今回は IAM リソースなのでどこでも問題ないです。
設定が完了したので実行します。
オペレーションタブで今回実行したログを確認できます。
スタックインスタンスでどこのリージョンやどの AWS アカウント単位の実行を確認できます。
実行が完了したらスイッチロール先の AWS アカウントにログインして IAM Role の確認をします。
するとしっかりと名前が設定され、管理アカウントとの信頼関係になっていることが確認できます。
接続確認
では、実際にスイッチロールを使って接続します。
IAM User のログインやパスワード変更は割愛します。
ログインができたら、AWS コンソールの右上から「ロール切り替え」を選択します。
スイッチロール先アカウントの情報を入力します。
今回の入力する値はロールは「ProjectAProdSwitchDeveloper」になります。
入力内容が間違っていなければスイッチロールできます。
右上のログイン情報が変わっています。
あとはこのまま操作が可能です。
まとめ
- アカウントが増えれば増えるほど管理は煩雑になる
- スイッチロールを使うと マルチアカウントの接続が楽になる
- StackSets を使うとマルチアカウントデプロイが楽になる
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitter2021年新卒入社。インフラエンジニアです。RDBが三度の飯より好きです。 主にデータベースやAWSのサーバレスについて書く予定です。あと寒いのは苦手です。
Recommends
こちらもおすすめ
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28
AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16