---
title: "CloudFormation StackSetsとは？権限モデルの選び方・デプロイオプション・CLI手順と更新の落とし穴"
url: "https://www.issoh.co.jp/tech/details/8400/"
published: 2025-08-25
updated: 2026-10-02
categories: ["AWS"]
publisher: "株式会社一創"
---

# CloudFormation StackSetsとは？権限モデルの選び方・デプロイオプション・CLI手順と更新の落とし穴

CloudFormation StackSetsは、1つのテンプレートから複数のAWSアカウントと複数のリージョンへ、スタックの作成・更新・削除を1回の操作で行う機能です。本記事では、2つの権限モデルのどちらを選ぶか、同時実行数と失敗許容数の組み合わせで実際の並列数がどう決まるかを整理します。そのうえで、`create-stack-set`／`update-stack-set` のCLI手順と、一部のアカウントだけ更新したときに残りがOUTDATEDになる仕様まで、2026年10月時点のAWS公式ドキュメントとAPI仕様に沿って解説します。

## まとめ：StackSetsで最初に決めること

- StackSetは「1テンプレート＋1組のパラメータ」の入れ物で、展開先の1アカウント×1リージョンごとにスタックインスタンスが1つできます。StackSet自体はリージョン単位のリソースで、利用料は無料です（作ったリソースの料金はかかります）。
- 権限モデルは、AWS Organizations配下に配るならサービスマネージド、組織外のアカウントやOrganizationsの管理アカウント自身へ配るならセルフマネージドです。サービスマネージドは管理アカウントへはデプロイしません。
- 既定は同時実行1アカウント・失敗許容0です。並列数を上げても、既定のSTRICT\_FAILURE\_TOLERANCEでは実際の並列数が「失敗許容数＋1」で頭打ちになります。
- `update-stack-set` でテンプレートかパラメータを変えつつ対象を一部に絞ると、対象外のスタックインスタンスはOUTDATEDのまま残ります。
- 操作がSUCCEEDEDでも、失敗許容の範囲内で失敗したインスタンスが含まれることがあります。`FailedStackInstancesCount` を必ず確認します。

以下、仕組み→権限モデル→デプロイオプション→CLI手順→更新・失敗時の扱いの順に説明します。

## StackSetsの仕組み：管理者アカウント・StackSet・スタックインスタンス

StackSetsを作成・管理するアカウントを**管理者アカウント**、スタックが作られる側を**ターゲットアカウント**と呼びます。StackSetは同じテンプレートから作る複数スタックの入れ物で、個々のスタックはパラメータで差を付けられます。展開先の「アカウント×リージョン」1組ごとに**スタックインスタンス**ができ、これは実スタックへの参照です。作成に失敗した場合でもインスタンスは残り、失敗理由を保持します。

| 用語         | 実体               | 数え方の例                              |
| ---------- | ---------------- | ---------------------------------- |
| StackSet   | テンプレート1つ＋パラメータ1組 | リージョンごとに作成・表示                      |
| スタックインスタンス | アカウント×リージョンの1組   | 20アカウント×2リージョン＝40                  |
| オペレーション    | 作成・更新・削除・ドリフト検出  | CREATE／UPDATE／DELETE／DETECT\_DRIFT |

StackSetはリージョン単位のリソースなので、東京リージョンで作ったStackSetはコンソールを東京に切り替えないと見えません。CLIでも `--region` を作成時と揃えます。StackSetが持つテンプレートは常に1つで、一部のスタックだけに別テンプレートを割り当てることはできません。更新の適用範囲は絞れますが、その場合は範囲外のインスタンスが旧テンプレートのまま残ります（後述）。アカウントごとにテンプレートを変えたいなら、StackSetを分けます。

テンプレートの書き方とスタック操作そのものは、[AWS CloudFormationとは？テンプレートの書き方・スタック操作と更新で消える設定の防ぎ方](/tech/details/2927/)で解説しています。

## 権限モデルの選び方：セルフマネージドとサービスマネージド

