AWS CloudFormation で Git Sync を試してみた

# はじめに
ＡＷＳでゼロからサイトを作る機会ができたので、表題の機能を使用してサイト構築をしてみた。
今ひとつ知見が足りないというか、説明読んでも、エッセンシャルな要素と、設定を同時に試みてるせいで、両者の区別が付かず、参考になる指標が分からなかったので、実際の手を動かしてみた結果から各フェーズで必要となる要素をまとめてみた。
あと妙に不安定な挙動を見つけたので理由が判明。ＡＷＳのドキュメントに誤りが…。

# 前提条件
- とりあえずクラウドフォーメーションやＩＡＭ等は知ってる前提として説明します（設定方法がわからない、は無しで）。
- ＧｉｔＨｕｂとの連携を前提として他のサービス[^services]との連携については見なかった物とします。
- ＧｉｔＨｕｂ側の権限問題や `AWS CodeConnections`[^codestar] についての詳細は省きます。
- とりあえずの初期設定はＩＡＭユーザーによる操作[^rootpriv]を行うものとして、その際 `AdministoratorAccess` ポリシーが適用されているものとします。クラウドフォーメーションやＩＡＭロール等の、必要な操作に絞った権限でどこまでできるかのチキンレースはしません。
- 準備自体（ＩＡＭユーザーやＩＡＭロールの作成）をクラウドフォーメーションで実施することについては、むしろ推奨しますが、管理コンソール上の作業がメインになる点に留意してください。ＣＬＩで実施しても問題ありませんが、そのための解説はしません。
- とは言え作ったＩＡＭロールを消してしまう（更新するつもりが）事故が無いことも無いので、手動で回復する余地は残しておいた方が良いです。
- またＧｉｔＳｙｎｃそのものの設定はＣＬＩでは実施できないようです[^inthistime]。
- 初期に作成したスタックを、後からＧｉｔＳｙｎｃすることができます。焦って同時に設定しようと思わないことが設定のコツです。
- 管理コンソールからであれば、ＧｉｔＳｙｎｃ設定からのスタック作成（デプロイ）ができますが、若干不安定さを感じることがありました。上手くスタックが作れなかった場合、まずはスタック作成し、後からＧｉｔＳｙｎｃすると良いです。
- 今のところＣＬＩ（＝公開ＡＰＩ）からＧｉｔＳｙｎｃを設定する方法は無いと思われます[^inthistime]。重要なので二回言ってみた。
- つまりスタックを追加する度に管理コンソールでの操作が必要です。テンプレートファイルを入れたら、新しくスタックを作ってくれるほど便利ではありません。
- ここはクラウドフォーメーションのスタックを作るためのクラウドフォーメーション化が…。

