AWS Lambda template - AWS CloudFormation

AWS Lambda template

The following template uses an AWS Lambda (Lambda) function and custom resource to append a new security group to a list of existing security groups. This function is useful when you want to build a list of security groups dynamically, so that your list includes both new and existing security groups. For example, you can pass a list of existing security groups as a parameter value, append the new value to the list, and then associate all your values with an EC2 instance. For more information about the Lambda function resource type, see AWS::Lambda::Function.

In the example, when AWS CloudFormation creates the AllSecurityGroups custom resource, AWS CloudFormation invokes the AppendItemToListFunction Lambda function. AWS CloudFormation passes the list of existing security groups and a new security group (NewSecurityGroup) to the function, which appends the new security group to the list and then returns the modified list. AWS CloudFormation uses the modified list to associate all security groups with the MyEC2Instance resource.

JSON

{ "AWSTemplateFormatVersion": "2010-09-09", "Parameters" : { "ExistingSecurityGroups" : { "Type" : "List<AWS::EC2::SecurityGroup::Id>" }, "ExistingVPC" : { "Type" : "AWS::EC2::VPC::Id", "Description" : "The VPC ID that includes the security groups in the ExistingSecurityGroups parameter." }, "InstanceType" : { "Type" : "String", "Default" : "t2.micro", "AllowedValues" : ["t2.micro", "m1.small"] } }, "Mappings": { "AWSInstanceType2Arch" : { "t2.micro" : { "Arch" : "HVM64" }, "m1.small" : { "Arch" : "HVM64" } }, "AWSRegionArch2AMI" : { "us-east-1" : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"}, "us-west-2" : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"}, "us-west-1" : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"}, "eu-west-1" : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"}, "eu-central-1" : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"}, "ap-northeast-1" : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"}, "ap-southeast-1" : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"}, "ap-southeast-2" : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"}, "sa-east-1" : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"}, "cn-north-1" : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"} } }, "Resources" : { "SecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Allow HTTP traffic to the host", "VpcId" : {"Ref" : "ExistingVPC"}, "SecurityGroupIngress" : [{ "IpProtocol" : "tcp", "FromPort" : 80, "ToPort" : 80, "CidrIp" : "0.0.0.0/0" }], "SecurityGroupEgress" : [{ "IpProtocol" : "tcp", "FromPort" : 80, "ToPort" : 80, "CidrIp" : "0.0.0.0/0" }] } }, "AllSecurityGroups": { "Type": "Custom::Split", "Properties": { "ServiceToken": { "Fn::GetAtt" : ["AppendItemToListFunction", "Arn"] }, "List": { "Ref" : "ExistingSecurityGroups" }, "AppendedItem": { "Ref" : "SecurityGroup" } } }, "AppendItemToListFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "index.handler", "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Code": { "ZipFile": { "Fn::Join": ["", [ "var response = require('cfn-response');", "exports.handler = function(event, context) {", " var responseData = {Value: event.ResourceProperties.List};", " responseData.Value.push(event.ResourceProperties.AppendedItem);", " response.send(event, context, response.SUCCESS, responseData);", "};" ]]} }, "Runtime": "nodejs14.x" } }, "MyEC2Instance" : { "Type" : "AWS::EC2::Instance", "Properties" : { "ImageId": { "Fn::FindInMap": [ "AWSRegionArch2AMI", { "Ref": "AWS::Region" }, { "Fn::FindInMap": [ "AWSInstanceType2Arch", { "Ref": "InstanceType" }, "Arch" ] } ] }, "SecurityGroupIds" : { "Fn::GetAtt": [ "AllSecurityGroups", "Value" ] }, "InstanceType" : { "Ref" : "InstanceType" } } }, "LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["lambda.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }] }, "Path": "/", "Policies": [{ "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["logs:*"], "Resource": "arn:aws:logs:*:*:*" }] } }] } } }, "Outputs" : { "AllSecurityGroups" : { "Description" : "Security Groups that are associated with the EC2 instance", "Value" : { "Fn::Join" : [ ", ", { "Fn::GetAtt": [ "AllSecurityGroups", "Value" ] }]} } } }

YAML

AWSTemplateFormatVersion: '2010-09-09' Parameters: ExistingSecurityGroups: Type: List<AWS::EC2::SecurityGroup::Id> ExistingVPC: Type: AWS::EC2::VPC::Id Description: The VPC ID that includes the security groups in the ExistingSecurityGroups parameter. InstanceType: Type: String Default: t2.micro AllowedValues: - t2.micro - m1.small Mappings: AWSInstanceType2Arch: t2.micro: Arch: HVM64 m1.small: Arch: HVM64 AWSRegionArch2AMI: us-east-1: HVM64: ami-0ff8a91507f77f867 HVMG2: ami-0a584ac55a7631c0c us-west-2: HVM64: ami-a0cfeed8 HVMG2: ami-0e09505bc235aa82d us-west-1: HVM64: ami-0bdb828fd58c52235 HVMG2: ami-066ee5fd4a9ef77f1 eu-west-1: HVM64: ami-047bb4163c506cd98 HVMG2: ami-0a7c483d527806435 eu-central-1: HVM64: ami-0233214e13e500f77 HVMG2: ami-06223d46a6d0661c7 ap-northeast-1: HVM64: ami-06cd52961ce9f0d85 HVMG2: ami-053cdd503598e4a9d ap-southeast-1: HVM64: ami-08569b978cc4dfa10 HVMG2: ami-0be9df32ae9f92309 ap-southeast-2: HVM64: ami-09b42976632b27e9b HVMG2: ami-0a9ce9fecc3d1daf8 sa-east-1: HVM64: ami-07b14488da8ea02a0 HVMG2: NOT_SUPPORTED cn-north-1: HVM64: ami-0a4eaf6c4454eda75 HVMG2: NOT_SUPPORTED Resources: SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTP traffic to the host VpcId: Ref: ExistingVPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 SecurityGroupEgress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 AllSecurityGroups: Type: Custom::Split Properties: ServiceToken: !GetAtt AppendItemToListFunction.Arn List: Ref: ExistingSecurityGroups AppendedItem: Ref: SecurityGroup AppendItemToListFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: !Sub | var response = require('cfn-response'); exports.handler = function(event, context) { var responseData = {Value: event.ResourceProperties.List}; responseData.Value.push(event.ResourceProperties.AppendedItem); response.send(event, context, response.SUCCESS, responseData); }; Runtime: nodejs14.x MyEC2Instance: Type: AWS::EC2::Instance Properties: ImageId: Fn::FindInMap: - AWSRegionArch2AMI - Ref: AWS::Region - Fn::FindInMap: - AWSInstanceType2Arch - Ref: InstanceType - Arch SecurityGroupIds: !GetAtt AllSecurityGroups.Value InstanceType: Ref: InstanceType LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:* Resource: arn:aws:logs:*:*:* Outputs: AllSecurityGroups: Description: Security Groups that are associated with the EC2 instance Value: Fn::Join: - ", " - Fn::GetAtt: - AllSecurityGroups - Value