StackSetを作るときに、`PermissionModel` を `SELF_MANAGED` か `SERVICE_MANAGED` から選びます。違いは「ターゲットアカウントのIAMロールを誰が用意するか」と「どのアカウントへ配れるか」です。

| 項目          | セルフマネージド        | サービスマネージド             |
| ----------- | --------------- | --------------------- |
| IAMロール      | 自分で2種類を作成       | CloudFormationが作成     |
| 配れる先        | ロールを作れる任意のアカウント | 同じ組織のアカウントのみ          |
| 管理アカウントへの展開 | 可               | 不可                    |
| 展開先の指定      | アカウントID         | 組織ルート・OU（＋アカウントフィルター） |
| 自動デプロイ      | なし              | OUへの追加・移動で自動実行        |
| マクロ・ネストスタック | 使える             | 使えない                  |

### セルフマネージドで作る2つのIAMロール

管理者アカウントに `AWSCloudFormationStackSetAdministrationRole`、各ターゲットアカウントに `AWSCloudFormationStackSetExecutionRole` を作ります。既定の構成では実行ロールがこの名前と完全一致している必要があり、信頼ポリシーで管理者アカウントを信頼させます。利用者ごとに配れるリソースを絞りたい場合は、別名の実行ロールを作って `ExecutionRoleName`（管理ロールは `AdministrationRoleARN`）で指定することもできます。AWSが配布しているサンプルテンプレート（`cloudformation-stackset-sample-templates-us-east-1` バケットの同名YAML）を使うと、実行ロールには `"Action": "*"` の管理者権限が付きます。公式ドキュメントも、作成後にStackSetで作るリソースの種類へ絞るよう注意しています。

見落としやすいのが `iam:PassRole` です。`AdministrationRoleARN` を指定しなくても、`CreateStackSet`／`UpdateStackSet` を呼ぶプリンシパルには管理ロールへの `iam:PassRole` が必要です。香港（ap-east-1）のように既定で無効なリージョンへ配る場合は、管理ロールの信頼ポリシーに `cloudformation.ap-east-1.amazonaws.com` のようなリージョン別サービスプリンシパルも追加します。

### サービスマネージドの前提：信頼されたアクセスと委任管理者

サービスマネージドを使うには、Organizationsで「すべての機能」を有効にし（一括請求機能だけの組織では作成不可）、管理アカウントの管理者が信頼されたアクセスを有効化します。有効化した時点で管理アカウントにサービスリンクロール `AWSServiceRoleForCloudFormationStackSetsOrgAdmin` が作られます。ターゲット側の `AWSServiceRoleForCloudFormationStackSetsOrgMember` と `stacksets-exec-*` という名前のサービスロールは、サービスマネージドのStackSetを作成したときに作られます。

管理アカウント以外にStackSetを運用させたい場合は、メンバーアカウントを委任管理者として登録します。登録できるのは組織あたり同時に5アカウントまでです。注意点として、委任管理者は組織内の全アカウントへ配る権限を持ち、管理アカウント側から特定OUや特定操作に絞ることはできません。委任管理者として操作するときは、CLIに `--call-as DELEGATED_ADMIN` を付けます。付け忘れると自分のアカウントのStackSetとして扱われ、目的のStackSetが見つかりません。

サービスマネージドのStackSetは、委任管理者が作ったものも含めて実体は管理アカウントに作られます。そして、管理アカウントがOUに含まれていても、管理アカウント自身へはスタックをデプロイしません。組織の構成は[AWS Organizationsとは？マルチアカウント管理・SCP/RCP・一括請求の仕組みと設計判断を実装者目線で解説](/tech/details/15618/)を参照してください。

### 権限モデルの選択条件

