みなさんこんにちは。今年になって花粉症に悩まされています。技術1課の北鶴です。
今回は先月のアップデートで紹介されていた CloudFormation Hooksを試してみたので、ご紹介しようと思います。
AWS CloudFormation Hooksとは
AWS公式のでは以下のように紹介されています。
CloudFormation スタック操作を作成、更新、または削除する前に、カスタムロジックを呼び出してアクションを自動化したり、リソース設定を検査したりできるようにする機能です。100 万を超えるお客様が毎週 AWS CloudFormation を使用して、クラウドアプリケーションとインフラストラクチャを安全で予測可能かつ再現可能な方法で、モデル化、プロビジョニング、および管理しています。AWS CloudFormation Hooks を使用することで、お客様は、非準拠リソースについて、リソースプロパティを検証して警告を送信したり、プロビジョニング操作を防止したりして、セキュリティとコンプライアンスのリスクを軽減し、運用オーバーヘッドを削減し、コストを最適化できます。
一言でまとめるとCloudFormationでリソースを作成する際に、なんでも好きに作れてしまう状態を制限するのに有用な機能ということになるでしょうか。
リソースごとの構築権限はIAMによって制限できますが、IAMよりリソース内のより細やかな制限をかけることができます。
CloudFormation Hooksの設定
どういった機能なのか実際に使用してみたので、手順と合わせてご紹介します。
1.検索
Hookの機能として既に用意されているサンプルフックがいくつかあるので、今回はそちらを利用していきます。
CloudFormationのPublic Registry 画面から検索可能となっています。

2.有効化
サンプルフックの中からAWSSamples::S3BucketEncrypt::Hookを有効化してみます。
こちらはS3Bucketを作成する際に暗号化が有効化されているかをチェックしてくれる機能となります。

Hookのアクティブ化画面では、実行ロールのARNやログ記録の設定を行います。

実行ロールについては以下の信頼ポリシーが必要となるので、事前に作成しておきましょう。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"hooks.cloudformation.amazonaws.com",
"resources.cloudformation.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
ログの設定についてはオプションとなりますが、スタックのエラー時にどういった問題があるのかを確認するためには必要となります。
ログ用のIAMロールには上記の信頼ポリシーに加えて以下のポリシーが必要となります。
参考

- cloudwatch:ListMetrics
- cloudwatch:PutMetricData
- logs:CreateLogStream
- logs:DescribeLogGroups
- logs:DescribeLogStreams
- logs:CreateLogGroup
- logs:PutLogEvents
3.設定JSON
Hookをアカウント内にて有効化するには、設定JSONにてHookで使用するプロパティを指定する必要があります。
プロパティにて設定可能な値は以下となります。
注意点:現在の設定では、Hookの有効化設定はスタック全体に対して有効化するかどうかの設定のみとなります。
参考
- TargetStacks:Hookの機能をオンにするか・オフにするかを指定する。
- ALL:Hookをオンにする
- NONE:Hookをオフにする
- FailureMode:Hookの設定に対してスタックがエラーとなった際の動作を指定する。
- FAIL:中断する
- WARN:続行しつつ、警告を送信する
- Properties:各Hookごとに設定可能な項目

今回のHookでは以下のように設定しました。
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
"minBuckets":"1",
"encryptionAlgorithm": "AES256"
}
}
}
}
設定後アクティブ化済みの拡張機能にて「ターゲットスタック」が「すべてのスタック」となっていれば有効化の完了です。

動作確認
動作確認のためにCloudFormationにてS3バケットを作成してみます。
まずは、BucketEncryptionが設定されていないテンプレートを流してみます・
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'mybucket-${AWS::Region}-${AWS::AccountId}'

上記のように設定したHookによってエラーとなることが確認できました。
CloudFormationの画面からでは詳細は確認できないため、必要に応じて設定したCloudWatchLogsを確認します。
続いてBucketEncryptionが設定されたテンプレートを流してみます。
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub 'mybucket-${AWS::Region}-${AWS::AccountId}'
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'AES256'
BucketKeyEnabled: true

今度は正常にリソースを作成することができました。
このようにHookを設定することで、Hook内で指定されたPropertiesがない場合にスタックをはじくといった動作が可能となります。
まとめ
多くのユーザーがCloudFormationを利用してリソースを作成している環境では、Hookを利用することでセキュリティホールとなる可能性のあるリソースの作成を未然に防ぐことができるため便利だと感じました。
一方でHookの設定がスタック全体に適応されていまったり、各Hookに関する詳細な使い方についてはご自身でサンプルHookを確認する必要があるといった面は、多少使いにくさはあるかもしれません。
(私も設定後何度か想定外のエラーに悩まされました。)
そのためまずはHookの設定を「警告」にしつつ、慣れてきたら「中断」にするなど段階的にお試しいただくことをお勧めします。
北鶴 光紀(執筆記事の一覧)
Enterprise Cloud部 技術1課