はじめに
AWSでゼロからサイトを作る機会ができたので、表題の機能を使用してサイト構築をしてみた。
今ひとつ知見が足りないというか、説明読んでも、エッセンシャルな要素と、設定を同時に試みてるせいで、両者の区別が付かず、参考になる指標が分からなかったので、実際の手を動かしてみた結果から各フェーズで必要となる要素をまとめてみた。
あと妙に不安定な挙動を見つけたので理由が判明。AWSのドキュメントに誤りが…。
前提条件
- とりあえずクラウドフォーメーションやIAM等は知ってる前提として説明します(設定方法がわからない、は無しで)。
- GitHubとの連携を前提として他のサービス1との連携については見なかった物とします。
- GitHub側の権限問題や
AWS CodeConnections
2 についての詳細は省きます。 - とりあえずの初期設定はIAMユーザーによる操作3を行うものとして、その際
AdministoratorAccess
ポリシーが適用されているものとします。クラウドフォーメーションやIAMロール等の、必要な操作に絞った権限でどこまでできるかのチキンレースはしません。 - 準備自体(IAMユーザーやIAMロールの作成)をクラウドフォーメーションで実施することについては、むしろ推奨しますが、管理コンソール上の作業がメインになる点に留意してください。CLIで実施しても問題ありませんが、そのための解説はしません。
- とは言え作ったIAMロールを消してしまう(更新するつもりが)事故が無いことも無いので、手動で回復する余地は残しておいた方が良いです。
- またGitSyncそのものの設定はCLIでは実施できないようです4。
- 初期に作成したスタックを、後からGitSyncすることができます。焦って同時に設定しようと思わないことが設定のコツです。
- 管理コンソールからであれば、GitSync設定からのスタック作成(デプロイ)ができますが、若干不安定さを感じることがありました。上手くスタックが作れなかった場合、まずはスタック作成し、後からGitSyncすると良いです。
- 今のところCLI(=公開API)からGitSyncを設定する方法は無いと思われます4。重要なので二回言ってみた。
- つまりスタックを追加する度に管理コンソールでの操作が必要です。テンプレートファイルを入れたら、新しくスタックを作ってくれるほど便利ではありません。
- ここはクラウドフォーメーションのスタックを作るためのクラウドフォーメーション化が…。
要素
- Gitリポジトリの作成
- GitHubとの接続設定(
AWS CodeConnections
) - IAMロール(2種類)の作成
-
cloudformation.sync.codeconnections.amazonaws.com
プリンシパルのための許可権限 -
cloudformation.amazonaws.com
プリンシパルのための許可権限
-
- スタックの作成
- デプロイファイル
- テンプレートファイル
- GitSyncの設定
- スタックの削除
- GitSyncの設定解除と
AWS CodeConnections
に関する注意
- GitSyncの設定解除と
事前準備
- GitHub上でリポジトリを作成します。
- 運用上の要請から、おそらくはプライベートリポジトリを作成することになると思われ。
- 一つでもファイルが無いとブランチの存在を認識しれくれなかったので、
README.md
ファイルでも置いておきます(0バイトでも良い)。
-
AWS管理コンソール(CodePipeline→設定→接続)から「接続を作成」ボタンを押して、GitHubとの連携を実施しておきます。
- GitHub への接続を作成する (コンソール)の手順が参考になります。
- この時どのリージョンで設定すべきかはよく分かっていません。
-
ap-northeast-1
上で設定して、ap-northeast-1
、us-east-1
のどちらのクラウドフォーメーションでもAWS CodeConnections
の設定が参照され、スタックがデプロイできることを確認しています。 - このことからメインで使うリージョン(
ap-northeast-1
など)に「接続」設定を用意しておくのが無難と思われます。 - CLIで設定しても良いですが、最終的に管理コンソールにアクセスすることになります。
- 最低でも2つのプリンシパルに関する、2つ(以上)のIAMロールを作成することになります(後述)。
-
cloudformation.sync.codeconnections.amazonaws.com
プリンシパル(一つ)の許可権限設定 -
cloudformation.amazonaws.com
プリンシパル(一つ以上)の許可権限設定
-
- デプロイファイル
- 事前に作成しない方が良いです/しないことを推奨します。
- が、事前に作成しておいた場合、差分ゼロのプルリクエストが発生することがあります。
- リポジトリ更新(
git push
)後、数分以内の場合、不安定な挙動が見られます。 - スタックのテンプレートとしてのファイルのパスを指定します(MUST)。
- テンプレートファイルのパラメータを指定します(オプション)。
- テンプレート中にパラメータが必要な場合は、先にデプロイファイル側にも用意しておく必要があります。
- テンプレートファイル更新後、デプロイファイルにそれを反映すると、同期に失敗することがあります。その場合「Gitと同期」タブから「最新のコミットを再試行」ボタンを押す必要があります。
- スタックのタグを指定します(オプション)。
- テンプレートファイル
- スタック作成時に無くても良いですが、事前に作成しておく方が安全です。
- いわゆるシステム構成が記述されたYAMLまたはJSONのファイルです。
- 先にテンプレートファイルを作らずにGitSyncした場合の動作については見守ることが必要かも知れません。途中よく分からない理由で止まってることもあります。
GitHub からの AWS CloudFormation デプロイ自動化の説明が非常に参考になりますが、いかんせん、余計なことを行い過ぎて、何が必須か分からないのが不満です。
たとえば「CodeSpace の設定」や「Pull Request アクションの追加」なんての後回しで良いです。本質的に余計なお世話です。
また「IAMロール」と「アクセス許可」の二カ所でIAMロール名を指定することになっていますが、まるで説明されていません。この二つはわかりにくい割に、非常に重要なポイントなのですが、何故か説明がありません。
cloudformation.sync.codeconnections.amazonaws.com プリンシパルと許可権限設定
これはGitSyncの設定時に「IAMロール」の設定箇所で「新しいIAMロール」または「既存のIAMロール」で指定される時に参照される「プリンシパル」です。
- 実行主体(AWS内で定義されるサービス)が
cloudformation.sync.codeconnections.amazonaws.com
であることを意味します。 - よって信頼されたエンティティにて
"Principal": {"Service": "cloudformation.sync.codeconnections.amazonaws.com"}
として定義されたIAMロールだけが「既存のIAMロール」で指定の対象になります。 - このロールの実行にあたってはプリンシパルが
cloudformation.sync.codeconnections.amazonaws.com
のものであるものだけ、というアクションを受けるよう、制限を入れるようにします(Condition:
行)。 - 複数のIAMロール、あるいは毎回「新しいIAMロール」を指定しても良いですが、一つで必要十分を賄えます。
- 「新しいIAMロール」で作られたIAMロールを調べたところ、そのスタックに制約されたIAMロールが作成されるだけで、汎用的に使えませんでした。それなら先に一つ作って使い回す方がマシです。
このIAMロールの役割は以下の作業を実施するのに必要な権限となります。
- イメージとしては作業しているIAMユーザーの代わりに、当該プリンシパルがチェンジセットの作成や適用等を実施するというニュアンスになります。
- この時GitHubから
git clone
、git pull
します。 - その後、指定された「デプロイファイル」から「テンプレートファイル」のチェンジセットのバリデーション、作成や実行等を行います。
本IAMロールを設定するにあたり、定義されるロール名とポリシー名についてですが cloudformation-git-sync-role
(cloudformation-git-sync-policy
) ないしは CloudFromationGitSyncRole
(CloudFromationGitSyncPolicy
) みたいな形を提案します。
少なくとも AWS
で始めるのは推奨しません。そちらはAWS用のプレフィックスになるかと思います。他にも My
とか Custom
とか 屋号
で始めるのもいいかもしれません。
cloudformation.amazonaws.com プリンシパルと許可権限設定
これはGitSyncの設定時に「アクセス許可」の「IAMロール」の選択箇所で指定される時に参照される「プリンシパル」です。
イメージとしてはチェンジセットが適用される際に必要となる、リソース作成・変更・削除のため権限が、作業者のIAMユーザーから、このプリンシパル(サービス)に変わりますよ、というニュアンスになります。
よってそのリソースに関する各種権限が必要になります。マネージドポリシー適応しておければ十分だと思います。
- 実行主体(AWS内で定義されるサービス)が
cloudformation.amazonaws.com
であることを意味します。 - よって信頼されたエンティティにて
"Principal": {"Service": "cloudformation.amazonaws.com"}
として定義されたIAMロールだけが「IAMロール」での指定の対象になります。 - スタック一つ一つ毎に設定されることが期待されています。
- このIAMロールの目的は、
cloudformation.amazonaws.com
が実際にAWSリソースを作成するのに必要な最小限の権限を与えることが期待されているからです。 - 面倒なら(通常面倒に思われる)
AdministoratorAccess
ポリシーと同等の設定を一つ用意して使い回すのが楽ではあります。が、強すぎるかもしれません。 - この運用を頑張るかは事情によるので、ここでのサンプルは事例の一つとして解説します。
本IAMロールを設定するにあたり、定義されるロール名とポリシー名についてですが cloudformation-deployment-何々-role
(cloudformation-deployment-何々-policy
) ないしは CloudFromationDeployment何々Role
(CloudFromationDeployment何々Policy
) みたいな形を提案します。
少なくとも AWS
で始めるのは推奨しません。そちらはAWS用のプレフィックスになるかと思います。他にも My
とか Custom
とか 屋号
で始めるのもいいかもしれません。
※最初git syncというキーワードを入れて説明しましたが、GitSyncに関係ないIAMロールなので修正しました。
※AWSの資料によると Condition:
行で制限する説明がありますが、実際に入れると不安定な挙動が見られたので、修正しました。
スタックの作成とGitSyncしてみる
スタックの作成(ステップ1)
- AWS管理コンソールより「スタックの作成」より「新しいリソースを使用(標準)」ボタンを押します
- 「テンプレートの準備」では「既存のテンプレートを選択」を選びます。
- 「テンプレートの指定」では「Git から同期」を選びます。
- 「次へ」ボタンを押します。
スタックの詳細を指定(ステップ2)
- 「スタック名」にて何かしかスタック名を入れます。
- 「デプロイファイルをスタック」にて「次のパラメータを使用してファイルを作成し、リポジトリに配置します。」を選びます。
- すでにデプロイファイルが用意済みでも挙動が変わらないので、なるべくならデプロイファイルは用意しない方がいいと思います。
- 「テンプレート定義リポジトリ」では
- 初回は「Git リポジトリをリンクする」からの「リポジトリプロバイダー」の選択と「AWS CodeConnections」の設定を選びます。
- すでに実施済みの場合は「リンクされている Git リポジトリを選択する」を選びます。
- この段階で
git://github.com/アカウント/
までは確定した状況になります。
- 「リポジトリ」ではGitHubリポジトリを選びます。
git://github.com/アカウント/リポジトリ/
のリポジトリ
に相当します。 - 「ブランチ」では当該リポジトリのデプロイ対象となるブランチを選びます。
- 「デプロイファイルのパス」で
git://github.com/アカウント/リポジトリ/デプロイファイルのパス
のデプロイファイルのパス
を入力します。 - 「IAMロール」では「既存のIAMロール」を選択し、「IAMロール名」に先に設定したIAMロールの名前を選択します。
- 事前に設定されていれば、この時、選択肢は一つだけしか出ません。
- 設定ミスがなければ、リストされるはずです。
- この作業中にIAMロールを設定する場合は、設定後、リロードアイコンを押せば選択肢に出てきます。
- 「デプロイファイルパラメーター」で
git://github.com/アカウント/リポジトリ/テンプレートファイルのパス
のテンプレートファイルのパス
を入力します。 - 「パラメータ」でテンプレートに適用するパラメータを設定します(設定しなくてもよい)。
- 「タグ」にて作成しようとしているスタックのタグを設定します(設定しなくてもよい)。
- 「次へ」ボタンを押します。
※デプロイファイル、テンプレートファイルについては後述します。
スタックオプション設定(ステップ3)
- 「アクセス許可」では「IAMロール」に先に設定したIAMロールの名前を選択します。
- 事前に設定されていれば、この時、選択肢は一つ以上出てきます。
- 設定ミスがなければ、リストされるはずです。
- この作業中にIAMロールを設定する場合は、設定後、リロードアイコンを押せば選択肢に出てきます。
- 「スタックの失敗オプション」→ここでは省略します。
- 「詳細オプション」→ここでは省略します。
- ただし「スタック作成オプション」では「削除保護」を「アクティブ化済み」を選択することで、スタックの削除から保護する設定が有効になります。
- 「次へ」ボタンを押します。
確認して作成(ステップ4)
- 設定した内容が表示されますので、確認の上「送信」ボタンを押します。
- 作成したスタックの「Git と同期」タブ画面に遷移するため、同期状態が確認できます。
- この時点では
DEPLOYMENT_FILE_RETRIVAL_FAILED
という状態で「プロビジョニングステータス」が「失敗」になっているのは正常です。- 裏でデプロイファイルのプルリクエストが行われるため、GitHubリポジトリに遷移して、マージリクエストを実施します。
- マージリクエストを受けて、デプロイファイルを読み、デプロイファイルに基づき、テンプレートファイルの読み取りとスタックのデプロイが行われます。
- 問題無ければすぐにでも
CHANGESET_CREATE_IN_PROGRESS
からしばらくしてSTACK_UPDATE_SUCCEEDED
に変化します。
以後のスタックの変更はデプロイファイルとテンプレートファイルの更新を行います。
スタックの削除
作成したスタックは「削除」ボタンから削除できます。ただし、GitSyncの状態(リポジトリリンク)については注意が必要です。
全てのスタックが削除された後に、スタックを追加しようとしても、「リンクされている Git リポジトリを選択する」で、選択肢がでてきません。
一度リポジトリリンクの削除を実施する必要があります。これは管理コンソール上でのオペレーションができず、CLIを使用して実施する必要があります。
$ aws codestar-connections list-repository-links
{
"RepositoryLinks": [
{
"ConnectionArn": "arn:aws:codeconnections:リージョン名:アカウントID:connection/47d2d46c-6db9-11ef-a581-00505682ee09",
"OwnerId": "接続名",
"ProviderType": "GitHub",
"RepositoryLinkArn": "arn:aws:codestar-connections:リージョン名:アカウントID: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 リポジトリリンク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
:
よくある質問とその答え
Q.管理コンソールやCLIで設定したスタックを後からGitSyncできますか? 未同期のスタックの同期は後から可能?
A.できます。問題ありません。
Q.デプロイに必要な権限が足りません。どうやって修正(権限追加/変更/削除)すればいいですか?
A.もちろん当該IAMロールを変更すればよいのですが、そもそもIAMロールを変更したい(フォークしたいなど)場合は「Gitと同期」タブの「編集」ボタンからは変更できないので、いったん「接続解除」してから再度「接続」ボタンを押すことで変更できます。
Q.デプロイに必要な権限を消してしまいました。どうやって復旧すれば良いですか?
A.スタックを削除するか、同名のIAMロールを手作業で作成して、それでロールバックを進めるなどするしか無いです。
Q.何故か同期してくれません、あるいは、何でかスタックのデプロイに失敗します。
A.いったんスタックを消して、手作業でスタックを作成後、GitSync設定してください。上手くいく時と上手くいかない時があります。
Q.一々ポリシー書くの面倒だからマネージドポリシーをアタッチするだけで、済ませられないですか?
A.マネージドポリシーだけで十分行けます。
Q.デプロイファイルを更新したらスタックを更新してくれますか?具体的にはパラメーターの変更が反映されることを期待したいのですが。
A.行けます。
Q.デプロイファイル更新したらスタックを更新してくれるなら、リージョン間で Fn::ImportValue
したいケースで、あの無理矢理な技を披露しなくても良いのでは?
A.自分もそう思います。GitHubアクションズを使用して、影響ありそうな変更をハンドリングして、関連するリソースのデプロイファイルも一緒に更新してしまうのが楽かも知れません。
参考文献
- Git 同期で Git リポジトリに保存されているソースコードとスタックを同期する
- GitHub からの AWS CloudFormation デプロイ自動化 同原文(英語)
- CloudFormationのGit同期設定方法
- GitHubへの接続を作成する (コンソール) 同原文(英語)
- GitHubへの接続を作成する(CLI) 同原文(英語)
- AWS CodeConnections (旧称 AWS CodeStar Connections) のご紹介
- AWSマネージドポリシー一覧
- イラストで理解するAssumeRoleの疑問
クラウドフォーメーションのためのテンプレート
ここではコピペして使える程度のクラウドフォーメーション用のテンプレートを例示します。このまま cloudformation.yaml
みたいな形でスタックを作ってしまえば、あとの作業はここで設定してIAMロールを参照するだけで使えるようになります。
個々の細かい運用ルール、命名規則やスタックの作り方については、色々と主張したいところがあると思いますが、とりあえず自分は、こんな感じでやってます。
「IAMロール」で指定されるロールの定義
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: '*'
「IAMロール」で「新しいIAMロール」にチェックを入れた場合の差分は Sid: SyncToCloudFormation
における Resource: '*'
の設定が以下のように変化します。このことから使い回しが効かないことが分かります。
Resource: [
"arn:aws:cloudformation:リージョン:アカウントID:stack/スタック名",
"arn:aws:cloudformation:リージョン:アカウントID:stack/スタック名/"
]
「アクセス許可」で指定されるロールの定義
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: '*'
により、ほぼあらゆる実行権限5が与えられます(伏線回収)。
この例をベースにスタックの作成に必要な本当の権限をリストアップするのが理想となります。
よく使いそうなマネージドポリシーは何かなぁ。とりあえずぱっと見リストアップしてみました。
arn:aws:iam::aws:policy/IAMFullAccess
arn:aws:iam::aws:policy/AmazonS3FullAccess
arn:aws:iam::aws:policy/AmazonEC2FullAccess
arn:aws:iam::aws:policy/AmazonRDSFullAccess
arn:aws:iam::aws:policy/AmazonECS_FullAccess
arn:aws:iam::aws:policy/CloudFrontFullAccess
arn:aws:iam::aws:policy/AWSLambda_FullAccess
arn:aws:iam::aws:policy/AmazonRoute53FullAccess
arn:aws:iam::aws:policy/AmazonElastiCacheFullAccess
arn:aws:iam::aws:policy/AmazonEventBridgeFullAccess
arn:aws:iam::aws:policy/AWSCertificateManagerFullAccess