CloudFormation StackSets の管理者ロールと実行ロールを変更してみた

後から変えたくなっても安心
2022.11.16

CloudFormation StackSets の管理者ロールや実行ロールを変更するとスタックの再デプロイが行われるのかな

こんにちは、のんピ(@non____97)です。

皆さんは「CloudFormation StackSets の管理者ロールや実行ロールを変更すると、スタックの再デプロイが行われるのか」気になったことはありますか? 私はあります。

セルフマネージド型のStackSetsを作成する場合は、管理者ロールや実行ロールを事前に用意する必要があります。

命名規約に揃えたいや、誤って他のロールを指定していた場合など、場合によってはStackSets作成後に管理者ロールや実行ロールを変更したくなることがあると思います。

管理者ロールや実行ロールを変更する場合、一度スタックインスタンスが削除されて再作成されるような挙動をするのでしょうか。

気になったので検証してみました。

いきなりまとめ

  • CloudFormationのテンプレートとパラメーターに差分がなければ、スタックの更新は発生しない
    • 差分がなくてもスタックインスタンスの更新は発生する
  • スタックインスタンスがある状態でアクセス許可(サービスマネージドとセルフマネージド)の変更はできない

検証環境

検証環境は以下の通りです。

StackSetsの検証環境

管理者ロールと実行ロールを2組ずつ用意して、StackSets作成後に使用している管理者ロールと実行ロールのペアを入れ替えた際の挙動を確認します。

やってみた

管理者ロールと実行ロールの作成

AWS CDKで検証に使用する管理者ロールと実行ロールを2組作成します。

IAMロールはAWS CDKで作成しました。コードは以下の通りです。

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";

export class IamRoleStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    for (let i = 0; i < 2; i++) {
      // AWSCloudFormationStackSetAdministrationRole
      const stackSetAdministrationRole = new cdk.aws_iam.Role(
        this,
        `StackSetAdministrationRole${i}`,
        {
          roleName: `StackSetAdministrationRole${i}`,
          assumedBy: new cdk.aws_iam.ServicePrincipal(
            "cloudformation.amazonaws.com"
          ),
        }
      );

      // AWSCloudFormationStackSetExecutionRole
      const setExecutionRole = new cdk.aws_iam.Role(
        this,
        `SetExecutionRole${i}`,
        {
          roleName: `SetExecutionRole${i}`,
          assumedBy: new cdk.aws_iam.ArnPrincipal(
            stackSetAdministrationRole.roleArn
          ),
        }
      );

      // AWSCloudFormationStackSetAdministrationRole Policy
      const stackSetAdministrationRolePolicy = new cdk.aws_iam.ManagedPolicy(
        this,
        `StackSetAdministrationRolePolicy${i}`,
        {
          statements: [
            new cdk.aws_iam.PolicyStatement({
              effect: cdk.aws_iam.Effect.ALLOW,
              actions: ["sts:AssumeRole"],
              resources: ["*"],
            }),
          ],
        }
      );

      // AWSCloudFormationStackSetExecutionRole Policy
      const setExecutionRolePolicy = new cdk.aws_iam.ManagedPolicy(
        this,
        `SetExecutionRolePolicy${i}`,
        {
          statements: [
            new cdk.aws_iam.PolicyStatement({
              effect: cdk.aws_iam.Effect.ALLOW,
              actions: ["cloudformation:*", "s3:*", "ec2:*"],
              resources: ["*"],
            }),
          ],
        }
      );

      stackSetAdministrationRole.addManagedPolicy(
        stackSetAdministrationRolePolicy
      );
      setExecutionRole.addManagedPolicy(setExecutionRolePolicy);
    }
  }
}

