CloudFormation StackSets入門 – 自アカウントの複数リージョンにデプロイ
本ページでは、AWS StackSetsを取り上げます。
AWS CloudFormation StackSets は、複数のアカウントおよび AWS リージョン のスタックを 1 度のオペレーションで、作成、更新、削除できるようにすることで、スタックの機能を拡張します。管理者アカウントを使用して、AWS CloudFormation テンプレートを定義および管理し、指定の AWS リージョン の選択されたターゲットアカウントにスタックをプロビジョニングする基盤としてテンプレートを使用します。
AWS CloudFormation StackSets の操作
今回はStackSets入門ということで、StackSetsを使用して、自アカウントの2つのリージョンにリソースをデプロイします。
構築する環境

CloudFormation StackSetsを使用して、自アカウントの2つのリージョンに対して、CloudFormationスタックを作成します。
スタックでは、Lambda関数を作成します。
StackSetsを実行する上で使用する2つのIAMロールも作成します。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/135
テンプレートファイルのポイント解説
StackSets
Resources:
  StackSet:
    Type: AWS::CloudFormation::StackSet
    Properties:
      AdministrationRoleARN: !GetAtt AdministrationRole.Arn
      Capabilities:
        - CAPABILITY_NAMED_IAM
      Parameters:
        - ParameterKey: Prefix
          ParameterValue: !Ref Prefix
        - ParameterKey: Handler
          ParameterValue: !Ref LambdaHandler
        - ParameterKey: Memory
          ParameterValue: !Ref LambdaMemory
        - ParameterKey: Runtime
          ParameterValue: !Ref LambdaRuntime
      PermissionModel: SELF_MANAGED
      StackInstancesGroup:
        - DeploymentTargets:
            Accounts:
              - !Ref AWS::AccountId
          Regions:
            - !Ref AWS::Region
        - DeploymentTargets:
            Accounts:
              - ap-northeast-1
          ParameterOverrides:
            - ParameterKey: Memory
              ParameterValue: 256
          Regions:
            - us-east-1
      StackSetName: !Ref Prefix
      TemplateURL: !Ref TemplateURL
Code language: YAML (yaml)StackSetsを作成する上でのポイントを取り上げます。
Parametersプロパティで、StackSetsによって作成されるスタック用のパラメータを設定できます。
今回は各リージョンにLambda関数を作成しますので、ランタイム環境やメモリ量を指定します。
PermissionModelプロパティはアクセス許可に関するパラメータです。
スタックセットは、セルフマネージド型のアクセス許可、またはサービスマネージド型のアクセス許可のいずれかを使用して作成できます。
セルフマネージド型アクセス許可を使用する場合、アカウントとリージョン間でデプロイするために StackSets で必要な IAM ロールを作成します。
サービスマネージド型のアクセス許可を使用する場合、AWS Organizations が管理するアカウントにスタックインスタンスをデプロイできます。
スタックセットのアクセス許可モデル
今回はセルフマネージド型を選択するため、「SELF_MANAGED」を指定します。
Parametersプロパティで、生成するスタックに渡すパラメータを指定できます。
今回はLambda関数用に以下のパラメータを設定します。
- Handler(Lambdaで実行する関数):index.lambda_handler
- Memory(Lambdaのメモリ量):128
- Runtime(Lambdaのランタイム環境):python3.8
- Prefix(Lambda関数名のプレフィックス):fa-135
StackInstancesGroupプロパティはスタックインスタンスに関する設定項目です。
スタックインスタンスは、リージョン内のターゲットアカウントのスタックへのリファレンスです。
スタックインスタンス
つまり誰のアカウントのどのリージョンにスタックを生成するかを、このスタックインスタンスで設定します。
今回は自アカウントの2つのリージョン(ap-northeast-1, us-east-1)にスタックを生成します。
ですからDeploymentTargetsプロパティに自身のアカウントIDを、Regionsに両リージョンを指定します。
us-east-1に配置するスタックに関しては、メモリ量を変更することを考えます。
今回の構成では、デフォルトの値として、先述のParametersプロパティで設定した「128」が渡されます。
この値を変更する場合は、ParameterOverridesプロパティが使用できます。
今回は「256」に変更します。
IAMロール
セルフマネージド型のStackSetsを作成する場合、IAMロールがポイントとなります。
2つのIAMロールを作成します。
管理者アカウント用のIAMロール
Resources:
  AdministrationRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: AWSCloudFormationStackSetAdministrationRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudformation.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: AssumeRole-AWSCloudFormationStackSetExecutionRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - sts:AssumeRole
                Resource:
                  - arn:*:iam::*:role/AWSCloudFormationStackSetExecutionRole