Organizationsで管理しているアカウントへ配るなら、サービスマネージドを選びます。ロールの配布が不要になり、新しく作ったアカウントにも自動デプロイで行き渡るからです。セルフマネージドを選ぶ代表的な条件は次の3つです。組織外のアカウントへ配る場合、管理アカウント自身にも同じリソースを置く場合、そしてテンプレートで `AWS::Serverless-2016-10-31` などのトランスフォーム（マクロ）やネストスタックを使う場合です。サービスマネージドは、マクロとトランスフォームを含むテンプレートの作成・更新に対応していません。このほか、管理者アカウント内で利用者ごとに操作できるStackSetや配れるリソースを細かく分けたい場合も、カスタムの管理ロール・実行ロールを使えるセルフマネージドが候補になります。

## デプロイオプション：同時実行数・失敗許容・リージョン順序

作成・更新・削除の各操作には `--operation-preferences`（API名 `StackSetOperationPreferences`）を渡せます。既定値は[StackSetOperationPreferencesのAPIリファレンス](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API%5FStackSetOperationPreferences.html)に明記されています。

| パラメータ                            | 意味                              | 既定         |
| -------------------------------- | ------------------------------- | ---------- |
| MaxConcurrentCount／Percentage    | 同時に処理するアカウント数                   | 1          |
| FailureToleranceCount／Percentage | リージョンごとの許容失敗数                   | 0          |
| RegionConcurrencyType            | SEQUENTIAL／PARALLEL             | SEQUENTIAL |
| RegionOrder                      | リージョンの処理順                       | 指定なし       |
| ConcurrencyMode                  | STRICT／SOFT\_FAILURE\_TOLERANCE | STRICT     |

Count と Percentage は同時に指定できず、どちらか一方を使います。パーセント指定は端数切り捨てで、10アカウントに25%なら2アカウントずつです。ただし `MaxConcurrentPercentage` は、切り捨てて0になる場合だけ1に繰り上がります。失敗許容は「リージョンごと」に数え、あるリージョンで超えた時点で操作全体がFAILEDになり、後続リージョンには進みません。

### STRICTとSOFTで実際の並列数が変わる仕組み

既定の `STRICT_FAILURE_TOLERANCE` では、実際の並列数は「MaxConcurrentCount」と「FailureToleranceCount＋1」の小さい方から始まり、失敗が出るたびに減っていきます。最大同時実行を10、失敗許容を5にしても、実際には6並列で始まります。公式の計算例では、1,000インスタンスに最大同時実行250・失敗許容100で臨むと、STRICTは101並列から始まり、5バッチ・305件を処理したところで止まり、成功は205件です。

`SOFT_FAILURE_TOLERANCE` は失敗許容と並列数を切り離し、失敗が出ても最大同時実行の値で走り続けます。設定値が同じでも、SOFTは250並列のまま進みます。公式の例は各バッチ50件の失敗を仮定しており、2バッチ・500件を処理して成功は400件です。その代わり、失敗許容に達した時点で並列実行の枠に入っている処理は中断されず最後まで走るため、失敗数が許容値を超えます。公式の図解では、失敗許容5に対して最終的に8件が失敗しています。新規アカウントへの初回展開のように、既存リソースとの衝突やクォータ不足で一定数の失敗が見込まれる場面はSOFT、本番の設定変更のように失敗を最小にしたい場面はSTRICTが向いています。

### 「SUCCEEDED」でも失敗したインスタンスが残るケース

操作のステータスがSUCCEEDEDになる条件は「失敗数が失敗許容を超えなかったこと」で、全件成功ではありません。失敗許容を9、最大同時実行を10のように広めに取ると、何件か失敗してもSUCCEEDEDで終わります。CI/CDでステータスだけを見て成否を判定していると、この取りこぼしに気付けません。`describe-stack-set-operation` の `StatusDetails.FailedStackInstancesCount` を併せて確認してください。

### リージョン順序と段階展開の決め方

SEQUENTIALでは `RegionOrder` の順に1リージョンずつ処理します。公式のベストプラクティスは、慎重に展開するなら最大同時実行1・失敗許容0とし、影響の小さいリージョンを先頭に置いて1リージョンから始める構成です。PARALLELは全リージョンを同時に処理するので速く終わりますが、テンプレートの誤りが全リージョンへ同時に広がります。