作成される管理者ロールと実行ロールのIAMポリシーは以下の通りです。

  • 管理者ロール(StackSetAdministrationRole0, StackSetAdministrationRole1)
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "sts:AssumeRole",
                "Resource": "*",
                "Effect": "Allow"
            }
        ]
    }

  • 実行ロール(SetExecutionRole0,SetExecutionRole1)

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "cloudformation:*",
                    "ec2:*",
                    "s3:*"
                ],
                "Resource": "*",
                "Effect": "Allow"
            }
        ]
    }

StackSetsの作成

それではStackSetsを作成します。

使用するCloudFormationのテンプレートは以下の通りです。

VPC.yml

AWSTemplateFormatVersion: "2010-09-09"

Description: VPC

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: vpc

AWS CLIでStackSetsを作成します。その際の管理者ロールを実行ロールは以下の通りです。

  • 管理者ロール : StackSetAdministrationRole0
  • 実行ロール : SetExecutionRole0

実行結果は以下の通りです。

# StackSetsの作成
$ aws cloudformation create-stack-set \
    --stack-set-name vpc-stacksets \
    --description VPC \
    --template-body file://VPC.yml \
    --permission-model SELF_MANAGED \
    --administration-role-arn arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0 \
    --execution-role-name SetExecutionRole0
{
    "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4"
}

# 作成されたStackSetsの確認
$ aws cloudformation describe-stack-set --stack-set-name vpc-stacksets
{
    "StackSet": {
        "StackSetName": "vpc-stacksets",
        "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "Description": "VPC",
        "Status": "ACTIVE",
        "TemplateBody": "AWSTemplateFormatVersion: \"2010-09-09\"\n\nDescription: VPC\n\nResources:\n  VPC:\n    Type: AWS::EC2::VPC\n    Properties:\n      CidrBlock: 10.0.0.0/16\n      Tags:\n        - Key: Name\n          Value: vpc\n",
        "Parameters": [],
        "Capabilities": [],
        "Tags": [],
        "StackSetARN": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stackset/vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "AdministrationRoleARN": "arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0",
        "ExecutionRoleName": "SetExecutionRole0",
        "StackSetDriftDetectionDetails": {
            "DriftStatus": "NOT_CHECKED",
            "TotalStackInstancesCount": 0,
            "DriftedStackInstancesCount": 0,
            "InSyncStackInstancesCount": 0,
            "InProgressStackInstancesCount": 0,
            "FailedStackInstancesCount": 0
        },
        "PermissionModel": "SELF_MANAGED",
        "OrganizationalUnitIds": [],
        "ManagedExecution": {
            "Active": false
        }
    }
}

次に、スタックインスタンスを作成します。

# スタックインスタンスの作成
$ aws cloudformation create-stack-instances \
    --stack-set-name vpc-stacksets \
    --accounts $(aws sts get-caller-identity --query Account --output text) \
    --regions us-east-1
{
    "OperationId": "27d52d60-05fd-41ed-a329-52157e392835"
}

# スタックインスタンスが作成されたことを確認
$ aws cloudformation describe-stack-set-operation \
    --stack-set-name vpc-stacksets \
    --operation-id 27d52d60-05fd-41ed-a329-52157e392835
{
    "StackSetOperation": {
        "OperationId": "27d52d60-05fd-41ed-a329-52157e392835",
        "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "Action": "CREATE",
        "Status": "SUCCEEDED",
        "OperationPreferences": {
            "RegionOrder": []
        },
        "AdministrationRoleARN": "arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0",
        "ExecutionRoleName": "SetExecutionRole0",
        "CreationTimestamp": "2022-11-16T07:34:43.750000+00:00",
        "EndTimestamp": "2022-11-16T07:35:07.871000+00:00"
    }
}

# 作成されたスタックを確認
$ aws cloudformation describe-stacks \
    --stack-name StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "Description": "VPC",
            "CreationTime": "2022-11-16T07:34:46.429000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

スタックインスタンスおよびスタックが作成されました。

管理者ロールと実行ロールの変更

本題の管理者ロールと実行ロールの変更を行います。

