はじめに
CodePipelineは便利。これをCloudFormationで自動構築して、フットワークの軽いデプロイを実現するぜ!
と言っても、商用リソースまで全自動でデプロイするようなクラウドネイティブに振り切ったシステムばかりではないよね。といった望みに、AWSはしっかり答えてくれている。
今回は、リリース直前に「ちょっと待った」をしてくれる承認ステージについての理解を深めてみる。
前提条件
- さすがにCodePipelineの概要くらいは抑えている
ハードル低め。最低限、以下の記事くらいのことができるのが望ましい。
Windowsのあたりは蛇足なので飛ばしても問題ない。
WindowsのEclipseからCodePipelineを起動してEC2にデプロイ&ECS on Fargateにアプリをデプロイする
ただし、↑の記事で扱っているECS on FargateのパイプラインはCloudFormationで書くと少し面倒なので、今回ベースにするのは、以下の記事のLambdaのパイプラインをベースに考えてみる。
Lambda関数をBlue/GreenデプロイメントするCodePipelineをCloudFormationで自動構築する
ということで、スタート時点では「CodeCommitにPushしたらCodeBuildでビルドしてSAMテンプレートをCloudFormationで実行するパイプライン」があることを前提とする。
承認ステージを作って承認してみる
まず、上のパイプラインに承認ステージを追加してみる。
-
出てきたダイアログに適当に名前をつける
-
適当に設定してみる
-
アクション名に適当な名前をつける
-
アクションプロバイダーは
Mannual approval
を選択 -
コメントを適当に入れる
-
パイプラインを走らせると、先ほど作ったApprovalのステージでちゃんとデプロイが「待った」された!
承認ステージで否認してみる
IAMで承認権限のあるIAMユーザのみ承認可能にする
IAMユーザの準備
以下を参考にしながら。
【AWS公式】CodePipeline の IAM ユーザーに承認権限を付与する
以下のIAMポリシーを持ったマネコンログイン可能なIAMユーザを作成する。
テストなので、管理ポリシーでもインラインポリシーでも何でもよい。
ポイントはcodepipeline:PutApprovalResult
の権限の有無。これがあると、パイプラインの承認ステージで承認が可能になる。
- IAMユーザ名:
can-approve
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"codepipeline:ListPipelines",
"codepipeline:GetPipeline",
"codepipeline:GetPipelineState",
"codepipeline:GetPipelineExecution",
"codepipeline:PutApprovalResult"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
- IAMユーザ名:
cannot-approve
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"codepipeline:ListPipelines",
"codepipeline:GetPipeline",
"codepipeline:GetPipelineState",
"codepipeline:GetPipelineExecution"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
なお、今回はおためしのためにResourceを*で指定しているが、当然ながら実運用をする際は最小権限を意識した方が良い。↑のAWS公式のドキュメントにも記載されているように、リソースを
"Resource": "arn:aws:codepipeline:us-east-2:80398EXAMPLE:MyFirstPipeline"
でパイプライン単位に絞ることができるし、パイプラインで複数の承認ステージがある場合(承認者が複数いてそれぞれで承認可能なステージを変えたい場合)は
"Resource": "arn:aws:codepipeline:us-east-2:80398EXAMPLE:MyFirstPipeline/MyApprovalStage/MyApprovalAction"
といった具合に、承認ステージ名や、その中の識別子で絞ることも可能なようだ。
権限のないユーザでの承認行為
上記のcannot-approveユーザで承認しようとすると、当然ながらエラーになる。
直前の「承認します」ボタンまでは押せて、そこで↓このエラーが出るので、設定が失敗したのではないかとちょっと心配になった……。
権限のあるユーザでの承認行為
can-approveユーザで承認すると、パイプラインは継続した。
「承認された でした」って何やねん……って感じだけど…。
承認者に対して通知を送る
CodePipelineは、承認ステージに到達するとAmazon SNSと連携する機能があるので、これで承認者に対して通知を行うことができる。
Amazon SNSの設定
まずはマネコンのAmazon SNSの設定画面に移動し、新規のSNSトピックを作る。
名前や表示名は適当に決めよう。これ以外は、今はひとまずデフォルトのままにしておく。
トピックを作ったら、サブスクリプションを設定する。これ以外もデフォルトのままにしておく。
サブスクリプションの設定ができたら、EメールのConfirmを行っておく(やっておかないとこの後の通知がされない)
CodePipeline実行IAMロールに対するIAMポリシの設定
CodePipeline実行に使うIAMロールに、Amazon SNSに対してPublishする権限がないとエラーになってしまう。しかも、権限がなくて実行失敗したときは却下されたかのように見えてエラー解析が大変になってしまうので、忘れず設定しておく。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "*"
}
]
}
CodePipelineの承認ステージの設定
承認ステージの「SNSトピックのARN」に、↑のSNSトピックを設定すると、承認依頼のメールが配信されるようになる。
承認依頼メール
メールは↓こんな感じで届く。
リンクを踏むと、パイプラインの詳細画面に遷移するので、そこで普通に承認/否認すれば良い。
IaCで書く
前の記事で作ったCloudFormationテンプレートに、以下を追加する。
こちらでは、できる限り最小権限を目指す。
また、CodePipelineのサービスロールと、承認ユーザのIAMユーザはあらかじめ作っておく前提とする(この辺のユーザは、パイプラインが増えても共通であることが多いので、ポリシを付け足していく考え方にする)。承認ユーザには、共通的に使うであろう以下の権限もあらかじめアタッチしておく。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"codepipeline:ListPipelines"
],
"Resource": [
"*"
],
"Effect": "Allow"
}
]
}
- パラメータ
SNSTopicNameSuffix:
Description: "SNS Topic Name for Approval stage on CodePipeline"
Type: "String"
Default: "-Pipeline-Approval-Request"
- SNSトピック/サブスクリプション
トピックにインラインでサブスクリプションを記述すると、削除時に消えなかったような気がするので、サブスクリプションも横着せずリソースとして作成するようにする。
SNSTOPIC:
Type: AWS::SNS::Topic
Properties:
TopicName: !Sub ${Prefix}${SNSTopicNameSuffix}
DisplayName: [トピックの表示名(メールのSubject)]
SNSSUBSCRIPTION:
Type: AWS::SNS::Subscription
Properties:
Protocol: email
Endpoint: [通知メールの宛先]
TopicArn: !Ref SNSTOPIC
- CodePipelineのサービスロールに付与するIAMポリシ
CODEPIPELINEIAMPOLYCY:
Type: AWS::IAM::Policy
Properties:
PolicyName: CodePipeline-SNS-Publish
Roles:
- CodePipelineRole
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: !Sub ${Prefix}AmazonSNSPublish
Effect: Allow
Action:
- "sns:Publish"
Resource: !Ref SNSTOPIC
- 承認権限を持ったIAMユーザに付与するIAMポリシ
APPROVALIAMPOLYCY:
Type: AWS::IAM::Policy
Properties:
PolicyName: CodePipeline-Approval
Users:
- can-approve
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: !Sub ${Prefix}CodePipelineAccess
Effect: Allow
Action:
- "codepipeline:GetPipeline"
- "codepipeline:GetPipelineState"
- "codepipeline:GetPipelineExecution"
Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Prefix}${PipelineNameSuffix}
- Sid: !Sub ${Prefix}CodePipelineApproval
Effect: Allow
Action:
- "codepipeline:PutApprovalResult"
Resource: !Sub arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${Prefix}${PipelineNameSuffix}/Approval/Approval
- パイプライン
好きなところに差し込む。後続のアクションのRunOrderをずらすのを忘れないように。
- Name: Approval
Actions:
- RunOrder: 3
Name: Approval
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
Configuration:
NotificationArn: !Ref SNSTOPIC
CustomData: [コメント]