Introduction

AWS CloudFormation hooks allows you to invoke custom logic to automate validation of resources. Customers have can select a pre-existing Hook from AWS’ Public Registry. It is also possible to create your own hook and publish them to your own Private Registry.

In this article, we will take a look at how to use one of the sample Hooks to prevent creation of an EC2 instance with an open ingress security group.

How to activate a CloudFormation Hook?

First, go to the CloudFormation console, and click on Public Extensions from the left menu.

CloudFormation Public Extensions

Next, choose the following filters: Hooks for Extension Type and Third Party for Publisher. We will be activating the following hook:

Security Group Extensions

Before, we can activate this hook, we need to create an Execution IAM role for this hook.

The Trust policy for the IAM role should be the following (replace your AWS region and Account number)


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "resources.cloudformation.amazonaws.com",
                    "hooks.cloudformation.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "account"
                },
                "StringLike": {
                    "aws:SourceArn": "arn:aws:cloudformation:us-west-2:account:type/hook/AWSSamples-SecurityGroupOpenIngress-Hook/*"
                }
            }
        }
    ]
}

Also, give this IAM role permission to describe the security groups so that it can verify the security group during the stack invocation.


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:DescribeSecurityGroup*",
            "Resource": "*"
        }
    ]
}

Now that you have created the IAM role, we will activate the CloudFormation Hook. In the activation screen enter the ARN for the Execution role that you just created and click on Activate Extension. You can leave the other settings as default.

Activate Extensions

We also need to configure the Hook before we can start using it. In the next screen, add the following as the Configuration JSON and click on Configure extension. Since the hook we are using doesn’t require any additional properties, our configuration is pretty straightforward. We want to apply this hook to ALL stacks and we want the stack to FAIL if there is a violation.

{
    "CloudFormationConfiguration": {
        "HookConfiguration": {
            "TargetStacks":"ALL",
            "FailureMode":"FAIL"
        }
    }
}

How to test the hook?

We have enabled our hook that should ensure we don’t have any EC2 instances with open security groups. Let’s test if the hook is working as expected.

Lets create a CloudFormation stack that is not compliant with our hook as follows:

AWSTemplateFormatVersion: "2010-09-09"
Resources:
  EC2InstanceNonCompliant:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SecurityGroups: [!Ref 'InstanceSecurityGroup']
      ImageId: ami-0341aeea105412b57
      Tags:
        - Key: Name
          Value: EC2InstanceNonCompliant
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "wide open group"
      SecurityGroupIngress:
      - IpProtocol: -1
        CidrIp: 0.0.0.0/0

We can use the AWS CLI to create the stack as follows:

aws cloudformation create-stack --stack-name sg-group-hook-non-compliant --template-body file://ec2-non-compliant.yaml

As expected, we see the CloudFormation stack that we just created failed because it was non-compliant with our hook.

Hook Fail

We will also create an EC2 instance that is valid to ensure that the hook won’t fail a stack that is compliant.


AWSTemplateFormatVersion: "2010-09-09"
Resources:
  EC2InstanceCompliant:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      SecurityGroups: [!Ref 'InstanceSecurityGroup']
      ImageId: ami-0341aeea105412b57
      Tags:
        - Key: Name
          Value: EC2InstanceCompliant
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "less wide open group"
      SecurityGroupIngress:
      - IpProtocol: -1
        CidrIp: 10.0.0.0/16

As expected, this stack succeeded and the EC2 instance was created.

Hook Success