管理者ロールと実行ロールを以下のように変更します。

  • 管理者ロール : StackSetAdministrationRole0 -> StackSetAdministrationRole1
  • 実行ロール : SetExecutionRole0 -> SetExecutionRole1

AWS CLIでStackSetsを更新する際に、管理者ロールと実行ロールの変更します。

# StackSetsの更新
$ aws cloudformation update-stack-set \
    --stack-set-name vpc-stacksets \
    --description VPC \
    --template-body file://VPC.yml \
    --permission-model SELF_MANAGED \
    --administration-role-arn arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole1 \
    --execution-role-name SetExecutionRole1
{
    "OperationId": "e9adbd76-5586-4d4f-ad5f-cdbbdcb43d9a"
}

# スタックインスタンスが更新されたか確認
$ aws cloudformation describe-stack-set-operation \
    --stack-set-name vpc-stacksets \
    --operation-id e9adbd76-5586-4d4f-ad5f-cdbbdcb43d9a
{
    "StackSetOperation": {
        "OperationId": "e9adbd76-5586-4d4f-ad5f-cdbbdcb43d9a",
        "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "Action": "UPDATE",
        "Status": "SUCCEEDED",
        "OperationPreferences": {
            "RegionOrder": []
        },
        "AdministrationRoleARN": "arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole1",
        "ExecutionRoleName": "SetExecutionRole1",
        "CreationTimestamp": "2022-11-16T07:42:56.151000+00:00",
        "EndTimestamp": "2022-11-16T07:43:05.500000+00:00"
    }
}

スタックインスタンスが更新されたようです。対象のスタックを確認してみましょう。

# スタックで発生したイベントを確認
$ aws cloudformation describe-stack-events \
    --stack-name StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138
{
    "StackEvents": [
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "318771a0-6581-11ed-9596-1249b96ecf2f",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "PhysicalResourceId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2022-11-16T07:35:07.441000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "ClientRequestToken": "66056f82-9ae4-4acd-875a-487bb31f6e77"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-CREATE_COMPLETE-2022-11-16T07:35:05.932Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "vpc-025b0eaee5c83fda6",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T07:35:05.932000+00:00",
            "ResourceStatus": "CREATE_COMPLETE",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"vpc\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "66056f82-9ae4-4acd-875a-487bb31f6e77"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-CREATE_IN_PROGRESS-2022-11-16T07:34:53.928Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "vpc-025b0eaee5c83fda6",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T07:34:53.928000+00:00",
            "ResourceStatus": "CREATE_IN_PROGRESS",
            "ResourceStatusReason": "Resource creation Initiated",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"vpc\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "66056f82-9ae4-4acd-875a-487bb31f6e77"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-CREATE_IN_PROGRESS-2022-11-16T07:34:51.175Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T07:34:51.175000+00:00",
            "ResourceStatus": "CREATE_IN_PROGRESS",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"vpc\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "66056f82-9ae4-4acd-875a-487bb31f6e77"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "24e5f430-6581-11ed-b9d4-0a93a4753343",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "PhysicalResourceId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2022-11-16T07:34:46.429000+00:00",
            "ResourceStatus": "CREATE_IN_PROGRESS",
            "ResourceStatusReason": "User Initiated",
            "ClientRequestToken": "66056f82-9ae4-4acd-875a-487bb31f6e77"
        }
    ]
}

特にスタックでは更新が発生していないようです。

試しに以下のようにNameタグの値を変更して、StackSetsを更新してみます。

VPC.yml

AWSTemplateFormatVersion: "2010-09-09"

Description: VPC

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: VPC
# StackSetsの更新
$ aws cloudformation update-stack-set \
    --stack-set-name vpc-stacksets \
    --description VPC \
    --template-body file://VPC.yml \
    --permission-model SELF_MANAGED \
    --administration-role-arn arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole1 \
    --execution-role-name SetExecutionRole1
{
    "OperationId": "d6d0e687-7e72-4f94-956e-3357737494e5"
}

