追記(2021.1.23)
本記事ではStackSetsのセルフサービスアクセス許可を利用する際に管理者・ターゲットアカウントにIAMロール・ポリシーを作成していますが、Control Towerにより作成されているIAMロールにより代用できることに気がつきました。
そのため、管理者・ターゲットアカウントで新規にIAMロール・ポリシーを作成する必要はありません。
Control Towerにより作成されているロールは、管理者アカウントにAWSControlTowerStackSetRole
、Control Towerにより作成されたアカウントにAWSControlTowerExecution
があります。
ポリシーと信頼関係は以下の通りです。
AWSControlTowerStackSetRole
は、AWSControlTowerStackSetRolePolicy
という管理ポリシーがアタッチされ、CloudFormationに対して信頼関係があります。
この記事で管理者アカウントで作成したIAMロールとの違いは、スイッチロールできるロールの名前だけで、実質的な権限は一緒です。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Resource": [
"arn:aws:iam::*:role/AWSControlTowerExecution"
],
"Effect": "Allow"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "cloudformation.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
AWSControlTowerExecution
は、インラインポリシーで管理者権限が与えられ、Contorl Towerの管理アカウントに対して信頼関係があります。
この記事のターゲットアカウントで作成したIAMロールとの違いは、Control Towerで作成したIAMロールは管理者権限があることです。
強力な管理者権限が設定されているとはいえ、Control Towerで既に作成されているものですし、プリンシパルを管理者アカウントに指定しているので、こちらを使用しても問題ないと思います。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::管理者アカウントID:root"
},
"Action": "sts:AssumeRole"
}
]
}
StackSetの作成時のIAMロールの指定は以下のように行い、無事に作成されました。
構成
前回、AWSのControl Towerマスターアカウントからサービスマネージド型StackSetsを展開してみたの記事を作成しましたが、いくつかデメリットがあったのでセルフマネージド型StackSetsバージョンとしてこちらの記事を執筆します。
今回の構成はこちら。
アカウント払い出し時に、BudgetsとSNSをアカウントに展開した上で払い出します。
セルフマネージド型StackSetsで、OUではなくアカウント指定でBudgets,SNSを展開します。
セルフマネージド型StackSetsを使用するには、以下のロールが必要です。
アカウント | ロール |
---|---|
管理アカウント | AWSCloudFormationStackSetAdministrationRole |
各ターゲットアカウント | AWSCloudFormationStackSetExecutionRole |
StackSetsの展開先が増える度に、ターゲットアカウントにサインインしてIAMロールを作成するのは面倒なので、各ターゲットアカウントの展開は親アカウントからサービスマネージド型StackSetsで展開します。
StackSets | 展開するサービス |
---|---|
サービスマネージド型 | IAMロール、ポリシー |
セルフマネージド型 | Budgets,SNS |
セルフマネージド型のStackSetsを展開するために、事前にサービスマネージド型のStackSetsでIAMロールを展開します。
なぜBudgets等をセルフマネージド型で作成するのか
冒頭でも述べましたが、サービスマネージド型で展開すると今回の場合ではデメリットの方が大きいと判断したからです。
なお、サービスマネージド型に一般的な欠陥があると言うわけではありません。あくまで私がしたいことと合わなかっただけです。
デメリットは二つあり、
・無駄なサブスクリプションの確認が生じる
・メールアドレス変更時に一から設定をし直す必要がある
ことです。
構成図の通り、各アカウントのBudgets等はアカウントごとに設定が異なります。
そのため、サービスマネージド型でターゲットをOUで指定すると、OU内のアカウント全てにデフォルトのメールアドレスをエンドポイントとしたSNSが作成されます。
また、OU内にアカウントが追加されると自動的にStackSetsを展開する自動デプロイ機能も有効化するので、そのときもデフォルトのメールアドレスをエンドポイントとしたSNSが作成されます。
SNSが作成されると、SNSサブスクリプションの確認メールが通知先に飛びます。
リンクをクリックするだけの作業ですが、できればしたくありません。
デフォルトのメールアドレスは実際の通知先として使わないからです。
後からアカウントごとに通知先を変更します。
使用しないサブスクリプションの確認メールをクリックすること自体は意味がありません。
これが一つ目のデメリットです。
二つ目のデメリットがセルフサービス型に決めた理由です。
諸事情によりデフォルトのメールアドレスを更新する場合、ターゲットOU内の全アカウントのSNS通知先が、変更した新しいメールアドレスになるからです。
当然各アカウントが通知したいメールアドレスは新しいメールアドレスではないので、再度設定を上書きし直す必要があります。
結構な労力になるので、これを避けるためにセルフサービス型で展開します。
なお、なぜ実際に通知先として使用しない無駄なデフォルトのメールアドレスを設定していたかと言うと、各アカウントで同じ内容のSNSを作成しないからです。
StackSetsはOU単位で展開するので、複数アカウントで展開します。
Aアカウントで実際に通知先として使用するメールアドレスで展開しても、BアカウントやCアカウントでは通知先として使用しないので、BやCにとっては後で変更する無駄な通知先となります。
どのメールアドレスを使用しても、いずれかのアカウントでは無駄な通知先となるので、自分が使用するメールアドレスをデフォルトのメールアドレスとしていました。
管理者アカウントでIAMロール作成
StackSetsがIAMロールを利用するので、信頼関係はCloudFormationに対して行います。
ターゲット先アカウントで作成したIAMロールを引き受けられるポリシーを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Resource": [
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole"
],
"Effect": "Allow"
}
]
}
ポリシーに適当な名前をつけます。
作成したポリシーをロールに割り当てます。
ロールの名前を間違えないようにつけます。
AWSCloudFormationStackSetAdministrationRole
です。
管理アカウントでIAMロール作成完了です。
ターゲットアカウントでIAMロール作成
ターゲットアカウントで、管理アカウントを信頼するIAMロールを作成します。
ポリシーは最低限のポリシーを作成します。
ポリシーに適当な名前をつけます。
作成したポリシーをロールにアタッチします。
あとはIAMロールの名前を間違えずに設定しましょう。
AWSCloudFormationStackSetExecutionRole
です。
セルフマネージド型StackSetsでBudgets,SNS展開
まず、StackSets用にテンプレートをS3にアップロードします。
いつもは事前にS3にアップロードしませんが、気まぐれでやってみます。
S3のアップロード完了しました。
StackSetsを作成します。
取り合えず予算額は100ドルにします。
セルフサービスのアクセス許可から、IAMロールを選択し、実行ロール名はデフォルトのままにします。
先ほどIAMロールを作成したターゲットアカウントを指定します。
StackSetsでBudgets、SNSを展開しました。
成功しましたが、ターゲットアカウントで展開されているか確認します。
SNSは作成されているようです。
Budgetsも100ドルで作成されています。
リソースは無事に展開されていました。
サービスマネージド型StackSetsでIAMロール展開
ターゲットアカウントでのIAMロール作成は、コンソールではうまく行きました。
ターゲットアカウントにいちいちサインインして作成するのも面倒です。
次はIAMロールをStackSetsで展開してみます。
IAMロールはOU単位で展開しても問題ないので、サービスマネージド型で展開します。
テンプレートは最後に載せます。
サービスマネージド型を選択する画面のキャプチャを撮るのを忘れていますが、サービスマネージド型を選択しています。
IAMロールの展開が成功しました。
念のため、ちゃんと作成されているかアカウントを移動してみてみます。
ポリシー、信頼関係ともに正常に作成できています。
セルフマネージド型StackSetsでスタックの追加を行い、新アカウントにBudgets,SNSを展開する
ターゲットOUへのIAMロール展開が終了したので、ターゲットOU内のアカウントを指定して、StackSetsでBudgets、SNSを展開します。
上書き指定します。
写真には載っていませんが、スタックを追加する新しいアカウントのIDを指定して作業をしているので、既存のスタックインスタンスには影響を及ぼしません。
指定した予算額、メールアドレスになっているか確認します。
予算額は50ドルになっているので合っています。
SNSも作成され、指定したメールアドレスになっています。
StackSetsで展開したIAMロールと、StackSetsで展開したBudgets等が正常に機能していることが確認できました。
テンプレート
Description: "Basic Budget"
Parameters:
Amount:
Type: String
Default: 100
Description: Budgeted amount
email:
Type: String
Description: Notification email1 address user
Resources:
Budget:
Type: AWS::Budgets::Budget
Properties:
Budget:
BudgetName: test1
BudgetLimit:
Amount: !Ref Amount
Unit: USD
TimeUnit: MONTHLY
BudgetType: COST
NotificationsWithSubscribers:
- Notification:
NotificationType: FORECASTED
ComparisonOperator: GREATER_THAN
Threshold: 50
ThresholdType: PERCENTAGE
Subscribers:
- Address: !Ref SNS
SubscriptionType: SNS
- Notification:
NotificationType: FORECASTED
ComparisonOperator: GREATER_THAN
Threshold: 100
ThresholdType: PERCENTAGE
Subscribers:
- Address: !Ref SNS
SubscriptionType: SNS
SNS:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: !Ref email
Protocol: email
TopicName: StackSetsBudgets1
SNSPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Id: MyTopicPolicy
Version: '2012-10-17'
Statement:
- Sid: My-statement-id
Effect: Allow
Principal:
Service: budgets.amazonaws.com
Action: SNS:Publish
Resource: !Ref SNS
Topics:
- !Ref SNS
AWSTemplateFormatVersion: 2010-09-09
Description: Configure the AWSCloudFormationStackSetExecutionRole to enable use of your account as a target account in AWS CloudFormation StackSets.
Parameters:
AdministratorAccountId:
Type: String
Description: AWS Account Id of the administrator account (the account in which StackSets will be created).
MaxLength: 12
MinLength: 12
Resources:
ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: AWSCloudFormationStackSetExecutionRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !Ref AdministratorAccountId
Action:
- sts:AssumeRole
Path: /
ExecuteBudgetsPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- "cloudformation:*"
- "budgets:*"
- "sns:*"
Resource: "*"
PolicyName: AWSCloudFormationStackSetExecutionRoleBudgetsPolicy
Roles:
- !Ref ExecutionRole
さいごに
セルフサービス型StackSets作成が初めてだったので結構身構えていましたが、やってみると思ったより簡単であることがわかりました。
CloudFormationの中にポリシーを入れることに対して苦手意識を持っていましたが、多少改善されたような気がします。
セルフサービス型にすることで無駄な確認メールが減り、最初から自分が望む設定のリソースを展開できるので結構嬉しいです。
ただIAMロールをOU単位でばらまくので、使わないアカウントが出る可能性があるのが残念ですが、これは仕方ないですね(たぶん)。
権限も最低限にしていますし、親アカウントしか使用できないので大丈夫でしょう。