Code language: YAML (yaml)1つ目は管理者アカウント用のIAMロールです。
管理者アカウントで、AWSCloudFormationStackSetAdministrationRole という名前の IAM ロールを作成します。ロールにはこの正確な名前が必要です。
スタックセットオペレーションの基本アクセス許可の設定
上記のテンプレートは、AWS公式が公開しているファイルを参考にして作成しました。
ターゲットアカウント用のIAMロール
Resources:
  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: AWSCloudFormationStackSetExecutionRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !Ref AWS::AccountId
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess"
Code language: YAML (yaml)2つ目はターゲットアカウント用のIAMロールです。
各ターゲットアカウントで、管理者アカウントを信頼する AWSCloudFormationStackSetExecutionRole という名前のサービスロールを作成します。ロールにはこの正確な名前が必要です。
スタックセットオペレーションの基本アクセス許可の設定
今回は自アカウントにスタックを作成するため、ターゲットアカウントも自分自身となります。
ですから管理者アカウント用IAMロールだけでなく、ターゲット用IAMロールも作成します。
上記のテンプレートは、AWS公式が公開しているファイルを参考にして作成しました。
TemplateURLプロパティで、各スタックを生成するために使用するテンプレートファイルを指定します。
テンプレートファイルはS3バケットに配置し、そのURLを指定します。
URLは仮想ホスティング形式で記載します。
https://[bucket-name].s3.[region].amazonaws.com/[template-file]
今回は、後述のLambda関数を含むテンプレートファイルを指定します。
(参考)Lambda関数
Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          REGION: !Ref AWS::Region
          MEMORY: !Ref Memory
      Code:
        ZipFile: |
          import json
          import os
          region = os.environ['REGION']
          memory = os.environ['MEMORY']
          def lambda_handler(event, context):
            data = {
              'region': region,
              'memory': memory
            }
            return {
              'statusCode': 200,
              'body': json.dumps(data, indent=2)
            }
      FunctionName: !Sub "${Prefix}-function"
      Handler: !Ref Handler
      MemorySize: !Ref Memory
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)StackSetsによって各リージョンで生成されるLambda関数です。
リージョン情報とメモリ量を返す簡単な内容です。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

今回は名前付きのIAMリソースを生成するため、以下のようなコマンドとなります。
aws cloudformation create-stack \
--stack-name fa-135 \
--template-url https://[bucket-name].s3.ap-northeast-1.amazonaws.com/[path]/fa-135.yaml \
--capabilities CAPABILITY_NAMED_IAM
Code language: YAML (yaml)各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- StackSets:fa-135
AWS Management Consoleから各リソースを確認します。
StackSetsを確認します。

StackSetが正常に作成されています。
スタックインスタンスを確認します。

確かに2つのリージョンにスタックが生成されていることがわかります。
デフォルトのパラメータを確認します。

4つのパラメータが渡されています。
特にメモリの値が「128」であることがポイントです。
動作確認
準備が整いましたので、生成された各スタックを確認します。
スタック1
まずap-northeast-1に生成されたスタックを確認します。


スタック内でLambda関数等が生成されていることがわかります。
またパラメータを見ると、先ほどStackSetsで確認した値が渡されていることがわかります。
作成されたLambda関数を確認します。


テンプレートファイルで指定した通りに関数が作成されています。
確かにメモリ量は128(MB)です。
この関数を実行します。

正常に実行されました。
このようにリージョンap-northeast-1に、メモリ量128MBで関数が生成されました。
スタック2
次にus-east-1に生成されたスタックを確認します。


スタック内でLambda関数等が生成されていることがわかります。
またパラメータを見ると、メモリ量が「256」とあります。
これはus-east-1リージョンだけパラメータの値を上書きしたためです。
作成されたLambda関数を確認します。


関数のコードは、テンプレートファイルで指定した通りです。
ただしメモリ量は256(MB)です。
確かにメモリのパラメータが上書きされたということがわかります。
この関数を実行します。

正常に実行されました。
このようにリージョンus-east-1に、メモリ量256MBで関数が生成されました。
まとめ
StackSets入門ということで、StackSetsを使用して、自アカウントの2つのリージョンにリソースをデプロイしました。