# StackSetsの更新が行われたか確認
$ aws cloudformation describe-stack-set-operation \
    --stack-set-name vpc-stacksets \
    --operation-id d6d0e687-7e72-4f94-956e-3357737494e5
{
    "StackSetOperation": {
        "OperationId": "d6d0e687-7e72-4f94-956e-3357737494e5",
        "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "Action": "UPDATE",
        "Status": "SUCCEEDED",
        "OperationPreferences": {
            "RegionOrder": []
        },
        "AdministrationRoleARN": "arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole1",
        "ExecutionRoleName": "SetExecutionRole1",
        "CreationTimestamp": "2022-11-16T07:52:19.501000+00:00",
        "EndTimestamp": "2022-11-16T07:52:32.184000+00:00"
    }
}

# スタックで発生したイベントの確認
$ aws cloudformation describe-stack-events \
    --stack-name StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138
{
    "StackEvents": [
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "9ffa3710-6583-11ed-b567-0a5fc6757e4b",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "PhysicalResourceId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2022-11-16T07:52:31.736000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "ClientRequestToken": "46116e23-7ace-41bc-a232-62358a63cfbb"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "9f841cb0-6583-11ed-8cff-0a0450a52555",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "PhysicalResourceId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2022-11-16T07:52:30.967000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS",
            "ClientRequestToken": "46116e23-7ace-41bc-a232-62358a63cfbb"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-UPDATE_COMPLETE-2022-11-16T07:52:29.208Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "vpc-025b0eaee5c83fda6",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T07:52:29.208000+00:00",
            "ResourceStatus": "UPDATE_COMPLETE",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"VPC\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "46116e23-7ace-41bc-a232-62358a63cfbb"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-UPDATE_IN_PROGRESS-2022-11-16T07:52:27.089Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "vpc-025b0eaee5c83fda6",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T07:52:27.089000+00:00",
            "ResourceStatus": "UPDATE_IN_PROGRESS",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"VPC\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "46116e23-7ace-41bc-a232-62358a63cfbb"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "9a20b7b0-6583-11ed-b70e-0e07992e27c5",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "PhysicalResourceId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2022-11-16T07:52:21.925000+00:00",
            "ResourceStatus": "UPDATE_IN_PROGRESS",
            "ResourceStatusReason": "User Initiated",
            "ClientRequestToken": "46116e23-7ace-41bc-a232-62358a63cfbb"
        },
.
.
(中略)
.
.
}

テンプレートを変更したらスタックの更新が行われましたね。管理者ロールや実行ロールを変更するだけではスタックは更新されず、CloudFormationのテンプレートやパラメーターに差分が発生した場合に初めて更新されるようです。

実行ロールのIAMポリシーの権限を足りなくする

最後に、実行ロールのIAMポリシーが権限不足になるように変更して様子を見てみます。

2つの実行ロールのIAMポリシーから以下のように"ec2:*"を削除しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "cloudformation:*",
                "s3:*"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

この状態で管理者ロールと実行ロールを以下のように変更します。

  • 管理者ロール : StackSetAdministrationRole1 -> StackSetAdministrationRole0
  • 実行ロール : SetExecutionRole1 -> SetExecutionRole0
# StackSetsの更新
$ aws cloudformation update-stack-set \
    --stack-set-name vpc-stacksets \
    --description VPC \
    --template-body file://VPC.yml \
    --permission-model SELF_MANAGED \
    --administration-role-arn arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0 \
    --execution-role-name SetExecutionRole0
{
    "OperationId": "a389d4f2-1c06-4ea4-b458-5e3cef048856"
}