## AWS CLIでStackSetを作成する手順

ここではサービスマネージドで、指定OU配下の全アカウントの東京・大阪リージョンへ配る流れを示します。例中のS3 URL・アカウントID・OU IDは自分の環境の値に置き換え、テンプレートは事前にS3へ配置しておきます。StackSetはリージョン単位なので、以降のコマンドはすべて同じ管理リージョン（`--region` またはプロファイルの既定）で実行します。最初に、管理アカウントで信頼されたアクセスを有効化します（コンソールのStackSets画面のバナーからでも可能です）。

```
aws cloudformation activate-organizations-access

aws cloudformation create-stack-set \
  --stack-set-name audit-baseline \
  --template-url https://example-bucket.s3.ap-northeast-1.amazonaws.com/audit-baseline.yaml \
  --permission-model SERVICE_MANAGED \
  --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false \
  --managed-execution Active=true \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameters ParameterKey=AuditAccountId,ParameterValue=111122223333

aws cloudformation create-stack-instances \
  --stack-set-name audit-baseline \
  --deployment-targets OrganizationalUnitIds=ou-abcd-11111111 \
  --regions ap-northeast-1 ap-northeast-3 \
  --operation-preferences RegionConcurrencyType=SEQUENTIAL,MaxConcurrentCount=1,FailureToleranceCount=0

aws cloudformation describe-stack-set-operation \
  --stack-set-name audit-baseline \
  --operation-id <create-stack-instancesが返したOperationId>
```

`create-stack-set` は入れ物を作るだけで、この時点ではスタックは1つもできません。実際の展開は `create-stack-instances` で始まります。`describe-stack-set-operation` は `--stack-set-name` と `--operation-id` の両方が必須で、公式ガイドの一部の例にある `--operation-id` だけの書き方はAPI仕様上エラーになります。セルフマネージドの場合は、`--permission-model SELF_MANAGED` で作成し、`--deployment-targets` の代わりに `--accounts 111122223333 444455556666` を渡します。

特定アカウントだけに絞るときは、`--deployment-targets` に `AccountFilterType` を付けます。値は `INTERSECTION`（OU内の指定アカウントのみ）、`DIFFERENCE`（指定アカウントを除外）、`UNION`（OUに加えて指定アカウント）、`NONE`（OU内すべて）の4つです。APIリファレンスでは省略時の既定値は `UNION` ですが、`create-stack-instances` では `UNION` を使えません（コンソールの選択肢は「なし」が既定です）。

### テンプレート例：IAMロールの単一リージョン作成

StackSetsの初歩的な失敗に、IAMロールのようなグローバルリソースを名前固定で作り、2つ目のリージョンで名前が衝突するケースがあります。公式のベストプラクティスも、同じアカウントの複数リージョンで作られるグローバルリソースの名前衝突に注意するよう求めています。次のテンプレートは、監査用ロールをHomeRegionだけで作り、SNSトピックは全リージョンにリージョン名付きで作ります。

```
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  AuditAccountId:
    Type: String
    AllowedPattern: "^[0-9]{12}$"
  HomeRegion:
    Type: String
    Default: ap-northeast-1
Conditions:
  IsHomeRegion: !Equals [!Ref "AWS::Region", !Ref HomeRegion]
Resources:
  AuditReadOnlyRole:
    Type: AWS::IAM::Role
    Condition: IsHomeRegion
    Properties:
      RoleName: org-audit-readonly
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:${AWS::Partition}:iam::${AuditAccountId}:root"
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess"
  SecurityAlertTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub "security-alerts-${AWS::Region}"
```

このテンプレートはcfn-lint 1.57.1で警告なしに通ります。一方、`Condition: IsHomeRegion` の1行を消すと、cfn-lintは「条件が未使用」という警告（W8001）しか出しません。名前衝突そのものは静的検査では検出できず、2つ目のリージョンへの展開で初めて失敗します。テンプレート検証の導入は[cfn-lintとは？CloudFormationテンプレート検証の導入・設定・CI組み込み](/tech/details/10676/)で扱っています。

