2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWSのControl Towerマスターアカウントからセルフマネージド型StackSetsを展開してみた

Last updated at Posted at 2021-01-20

追記(2021.1.23)

 本記事ではStackSetsのセルフサービスアクセス許可を利用する際に管理者・ターゲットアカウントにIAMロール・ポリシーを作成していますが、Control Towerにより作成されているIAMロールにより代用できることに気がつきました。
 そのため、管理者・ターゲットアカウントで新規にIAMロール・ポリシーを作成する必要はありません。

 Control Towerにより作成されているロールは、管理者アカウントにAWSControlTowerStackSetRole、Control Towerにより作成されたアカウントにAWSControlTowerExecutionがあります。
 ポリシーと信頼関係は以下の通りです。

 AWSControlTowerStackSetRoleは、AWSControlTowerStackSetRolePolicyという管理ポリシーがアタッチされ、CloudFormationに対して信頼関係があります。
 この記事で管理者アカウントで作成したIAMロールとの違いは、スイッチロールできるロールの名前だけで、実質的な権限は一緒です。

AWSControlTowerStackSetRole
{
    "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で既に作成されているものですし、プリンシパルを管理者アカウントに指定しているので、こちらを使用しても問題ないと思います。

AWSControlTowerExecution
{
    "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ロールの指定は以下のように行い、無事に作成されました。

スクリーンショット 2021-01-23 8.58.34.png

構成

 前回、AWSのControl Towerマスターアカウントからサービスマネージド型StackSetsを展開してみたの記事を作成しましたが、いくつかデメリットがあったのでセルフマネージド型StackSetsバージョンとしてこちらの記事を執筆します。
 今回の構成はこちら。

StackSetsSelfService.png

 アカウント払い出し時に、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ロール作成

01.png

 StackSetsがIAMロールを利用するので、信頼関係はCloudFormationに対して行います。

スクリーンショット 2021-01-20 19.09.52.png

 ターゲット先アカウントで作成したIAMロールを引き受けられるポリシーを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole"
            ],
            "Effect": "Allow"
        }
    ]
}

スクリーンショット 2021-01-20 19.10.38.png

 ポリシーに適当な名前をつけます。

スクリーンショット 2021-01-20 19.11.36.png

 作成したポリシーをロールに割り当てます。

スクリーンショット 2021-01-20 19.11.55.png

 ロールの名前を間違えないようにつけます。
 AWSCloudFormationStackSetAdministrationRoleです。
 管理アカウントでIAMロール作成完了です。

ターゲットアカウントでIAMロール作成

スクリーンショット 2021-01-20 19.15.11.png

 ターゲットアカウントで、管理アカウントを信頼するIAMロールを作成します。

スクリーンショット 2021-01-20 19.17.52.png

 ポリシーは最低限のポリシーを作成します。

スクリーンショット 2021-01-20 19.18.18.png

 ポリシーに適当な名前をつけます。

スクリーンショット 2021-01-20 19.18.35.png

 作成したポリシーをロールにアタッチします。
 あとはIAMロールの名前を間違えずに設定しましょう。
 AWSCloudFormationStackSetExecutionRoleです。

セルフマネージド型StackSetsでBudgets,SNS展開

 まず、StackSets用にテンプレートをS3にアップロードします。
 いつもは事前にS3にアップロードしませんが、気まぐれでやってみます。

スクリーンショット 2021-01-20 19.23.43.png

スクリーンショット 2021-01-20 19.22.15.png

スクリーンショット 2021-01-20 19.25.09.png

 S3のアップロード完了しました。
 StackSetsを作成します。

スクリーンショット 2021-01-20 19.26.57.png

スクリーンショット 2021-01-20 19.27.11.png

 取り合えず予算額は100ドルにします。

スクリーンショット 2021-01-20 19.27.22.png

 セルフサービスのアクセス許可から、IAMロールを選択し、実行ロール名はデフォルトのままにします。

スクリーンショット 2021-01-20 19.28.19.png

 先ほどIAMロールを作成したターゲットアカウントを指定します。
 StackSetsでBudgets、SNSを展開しました。
 成功しましたが、ターゲットアカウントで展開されているか確認します。

スクリーンショット 2021-01-20 19.32.02.png

 SNSは作成されているようです。

スクリーンショット 2021-01-20 19.32.15.png

 Budgetsも100ドルで作成されています。
 リソースは無事に展開されていました。

サービスマネージド型StackSetsでIAMロール展開

 ターゲットアカウントでのIAMロール作成は、コンソールではうまく行きました。
 ターゲットアカウントにいちいちサインインして作成するのも面倒です。
 次はIAMロールをStackSetsで展開してみます。
 IAMロールはOU単位で展開しても問題ないので、サービスマネージド型で展開します。
 テンプレートは最後に載せます。

スクリーンショット 2021-01-20 19.58.54.png

 サービスマネージド型を選択する画面のキャプチャを撮るのを忘れていますが、サービスマネージド型を選択しています。

スクリーンショット 2021-01-20 20.00.33.png

 IAMロールの展開が成功しました。
 念のため、ちゃんと作成されているかアカウントを移動してみてみます。

スクリーンショット 2021-01-20 21.23.11.png
スクリーンショット 2021-01-20 21.23.27.png

 ポリシー、信頼関係ともに正常に作成できています。

セルフマネージド型StackSetsでスタックの追加を行い、新アカウントにBudgets,SNSを展開する

スクリーンショット 2021-01-20 21.13.31.png

 ターゲットOUへのIAMロール展開が終了したので、ターゲットOU内のアカウントを指定して、StackSetsでBudgets、SNSを展開します。

スクリーンショット 2021-01-20 21.14.59.png

 上書き指定します。
 写真には載っていませんが、スタックを追加する新しいアカウントのIDを指定して作業をしているので、既存のスタックインスタンスには影響を及ぼしません。
 指定した予算額、メールアドレスになっているか確認します。

スクリーンショット 2021-01-20 21.21.07.png

 予算額は50ドルになっているので合っています。

スクリーンショット 2021-01-20 21.22.11.png

 SNSも作成され、指定したメールアドレスになっています。
 StackSetsで展開したIAMロールと、StackSetsで展開したBudgets等が正常に機能していることが確認できました。

テンプレート

Budgets,SNS
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
IAMロール・ポリシー
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単位でばらまくので、使わないアカウントが出る可能性があるのが残念ですが、これは仕方ないですね(たぶん)。
 権限も最低限にしていますし、親アカウントしか使用できないので大丈夫でしょう。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?