# スタックインスタンスが更新されたことを確認
$ aws cloudformation describe-stack-set-operation \
    --stack-set-name vpc-stacksets \
    --operation-id a389d4f2-1c06-4ea4-b458-5e3cef048856
{
    "StackSetOperation": {
        "OperationId": "a389d4f2-1c06-4ea4-b458-5e3cef048856",
        "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "Action": "UPDATE",
        "Status": "SUCCEEDED",
        "OperationPreferences": {
            "RegionOrder": []
        },
        "AdministrationRoleARN": "arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0",
        "ExecutionRoleName": "SetExecutionRole0",
        "CreationTimestamp": "2022-11-16T09:11:55.746000+00:00",
        "EndTimestamp": "2022-11-16T09:12:04.668000+00:00"
    }
}

この後、スタックのイベントを確認しましたが、やはり更新は発生していませんでした。逆に言えば、スタックの更新が発生しないので、実行ロールの権限に不足があっても気づくことは難しそうです。

権限が不足していることを確認するために、また以下のようにNameタグの値を変更して、StackSetsを更新してみます。

VPC.yml

AWSTemplateFormatVersion: "2010-09-09"

Description: VPC

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Name
          Value: vpc

実行結果は以下の通りです。

# StackSetsの更新
$ aws cloudformation update-stack-set \
      --stack-set-name vpc-stacksets \
      --description VPC \
      --template-body file://VPC.yml \
      --permission-model SELF_MANAGED \
      --administration-role-arn arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0 \
      --execution-role-name SetExecutionRole0
{
    "OperationId": "71e5b46b-63b4-4a3d-aeec-57523217c343"
}

# スタックインスタンスが更新されたことを確認
$ aws cloudformation describe-stack-set-operation \
    --stack-set-name vpc-stacksets \
    --operation-id 71e5b46b-63b4-4a3d-aeec-57523217c343
{
    "StackSetOperation": {
        "OperationId": "71e5b46b-63b4-4a3d-aeec-57523217c343",
        "StackSetId": "vpc-stacksets:98e3efa2-e734-4382-a011-168a7582cfc4",
        "Action": "UPDATE",
        "Status": "FAILED",
        "OperationPreferences": {
            "RegionOrder": []
        },
        "AdministrationRoleARN": "arn:aws:iam::<AWSアカウントID>:role/StackSetAdministrationRole0",
        "ExecutionRoleName": "SetExecutionRole0",
        "CreationTimestamp": "2022-11-16T09:13:36.369000+00:00",
        "EndTimestamp": "2022-11-16T09:13:54.831000+00:00"
    }
}