## update-stack-setとupdate-stack-instancesの使い分け

テンプレートや共通パラメータを変えるのが `update-stack-set`、特定のアカウント・リージョンのパラメータだけを上書きするのが `update-stack-instances` です。テンプレートを変えない場合は `--use-previous-template` を付けます。

```
aws cloudformation update-stack-set \
  --stack-set-name audit-baseline \
  --use-previous-template \
  --parameters ParameterKey=AuditAccountId,ParameterValue=999988887777 \
  --capabilities CAPABILITY_NAMED_IAM \
  --operation-preferences MaxConcurrentPercentage=25,FailureToleranceCount=0

aws cloudformation update-stack-instances \
  --stack-set-name audit-baseline \
  --deployment-targets OrganizationalUnitIds=ou-abcd-11111111 \
  --regions ap-northeast-1 ap-northeast-3 \
  --parameter-overrides ParameterKey=AuditAccountId,ParameterValue=444455556666
```

### 対象を絞った更新で残りがOUTDATEDになる仕様

`update-stack-set` に `--accounts`／`--deployment-targets` と `--regions` を付けると、更新対象を一部に絞れます。ただし、[UpdateStackSetのAPIリファレンス](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API%5FUpdateStackSet.html)には、テンプレートかパラメータを変更する更新では、指定した範囲を更新する前に**すべての**スタックインスタンスをOUTDATEDにする、と書かれています。つまり、テスト用OUだけ先に更新すると、他のOUのインスタンスは古いテンプレートのままOUTDATEDとして残り、次に対象を広げて更新するまで解消しません。テンプレートもパラメータも変えない更新（タグや実行設定だけの変更など）なら、対象外のインスタンスは元のステータスのままです。

もう1つの仕様として、更新操作が一部またはすべて失敗しても、StackSet側の定義は変更後の内容に更新されます。以降の `create-stack-instances` は新しい定義で展開されるので、失敗したらテンプレートを直して再度更新するのが基本です。なお、1回の `UpdateStackSet` で指定できるOUは50までです。

### パラメータ上書きの効く範囲

`--parameter-overrides` で上書きした値は、その後の `update-stack-set` でも維持されます。上書きできるのはStackSetに定義済みのパラメータの値だけで、パラメータの追加や削除にはテンプレートの更新が必要です。サービスマネージドでOU単位に上書きした値が効くのは、その時点でOUにいるアカウントだけです。後からOUに追加されたアカウントには、自動デプロイでもStackSetの既定値が使われます。本番OUだけ値を変える運用では、新規アカウントの追加後に上書きをかけ直す手順を残しておきます。

### マネージド実行（ManagedExecution）と同時操作

既定（`ManagedExecution Active=false`）では、1つのStackSetに対する操作は要求順に1件ずつ実行されます。`Active=true` にすると、競合しない操作は並行実行され、競合する操作は自動でキューに入って要求順に処理されます。ただし、実行中またはキュー待ちの操作があるときは、競合しない操作もすべてキューに入り、その間は実行設定を変更できません。公式ベストプラクティスのページには今も「1つのStackSetで同時に許される操作は1つ」と書かれていますが、これはマネージド実行が無効な場合の挙動です。

## 失敗時の切り分けと再試行

スタックインスタンスの状態は、StackSetとの同期状態を示す `Status` と、直近操作の結果を示す `DetailedStatus` の2層で見ます。

| Status     | 意味              | 対処                |
| ---------- | --------------- | ----------------- |
| CURRENT    | StackSetと同期済み   | 不要                |
| OUTDATED   | 作成・更新の失敗や停止で未同期 | 原因を直して再更新         |
| INOPERABLE | 削除やインポートの失敗で不安定 | retain付きで外し原因別に復旧 |

