AWS has announced the general availability of AWS CloudFormation Hooks which allow for custom logic prior to a create, update, or delete CloudFormation stack operation. CloudFormation hooks support versioning, public and private distribution, and can be published into multiple AWS accounts and regions.
CloudFormation Hooks provide proactive validation of CloudFormation operations by inspecting the resources that are to be provisioned. If a non-compliant resource is discovered, either a warning can be returned or the execution can be halted by failing the operation. Example use cases range from verifying that security groups will have the appropriate inbound and outbound traffic rules, restricting the usage of more expensive EC2 instances, or enforcing automatic backups be enabled for RDS instances.
The CloudFormation CLI is used to develop CloudFormation Hooks. CloudFormation Hooks are a supported extension type within the AWS CloudFormation registry. Developer plugins for hooks are available in Java and Python.
The AWS CloudFormation registry allows for management of extensions, including hooks, as both public and private resources. Public extensions are either published by AWS or by other third-parties. Extensions by AWS are always public and have their versioning controlled by AWS. Registered private extensions can be used for bespoke hooks and made available to the required AWS accounts by registering them. Publishing an extension into multiple regions can be done using AWS CloudFormation StackSets.
Generating the required hook project code can be done using the CloudFormation CLI by running the command cfn init
. The next step is generating the hook schema which is a JSON-formatted text file that defines the properties and attributes for the hook. The hook handler code is then written in one of the supported developer plugin languages. Registering the hook with the private registry can be done using cfn submit --set-default
.
Once complete, the hook can be enabled as follows:
aws cloudformation set-type-configuration \
--configuration "{\"CloudFormationConfiguration\":{\"HookConfiguration\":{\"TargetStacks\":\"ALL\",\"FailureMode\":\"FAIL\",\"Properties\":{\"SsmKey\": \"compliant-imageid-x86\"}}}}" \
--type-arn $HOOK_TYPE_ARN
When TargetStacks
is set to ALL
, the hook will apply to all stacks in the account during any CREATE
, UPDATE
, or DELETE
operation. FailureMode
can be set to either WARN
or FAIL
. The Properties
object is where hook runtime properties, as defined within the hook schema, are provided.
AWS has released a number of sample hooks in both Python and Java. For example, the AWSSamples::S3BucketEncrypt::Hook
sample will ensure that server-side encryption with KMS keys is enabled during the CREATE
or UPDATE
operations. If FAIL
is set for FailureMode
, then the following CloudFormation template would not be allowed to proceed as it does not specify encryption properties:
AWSTemplateFormatVersion: "2010-09-09"
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties: {}
CloudFormation hooks run against all CloudFormation stacks including stacks created by CDK, SAM, AWS Amplify, and AWS Elastic Beanstalk. CloudFormation hook invocation events can be subscribed to in Amazon EventBridge by creating an event-bridge rule.
More information can be found within the AWS documentation. There are quotas in place that limit the number of hooks per account to 100, hooks per resource to 100, and the number of versions of each hook to 100. CloudFormation Hooks incur a charge by hook based on the number and duration of requests.