# スタックで発生したイベントの確認
$ aws cloudformation describe-stack-events \
    --stack-name StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138 \
    --max-items 3
{
    "StackEvents": [
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "fe2ae9a0-658e-11ed-a451-12730e200e31",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "PhysicalResourceId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "ResourceType": "AWS::CloudFormation::Stack",
            "Timestamp": "2022-11-16T09:13:54.226000+00:00",
            "ResourceStatus": "UPDATE_ROLLBACK_FAILED",
            "ResourceStatusReason": "The following resource(s) failed to update: [VPC]. ",
            "ClientRequestToken": "63447ed6-9e06-4dec-8f54-6679ce821167"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-UPDATE_FAILED-2022-11-16T09:13:53.270Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "vpc-025b0eaee5c83fda6",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T09:13:53.270000+00:00",
            "ResourceStatus": "UPDATE_FAILED",
            "ResourceStatusReason": "Resource handler returned message: \"You are not authorized to perform this operation. Encoded authorization failure message: BNTtzHrughjydg620izP42rKEExXAh_gCc0dxnR68EZ2ftrro-ViJKjAwR0q_GJ_ZD6fymkzl5j6ZVs9YcSOrYA2jUL_ihpALBlsPWNtFfVAQpJMXoW8S5Mf89aJ0zlXvgsorQ3qeRMSc5TFQ1XFVYyWPDo8nTjMpwE83jAgZrt5DPIGXsAIci5_u3pGUgKBHUAWdCrFwBBmb_VJh4_SKa_WCSzizUUKmGEPHb7spiEzgb8zY3cpO9AWxYbwT1dpK2tzFjamh4zgQ3elNHlTQjkzw3xYcO_nlrjmc3fzYMYAwXdrzaBcT_HqtJ6fufks49b3pLjAu_GdCZl8WU0Z2RHrDmxzk9TXbmBKMyojFLv40DZxGFu0XCfLlu_2VPSFVtzooflPH0xXyv3vrlUgnyOhcpkdRThN5NnWjDQOurmrwYRI_7jnsH5nXvcFTJQC4HXC2UhwdW5gAr1vCCfEZZZB0ZzRUf8aVXEfcKsjrbbHPYJu-tzTbYLVpcAOOSmwMnvaPdy7gq0P4qPKA7nruG6jzkstgLTasKjdwMmBM0tRavtx-xVGkoAhS9LR-MxWVT3eoG36Tjdehzq5YXWOJvs--5Rza-DzDXJ63GgpMV4x1i_s1yxAzuf9fGHc7ccMoN2b_bpR3VozKGLtCzGMgGeQoXzPUplrKSYFMs-8A896C6riYBuQKLKjiQ-YOJz864wXi0KTNgCIDE1zpjTSLZlh6nPbZFZzWXWTo6lWpokqq4-srdOmoq7VnGsczmpB24tWti3btvDbjzMxG-uFVhHWNSJ33aYL3yUCGa5WX0AWvyOavHBIOR4i1MSt (Service: Ec2, Status Code: 403, Request ID: 72c044f8-c167-4c0f-8835-57f593bb98e1)\" (RequestToken: 7dc7663d-3419-990f-d274-873f892b58e6, HandlerErrorCode: AccessDenied)",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"VPC\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "63447ed6-9e06-4dec-8f54-6679ce821167"
        },
        {
            "StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138/24e33510-6581-11ed-b9d4-0a93a4753343",
            "EventId": "VPC-UPDATE_IN_PROGRESS-2022-11-16T09:13:51.800Z",
            "StackName": "StackSet-vpc-stacksets-ad8e1166-eb52-4798-8bd5-00692029f138",
            "LogicalResourceId": "VPC",
            "PhysicalResourceId": "vpc-025b0eaee5c83fda6",
            "ResourceType": "AWS::EC2::VPC",
            "Timestamp": "2022-11-16T09:13:51.800000+00:00",
            "ResourceStatus": "UPDATE_IN_PROGRESS",
            "ResourceProperties": "{\"CidrBlock\":\"10.0.0.0/16\",\"Tags\":[{\"Value\":\"VPC\",\"Key\":\"Name\"}]}",
            "ClientRequestToken": "63447ed6-9e06-4dec-8f54-6679ce821167"
        }
    ],
    "NextToken": "eyJOZXh0VG9rZW4iOiBudWxsLCAiYm90b190cnVuY2F0ZV9hbW91bnQiOiAzfQ=="
}

権限不足のためにスタックインスタンスの更新に失敗しましたね。

後から変えたくなっても安心

CloudFormation StackSets の管理者ロールと実行ロールを変更した際の挙動を確認してみました。

CloudFormationのテンプレートとパラメーターに差分がなければ、スタックの更新は発生しないということが分かり安心しました。

なお、AWS Organizationsと連携する場合は、StackSetsのアクセス許可はサービスマネージドを選択する場合が多いと思います。

StackSets作成後にAWS Organizationsを導入した場合、アクセス許可をサービスマネージドに変更したい場面もあるかと思いますが、スタックインスタンスがある場合はアクセス許可の方法を切り替えることができないようなので注意しましょう。

PermissionModel

Describes how the IAM roles required for stack set operations are created. You cannot modify PermissionModel if there are stack instances associated with your stack set.

UpdateStackSet - AWS CloudFormation

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!