失敗したインスタンスは次の2コマンドで特定できます。前者は操作ごとの結果、後者は直近操作で失敗したインスタンスの一覧です。

```
aws cloudformation list-stack-set-operation-results \
  --stack-set-name audit-baseline --operation-id <OperationId> \
  --filters Name=OPERATION_RESULT_STATUS,Values=FAILED

aws cloudformation list-stack-instances \
  --stack-set-name audit-baseline \
  --filters Name=DETAILED_STATUS,Values=FAILED Name=LAST_OPERATION_ID,Values=<OperationId>
```

セルフマネージドでロール設定に問題があると、`StatusReason` に次のようなメッセージが出ます。`Account 123456789012 should have 'AWSCloudFormationStackSetExecutionRole' role with trust relationship to Role 'AWSCloudFormationStackSetAdministrationRole'.` ターゲット側の実行ロールが無いか、信頼ポリシーの管理者アカウントIDが違います。このほか公式のトラブルシューティングには、ターゲットアカウントの権限不足、S3バケット名などグローバルに一意な名前の衝突、IAMロール数などのクォータ到達が挙がっています。インスタンスの削除が失敗する場合は、対象スタックで削除保護（termination protection）が有効になっていないかを確認します。

原因を直したら、同じテンプレートのまま `update-stack-set` を再実行するとOUTDATEDのインスタンスが再試行されます。INOPERABLEになったインスタンスは以後の更新対象から外れるので、まず `delete-stack-instances --retain-stacks` でStackSetから切り離します。削除の失敗が原因なら、残ったスタックをターゲットアカウント側で手動削除します。インポートの失敗が原因なら、スタックは消さずにエラー原因を直し、インポートをやり直します。

## 自動デプロイと依存関係の指定（DependsOn）

サービスマネージドで `AutoDeployment Enabled=true` にすると、対象OUへのアカウント追加・削除・OU間移動をきっかけに展開が自動で走ります。OU1からOU2へアカウントを移すと、OU1側のStackSetのスタックを削除する操作が走り、OU2側のStackSetの作成操作がキューに入ります。アカウントがOUから外れたときにスタックを消すか残すかは `RetainStacksOnAccountRemoval` で決めます。

自動デプロイはStackSet単位の設定で、OU・アカウント・リージョンごとには切り替えられません。また、前述の同時実行数や失敗許容（`StackSetOperationPreferences`）は自動デプロイには適用されません。また、アカウントフィルターを考慮しないため、`INTERSECTION` で特定アカウントに絞っていても、OUに新しく入ったアカウントへは展開されます。絞り込みを守りたいStackSetでは、自動デプロイを無効にしてください。

2025年11月21日に、自動デプロイの `DependsOn` が追加されました。依存先StackSetのARNを指定すると、ネットワークやセキュリティのスタックが完了してからアプリケーションのスタックを展開する、という順序を保証できます。上限はStackSetあたり10件・アカウントあたり100件で、循環依存は自動検出されます（[自動デプロイの公式ガイド](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-orgs-manage-auto-deployment.html)）。公式ドキュメントは、自動デプロイを使う場合にマネージド実行を有効にすることを推奨しています。

```
aws cloudformation update-stack-set \
  --stack-set-name app-baseline \
  --use-previous-template \
  --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=true,DependsOn=arn:aws:cloudformation:ap-northeast-1:111122223333:stackset/network-baseline:example-id
```

OUの設計とガードレールをまとめて用意するなら、StackSetsを内部で使っている[AWS Control Towerとは？ランディングゾーン4.0の仕組み・料金の実額と導入判断をCLI例つきで解説](/tech/details/15623/)も比較対象になります。

## AWS::CloudFormation::StackSetによるStackSet定義のコード化

StackSetの定義そのものをテンプレートで管理したい場合は、リソースタイプ `AWS::CloudFormation::StackSet` を使います。必須プロパティは `StackSetName` と `PermissionModel` で、展開先は `StackInstancesGroup` に書きます。