[^inthistime]: ２０２４年０８月現在。
[^services]: `Bitbucker`、`GitHub`、`GitHub Enterprise Server`、`GitLab`、`GitLab Self Managed` に対応[^inthistime]しています。
[^rootpriv]: ルートユーザーで作業しても良いですが、その差異については見なかったものとします（どうなるか知らない）。
[^codestar]: [AWS CodeConnections (旧称 AWS CodeStar Connections) のご紹介](https://aws.amazon.com/jp/about-aws/whats-new/2024/03/aws-codeconnections-formerly-codestar-connections/)

## 要素
- Ｇｉｔリポジトリの作成
- ＧｉｔＨｕｂとの接続設定（`AWS CodeConnections`）
- ＩＡＭロール（２種類）の作成
    - `cloudformation.sync.codeconnections.amazonaws.com` プリンシパルのための許可権限
    - `cloudformation.amazonaws.com` プリンシパルのための許可権限
- スタックの作成
    - デプロイファイル
    - テンプレートファイル
    - ＧｉｔＳｙｎｃの設定
- スタックの削除
    - ＧｉｔＳｙｎｃの設定解除と `AWS CodeConnections` に関する注意

# 事前準備
- ＧｉｔＨｕｂ上でリポジトリを作成します。
    - 運用上の要請から、おそらくはプライベートリポジトリを作成することになると思われ。
    - 一つでもファイルが無いとブランチの存在を認識しれくれなかったので、`README.md` ファイルでも置いておきます（０バイトでも良い）。
- [ＡＷＳ管理コンソール](https://console.aws.amazon.com/codesuite/settings/connections)（CodePipeline→設定→接続）から「接続を作成」ボタンを押して、ＧｉｔＨｕｂとの連携を実施しておきます。
    - [GitHub への接続を作成する (コンソール）](https://docs.aws.amazon.com/ja_jp/dtconsole/latest/userguide/connections-create-github.html#connections-create-github-console)の手順が参考になります。
    - この時どのリージョンで設定すべきかはよく分かっていません。
    - `ap-northeast-1` 上で設定して、`ap-northeast-1`、`us-east-1` のどちらのクラウドフォーメーションでも `AWS CodeConnections` の設定が参照され、スタックがデプロイできることを確認しています。
    - このことからメインで使うリージョン（`ap-northeast-1` など）に「接続」設定を用意しておくのが無難と思われます。
    - [ＣＬＩで設定](https://docs.aws.amazon.com/ja_jp/dtconsole/latest/userguide/connections-create-github.html#connections-create-github-cli)しても良いですが、最終的に管理コンソールにアクセスすることになります。
- 最低でも２つのプリンシパルに関する、２つ（以上）のＩＡＭロールを作成することになります（後述）。
    - `cloudformation.sync.codeconnections.amazonaws.com` プリンシパル（一つ）の許可権限設定
    - `cloudformation.amazonaws.com` プリンシパル（一つ以上）の許可権限設定
- デプロイファイル
    - 事前に作成しない方が良いです／しないことを推奨します。
    - が、事前に作成しておいた場合、差分ゼロのプルリクエストが発生することがあります。
    - リポジトリ更新（`git push`）後、数分以内の場合、不安定な挙動が見られます。
    - スタックのテンプレートとしてのファイルのパスを指定します（ＭＵＳＴ）。
    - テンプレートファイルのパラメータを指定します（オプション）。
        - テンプレート中にパラメータが必要な場合は、先にデプロイファイル側にも用意しておく必要があります。
        - テンプレートファイル更新後、デプロイファイルにそれを反映すると、同期に失敗することがあります。その場合「Ｇｉｔと同期」タブから「最新のコミットを再試行」ボタンを押す必要があります。
    - スタックのタグを指定します（オプション）。
- テンプレートファイル
    - スタック作成時に無くても良いですが、事前に作成しておく方が安全です。
    - いわゆるシステム構成が記述されたＹＡＭＬまたはＪＳＯＮのファイルです。
    - 先にテンプレートファイルを作らずにＧｉｔＳｙｎｃした場合の動作については見守ることが必要かも知れません。途中よく分からない理由で止まってることもあります。

[GitHub からの AWS CloudFormation デプロイ自動化](https://aws.amazon.com/jp/blogs/news/automate-safe-aws-cloudformation-deployments-from-github-jp/)の説明が非常に参考になりますが、いかんせん、余計なことを行い過ぎて、何が必須か分からないのが不満です。
たとえば「CodeSpace の設定」や「Pull Request アクションの追加」なんての後回しで良いです。本質的に余計なお世話です。
また「ＩＡＭロール」と「アクセス許可」の二カ所でＩＡＭロール名を指定することになっていますが、まるで説明されていません。この二つはわかりにくい割に、非常に重要なポイントなのですが、何故か説明がありません。

## cloudformation.sync.codeconnections.amazonaws.com プリンシパルと許可権限設定
これはＧｉｔＳｙｎｃの設定時に「ＩＡＭロール」の設定箇所で「新しいＩＡＭロール」または「既存のＩＡＭロール」で指定される時に参照される「プリンシパル」です。
- 実行主体（ＡＷＳ内で定義されるサービス）が `cloudformation.sync.codeconnections.amazonaws.com` であることを意味します。
- よって信頼されたエンティティにて `"Principal": {"Service": "cloudformation.sync.codeconnections.amazonaws.com"}` として定義されたＩＡＭロールだけが「既存のＩＡＭロール」で指定の対象になります。
- このロールの実行にあたってはプリンシパルが `cloudformation.sync.codeconnections.amazonaws.com` のものであるものだけ、というアクションを受けるよう、制限を入れるようにします（`Condition:`行）。
- 複数のＩＡＭロール、あるいは毎回「新しいＩＡＭロール」を指定しても良いですが、一つで必要十分を賄えます。
- 「新しいＩＡＭロール」で作られたＩＡＭロールを調べたところ、そのスタックに制約されたＩＡＭロールが作成されるだけで、汎用的に使えませんでした。それなら先に一つ作って使い回す方がマシです。

このＩＡＭロールの役割は以下の作業を実施するのに必要な権限となります。
- イメージとしては作業しているＩＡＭユーザーの代わりに、当該プリンシパルがチェンジセットの作成や適用等を実施するというニュアンスになります。
- この時ＧｉｔＨｕｂから `git clone`、`git pull` します。
- その後、指定された「デプロイファイル」から「テンプレートファイル」のチェンジセットのバリデーション、作成や実行等を行います。

本ＩＡＭロールを設定するにあたり、定義されるロール名とポリシー名についてですが `cloudformation-git-sync-role`（`cloudformation-git-sync-policy`） ないしは `CloudFromationGitSyncRole`（`CloudFromationGitSyncPolicy`） みたいな形を提案します。
少なくとも `AWS` で始めるのは推奨しません。そちらはＡＷＳ用のプレフィックスになるかと思います。他にも `My` とか `Custom` とか `屋号` で始めるのもいいかもしれません。

## cloudformation.amazonaws.com プリンシパルと許可権限設定
これはＧｉｔＳｙｎｃの設定時に「アクセス許可」の「ＩＡＭロール」の選択箇所で指定される時に参照される「プリンシパル」です。
イメージとしてはチェンジセットが適用される際に必要となる、リソース作成・変更・削除のため権限が、作業者のＩＡＭユーザーから、このプリンシパル（サービス）に変わりますよ、というニュアンスになります。
よってそのリソースに関する各種権限が必要になります。マネージドポリシー適応しておければ十分だと思います。
- 実行主体（ＡＷＳ内で定義されるサービス）が `cloudformation.amazonaws.com` であることを意味します。
- よって信頼されたエンティティにて `"Principal": {"Service": "cloudformation.amazonaws.com"}` として定義されたＩＡＭロールだけが「ＩＡＭロール」での指定の対象になります。
- スタック一つ一つ毎に設定されることが期待されています。
- このＩＡＭロールの目的は、`cloudformation.amazonaws.com` が実際にＡＷＳリソースを作成するのに必要な最小限の権限を与えることが期待されているからです。
- 面倒なら（通常面倒に思われる）`AdministoratorAccess` ポリシーと同等の設定を一つ用意して使い回すのが楽ではあります。が、強すぎるかもしれません。
- この運用を頑張るかは事情によるので、ここでのサンプルは事例の一つとして解説します。

本ＩＡＭロールを設定するにあたり、定義されるロール名とポリシー名についてですが `cloudformation-deployment-何々-role`（`cloudformation-deployment-何々-policy`） ないしは `CloudFromationDeployment何々Role`（`CloudFromationDeployment何々Policy`） みたいな形を提案します。
少なくとも `AWS` で始めるのは推奨しません。そちらはＡＷＳ用のプレフィックスになるかと思います。他にも `My` とか `Custom` とか `屋号` で始めるのもいいかもしれません。

※最初ｇｉｔ ｓｙｎｃというキーワードを入れて説明しましたが、ＧｉｔＳｙｎｃに関係ないＩＡＭロールなので修正しました。

※ＡＷＳの資料によると `Condition:` 行で制限する説明がありますが、実際に入れると不安定な挙動が見られたので、修正しました。

# スタックの作成とＧｉｔＳｙｎｃしてみる

## スタックの作成（ステップ１）
- [ＡＷＳ管理コンソール](https://console.aws.amazon.com/cloudformation/home#/stacks)より「スタックの作成」より「新しいリソースを使用（標準）」ボタンを押します
- 「テンプレートの準備」では「既存のテンプレートを選択」を選びます。
- 「テンプレートの指定」では「Git から同期」を選びます。
- 「次へ」ボタンを押します。

## スタックの詳細を指定（ステップ２）
- 「スタック名」にて何かしかスタック名を入れます。
- 「デプロイファイルをスタック」にて「次のパラメータを使用してファイルを作成し、リポジトリに配置します。」を選びます。
    - すでにデプロイファイルが用意済みでも挙動が変わらないので、なるべくならデプロイファイルは用意しない方がいいと思います。
- 「テンプレート定義リポジトリ」では
    - 初回は「Git リポジトリをリンクする」からの「リポジトリプロバイダー」の選択と「AWS CodeConnections」の設定を選びます。
    - すでに実施済みの場合は「リンクされている Git リポジトリを選択する」を選びます。 
    - この段階で `git://github.com/アカウント/` までは確定した状況になります。
- 「リポジトリ」ではＧｉｔＨｕｂリポジトリを選びます。`git://github.com/アカウント/リポジトリ/` の `リポジトリ` に相当します。
- 「ブランチ」では当該リポジトリのデプロイ対象となるブランチを選びます。
- 「デプロイファイルのパス」で`git://github.com/アカウント/リポジトリ/デプロイファイルのパス` の `デプロイファイルのパス`を入力します。
- 「ＩＡＭロール」では「既存のＩＡＭロール」を選択し、「ＩＡＭロール名」に先に設定したＩＡＭロールの名前を選択します。
    - 事前に設定されていれば、この時、選択肢は一つだけしか出ません。
    - 設定ミスがなければ、リストされるはずです。
    - この作業中にＩＡＭロールを設定する場合は、設定後、リロードアイコンを押せば選択肢に出てきます。
- 「デプロイファイルパラメーター」で　`git://github.com/アカウント/リポジトリ/テンプレートファイルのパス` の `テンプレートファイルのパス` を入力します。
- 「パラメータ」でテンプレートに適用するパラメータを設定します（設定しなくてもよい）。
- 「タグ」にて作成しようとしているスタックのタグを設定します（設定しなくてもよい）。
- 「次へ」ボタンを押します。

※デプロイファイル、テンプレートファイルについては後述します。

## スタックオプション設定（ステップ３）
- 「アクセス許可」では「ＩＡＭロール」に先に設定したＩＡＭロールの名前を選択します。
    - 事前に設定されていれば、この時、選択肢は一つ以上出てきます。
    - 設定ミスがなければ、リストされるはずです。
    - この作業中にＩＡＭロールを設定する場合は、設定後、リロードアイコンを押せば選択肢に出てきます。
- 「スタックの失敗オプション」→ここでは省略します。
- 「詳細オプション」→ここでは省略します。 
    - ただし「スタック作成オプション」では「削除保護」を「アクティブ化済み」を選択することで、スタックの削除から保護する設定が有効になります。
- 「次へ」ボタンを押します。

## 確認して作成（ステップ４）
- 設定した内容が表示されますので、確認の上「送信」ボタンを押します。
- 作成したスタックの「Git と同期」タブ画面に遷移するため、同期状態が確認できます。
- この時点では `DEPLOYMENT_FILE_RETRIVAL_FAILED` という状態で「プロビジョニングステータス」が「失敗」になっているのは正常です。
    - 裏でデプロイファイルのプルリクエストが行われるため、ＧｉｔＨｕｂリポジトリに遷移して、マージリクエストを実施します。
    - マージリクエストを受けて、デプロイファイルを読み、デプロイファイルに基づき、テンプレートファイルの読み取りとスタックのデプロイが行われます。
 - 問題無ければすぐにでも `CHANGESET_CREATE_IN_PROGRESS` からしばらくして `STACK_UPDATE_SUCCEEDED` に変化します。

以後のスタックの変更はデプロイファイルとテンプレートファイルの更新を行います。

# スタックの削除
作成したスタックは「削除」ボタンから削除できます。ただし、ＧｉｔＳｙｎｃの状態（リポジトリリンク）については注意が必要です。

全てのスタックが削除された後に、スタックを追加しようとしても、「リンクされている Git リポジトリを選択する」で、選択肢がでてきません。
一度リポジトリリンクの削除を実施する必要があります。これは管理コンソール上でのオペレーションができず、ＣＬＩを使用して実施する必要があります。

```console
$ aws codestar-connections list-repository-links
{
    "RepositoryLinks": [
        {
            "ConnectionArn": "arn:aws:codeconnections:リージョン名:アカウントＩＤ:connection/47d2d46c-6db9-11ef-a581-00505682ee09",
            "OwnerId": "接続名",
            "ProviderType": "GitHub",
            "RepositoryLinkArn": "arn:aws:codestar-connections:リージョン名:アカウントＩＤ:repository-link/50c6e119-6db9-11ef-a581-00505682ee09",
            "RepositoryLinkId": "50c6e119-6db9-11ef-a581-00505682ee09",
            "RepositoryName": "example-repository"
        }
    ]
}
$ aws codestar-connections delete-repository-link --repository-link-id リポジトリリンクＩＤ
※この例では 50c6e119-6db9-11ef-a581-00505682ee09
```

# リポジトリのファイル構成
どう構成するのが良いのか議論の余地がありますが、例えばリージョン毎にディレクトリを切って、テンプレートファイルを設置、
デプロイファイルはトップディレクトリに置く、というような運用がいいかな、と思っています。

```
 / -+- README.md
    +- ap-northeast-1 -+- example1.yaml
    |                  +- exmaple2.yaml
    :                  :
    +- us-east-1      -+- exampleA.yaml
    |                  +- exampleB.yaml
    :                  :
    +- deployment-ap-northeast-1-example1.yaml
    +- deployment-ap-northeast-1-example2.yaml
    :
    +- deployment-us-east-1-exampleA.yaml
    +- deployment-us-east-1-exampleB.yaml
    :
```

# よくある質問とその答え

## Ｑ．管理コンソールやＣＬＩで設定したスタックを後からＧｉｔＳｙｎｃできますか？ 未同期のスタックの同期は後から可能？
Ａ．できます。問題ありません。

## Ｑ．デプロイに必要な権限が足りません。どうやって修正（権限追加／変更／削除）すればいいですか？
Ａ．もちろん当該ＩＡＭロールを変更すればよいのですが、そもそもＩＡＭロールを変更したい（フォークしたいなど）場合は「Ｇｉｔと同期」タブの「編集」ボタンからは変更できないので、いったん「接続解除」してから再度「接続」ボタンを押すことで変更できます。

## Ｑ．デプロイに必要な権限を消してしまいました。どうやって復旧すれば良いですか？
Ａ．スタックを削除するか、同名のＩＡＭロールを手作業で作成して、それでロールバックを進めるなどするしか無いです。

## Ｑ．何故か同期してくれません、あるいは、何でかスタックのデプロイに失敗します。
Ａ．いったんスタックを消して、手作業でスタックを作成後、ＧｉｔＳｙｎｃ設定してください。上手くいく時と上手くいかない時があります。

## Ｑ．一々ポリシー書くの面倒だからマネージドポリシーをアタッチするだけで、済ませられないですか？
Ａ．マネージドポリシーだけで十分行けます。

## Ｑ．デプロイファイルを更新したらスタックを更新してくれますか？具体的にはパラメーターの変更が反映されることを期待したいのですが。
Ａ．行けます。

## Ｑ．デプロイファイル更新したらスタックを更新してくれるなら、リージョン間で `Fn::ImportValue` したいケースで、あの無理矢理な技を披露しなくても良いのでは？
Ａ．自分もそう思います。ＧｉｔＨｕｂアクションズを使用して、影響ありそうな変更をハンドリングして、関連するリソースのデプロイファイルも一緒に更新してしまうのが楽かも知れません。

# 参考文献
- [Git 同期で Git リポジトリに保存されているソースコードとスタックを同期する](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/git-sync.html)
    - [Git 同期の仕組み](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/git-sync-concepts-terms.html)
    - [Git 同期の前提条件](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/git-sync-prereq.html)
    - [Git 同期を使用してリポジトリソースコードからスタックを作成する](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/git-sync-walkthrough.html)
    - [Git 同期ステータスダッシュボード](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/git-sync-status.html)
- [GitHub からの AWS CloudFormation デプロイ自動化](https://aws.amazon.com/jp/blogs/news/automate-safe-aws-cloudformation-deployments-from-github-jp/) [同原文（英語）](https://aws.amazon.com/jp/blogs/devops/automate-safe-aws-cloudformation-deployments-from-github/)
- [CloudFormationのGit同期設定方法](https://agaroot-itp.com/blog/1768/)
- [GitHubへの接続を作成する (コンソール）](https://docs.aws.amazon.com/ja_jp/dtconsole/latest/userguide/connections-create-github.html#connections-create-github-console) [同原文（英語）](https://docs.aws.amazon.com/dtconsole/latest/userguide/connections-create-github.html#connections-create-github-console)
- [GitHubへの接続を作成する(CLI)](https://docs.aws.amazon.com/ja_jp/dtconsole/latest/userguide/connections-create-github.html#connections-create-github-cli) [同原文（英語）](https://docs.aws.amazon.com/dtconsole/latest/userguide/connections-create-github.html#connections-create-github-cli)
- [AWS CodeConnections (旧称 AWS CodeStar Connections) のご紹介](https://aws.amazon.com/jp/about-aws/whats-new/2024/03/aws-codeconnections-formerly-codestar-connections/)
- [ＡＷＳマネージドポリシー一覧](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/policy-list.html)
- [イラストで理解するAssumeRoleの疑問](https://zenn.dev/fdnsy/articles/e98c43d9c3f611)

# クラウドフォーメーションのためのテンプレート

ここではコピペして使える程度のクラウドフォーメーション用のテンプレートを例示します。このまま `cloudformation.yaml` みたいな形でスタックを作ってしまえば、あとの作業はここで設定してＩＡＭロールを参照するだけで使えるようになります。
個々の細かい運用ルール、命名規則やスタックの作り方については、色々と主張したいところがあると思いますが、とりあえず自分は、こんな感じでやってます。

## 「ＩＡＭロール」で指定されるロールの定義
```yaml: ロール名 cloudformation-git-sync-role
AWSTemplateFormatVersion: '2010-09-09'

Resources:
  CloudFormationGitSyncIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 'cloudformation-git-sync-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Sid: CfnGitSyncTrustPolicy
          Effect: Allow
          Principal:
            Service: cloudformation.sync.codeconnections.amazonaws.com
          Action: sts:AssumeRole
      Policies:
      - PolicyName: 'cloudformation-git-sync-policy'
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Sid: SyncToCloudFormation
            Effect: Allow
            Action:
            - cloudformation:CreateChangeSet
            - cloudformation:DeleteChangeSet
            - cloudformation:DescribeChangeSet
            - cloudformation:DescribeStackEvents
            - cloudformation:DescribeStacks
            - cloudformation:ExecuteChangeSet
            - cloudformation:GetTemplate
            - cloudformation:ListChangeSets
            - cloudformation:ListStacks
            - cloudformation:ValidateTemplate
            Resource: '*'
          - Sid: PolicyForManagedRules
            Effect: Allow
            Action:
            - events:PutRule
            - events:PutTargets
            Resource: '*'
            Condition:
              StringEquals:
                events:ManagedBy:
                - cloudformation.sync.codeconnections.amazonaws.com
          - Sid: PolicyForDescribingRule
            Effect: Allow
            Action: events:DescribeRule
            Resource: '*'
```
「ＩＡＭロール」で「新しいＩＡＭロール」にチェックを入れた場合の差分は `Sid: SyncToCloudFormation` における `Resource: '*'` の設定が以下のように変化します。このことから使い回しが効かないことが分かります。
```yaml
            Resource: [
                "arn:aws:cloudformation:リージョン:アカウントＩＤ:stack/スタック名",
                "arn:aws:cloudformation:リージョン:アカウントＩＤ:stack/スタック名/"
            ]
```

## 「アクセス許可」で指定されるロールの定義
```yaml: ロール名 cloudformation-deployment-admin-priv-role
AWSTemplateFormatVersion: '2010-09-09'

Resources:
  CloudFormationDeploymentAdminPrivIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 'cloudformation-deployment-admin-priv-role'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service: cloudformation.amazonaws.com
          Action: sts:AssumeRole
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/AdministratorAccess
```
本例では `Action: '*'`、`Resource: '*'` により、ほぼあらゆる実行権限[^adminaccess]が与えられます（伏線回収）。
この例をベースにスタックの作成に必要な本当の権限をリストアップするのが理想となります。

よく使いそうなマネージドポリシーは何かなぁ。とりあえずぱっと見リストアップしてみました。

- [`arn:aws:iam::aws:policy/IAMFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/IAMFullAccess.html)
- [`arn:aws:iam::aws:policy/AmazonS3FullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonS3FullAccess)
- [`arn:aws:iam::aws:policy/AmazonEC2FullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEC2FullAccess)
- [`arn:aws:iam::aws:policy/AmazonRDSFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonRDSFullAccess)
- [`arn:aws:iam::aws:policy/AmazonECS_FullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonECS_FullAccess)
- [`arn:aws:iam::aws:policy/CloudFrontFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/CloudFrontFullAccess)
- [`arn:aws:iam::aws:policy/AWSLambda_FullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambda_FullAccess.html)
- [`arn:aws:iam::aws:policy/AmazonRoute53FullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonRoute53FullAccess)
- [`arn:aws:iam::aws:policy/AmazonElastiCacheFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonElastiCacheFullAccess)
- [`arn:aws:iam::aws:policy/AmazonEventBridgeFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEventBridgeFullAccess)
- [`arn:aws:iam::aws:policy/AWSCertificateManagerFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSCertificateManagerFullAccess.html)

[^adminaccess]: [AdministratorAccess マネージドポリシー](https://docs.aws.amazon.com/ja_jp/aws-managed-policy/latest/reference/AdministratorAccess.html)