```
Parameters:
  TargetOuId:
    Type: String
  AuditAccountId:
    Type: String
Resources:
  AuditBaselineStackSet:
    Type: AWS::CloudFormation::StackSet
    Properties:
      StackSetName: audit-baseline
      PermissionModel: SERVICE_MANAGED
      Capabilities:
        - CAPABILITY_NAMED_IAM
      AutoDeployment:
        Enabled: true
        RetainStacksOnAccountRemoval: false
      ManagedExecution:
        Active: true
      OperationPreferences:
        RegionConcurrencyType: SEQUENTIAL
        MaxConcurrentPercentage: 25
        FailureTolerancePercentage: 10
      Parameters:
        - ParameterKey: AuditAccountId
          ParameterValue: !Ref AuditAccountId
      TemplateURL: https://example-bucket.s3.ap-northeast-1.amazonaws.com/audit-baseline.yaml
      StackInstancesGroup:
        - DeploymentTargets:
            OrganizationalUnitIds:
              - !Ref TargetOuId
          Regions:
            - ap-northeast-1
            - ap-northeast-3
```

このテンプレートで検証すると、cfn-lint 1.57.1は2種類の誤りを見逃しました。1つは `MaxConcurrentPercentage` と `MaxConcurrentCount` の併記で、もう1つはサービスマネージドなのに `AutoDeployment` を省いた定義です。どちらもエラーを出さずに通りましたが、APIリファレンスでは前者は「どちらか一方のみ」、後者は「SERVICE\_MANAGEDでは必須」とされています。オペレーション設定はlintに頼らず、目で確認してください。

## 削除・ドリフト検出・既存スタックの取り込み

StackSetはスタックインスタンスが0件のときしか削除できません。先に `delete-stack-instances` で全インスタンスを消し、この削除操作は非同期なので完了を待ってから `delete-stack-set` を実行します。このコマンドは `--retain-stacks` か `--no-retain-stacks` の指定が必須です。`--retain-stacks` を選ぶとスタックとリソースはターゲットアカウントに残り、以後はそのアカウントの通常スタックとして管理します。

```
aws cloudformation delete-stack-instances \
  --stack-set-name audit-baseline \
  --deployment-targets OrganizationalUnitIds=ou-abcd-11111111 \
  --regions ap-northeast-1 ap-northeast-3 \
  --no-retain-stacks

# 返されたOperationIdがSUCCEEDEDになり、一覧が空になったことを確認してから実行
aws cloudformation describe-stack-set-operation \
  --stack-set-name audit-baseline --operation-id <OperationId>
aws cloudformation list-stack-instances --stack-set-name audit-baseline

aws cloudformation delete-stack-set --stack-set-name audit-baseline
```

手作業による変更は `detect-stack-set-drift` で全インスタンスについて一括検出でき、結果は `list-stack-instances` の `DRIFT_STATUS` フィルターで絞り込めます。既存の個別スタックをStackSetの管理下へ移すときは `import-stacks-to-stack-set` を使います。1回で取り込めるのはスタックIDの直接指定なら10件、S3オブジェクト経由なら200件までです。`NoEcho` のパラメータを持つスタックは新規StackSetへ取り込めず、1つのスタックは1つのStackSetにしか属せません。

## StackSetsの上限値（クォータ）と料金

| 項目                              | 上限      |
| ------------------------------- | ------- |
| 管理者アカウントあたりのStackSet数           | 1,000   |
| StackSetあたりのスタックインスタンス数         | 100,000 |
| リージョンごとの同時インスタンス操作（管理者アカウント単位）  | 10,000  |
| StackSetあたりのキュー済み操作             | 10,000  |
| S3経由のインポート（1操作）                 | 200スタック |
| 委任管理者（組織あたり）                    | 5アカウント  |
| DependsOn（StackSetあたり／アカウントあたり） | 10／100  |

値は[CloudFormationのクォータ一覧](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html)などの公式ドキュメントによります。StackSet数とインスタンス数はService Quotasで引き上げを申請できます。StackSets自体の利用料はかからず、課金されるのは展開したリソース（AWS Configの記録やSNSなど）です。展開先の数だけ同じリソースが作られるので、Configのように記録単位で課金されるサービスを全アカウント×全リージョンへ配ると、各展開先の利用量に応じた料金が展開先の数だけ積み上がります。

## StackSetsの採用を避ける条件

StackSetsは「全アカウントに同じものを置く」用途には強い一方、次の条件ではほかの仕組みの方が運用しやすくなります。

- アカウントごとにリソース構成が大きく違う場合。パラメータ上書きで吸収できる範囲を超えると、StackSetを分けるか、アカウント別のパイプラインで通常スタックを配る方が差分を追えます。
- 利用部門が必要なときに自分で構成を選んで作る場合。中央から一斉に配る形が合わないため、[AWS Service Catalogとは？仕組み・ポートフォリオ設計と組織展開の判断を実装者目線で解説](/tech/details/15630/)のセルフサービス型が向いています。
- SAMのトランスフォームやネストスタックを組織全体に配りたい場合。サービスマネージドでは使えないので、セルフマネージドでロールを配るか、テンプレートを展開済みの形に変換します。

逆に、ガードレール用のIAMロール・AWS Config・GuardDuty設定・通知用SNSのように、どのアカウントにも同じテンプレートで必要なものは、サービスマネージド＋自動デプロイが適しています。各アカウントへのロール配布が不要になり、OUに追加したアカウントへの展開も自動で行われるからです。

## よくある質問

### CloudFormation StackSetsとは何ですか？

1つのCloudFormationテンプレートから、複数のAWSアカウントと複数のリージョンへスタックをまとめて作成・更新・削除する機能です。管理者アカウントでStackSetを作り、展開先の「アカウント×リージョン」ごとにスタックインスタンスができます。

### StackSetsの料金はかかりますか？

StackSets自体は無料です。課金されるのは、StackSetで各アカウント・リージョンに作成したAWSリソースの利用料です。

### サービスマネージドのStackSetが管理アカウントにデプロイされないのはなぜですか？

仕様です。サービスマネージドでは、管理アカウントがOUに含まれていても管理アカウントへはスタックを作りません。管理アカウントにも同じリソースが必要なら、セルフマネージドのStackSetか通常のスタックで別に作成します。

### aws cloudformation update-stack-setで一部のアカウントだけ更新できますか？

できます。`--accounts` または `--deployment-targets` と `--regions` で範囲を絞ります。ただし、テンプレートかパラメータを変える更新では、範囲外のインスタンスもOUTDATEDになり、範囲を広げて更新するまでその状態が残ります。

### スタックセットとスタックの違いは何ですか？

スタックは1アカウント・1リージョンにあるリソースのまとまりです。スタックセット（StackSet）は、同じテンプレートから作った複数のスタックを、アカウントとリージョンをまたいでまとめて管理する入れ物です。

## 関連記事

- [AWS CloudFormationとは？テンプレートの書き方・スタック操作と更新で消える設定の防ぎ方](/tech/details/2927/)
- [AWS Organizationsとは？マルチアカウント管理・SCP/RCP・一括請求の仕組みと設計判断を実装者目線で解説](/tech/details/15618/)
- [AWS Control Towerとは？ランディングゾーン4.0の仕組み・料金の実額と導入判断をCLI例つきで解説](/tech/details/15623/)
- [AWS Service Catalogとは？仕組み・ポートフォリオ設計と組織展開の判断を実装者目線で解説](/tech/details/15630/)
- [cfn-lintとは？CloudFormationテンプレート検証の導入・設定・CI組み込み](/tech/details/10676/)

---

出典: [CloudFormation StackSetsとは？権限モデルの選び方・デプロイオプション・CLI手順と更新の落とし穴](<https://www.issoh.co.jp/tech/details/8400/>)（株式会社一創）
