AWS Lambda テンプレート
以下のテンプレートは、AWS Lambda (Lambda) 関数とカスタムのリソースを使用して、既存のセキュリティグループのリストに新しいセキュリティグループを追加します。この関数は、新規および既存のセキュリティグループが両方含まれるリストを作成できるように、セキュリティグループのリストを動的に構築する場合に便利です。たとえば、パラメーター値として既存のセキュリティグループのリストを渡し、新しい値をリストに追加して、すべての値を EC2 インスタンスに関連付けることができます。Lambda 関数のリソース タイプの詳細については、「AWS::Lambda::Function」を参照してください。
次の例に示した CloudFormation は、AllSecurityGroups カスタムリソースを作成するときに、まず AppendItemToListFunction Lambda 関数を呼び出しています。次にその関数に、既存のセキュリティグループと新しいセキュリティグループ (NewSecurityGroup) のリストを渡します。関数は、新しいセキュリティグループをリストに追加し、最新のリストを返します。CloudFormation は、最新のリストを使用して、すべてのセキュリティグループを MyEC2Instance リソースに関連付けます。
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", "t3.micro" ] } }, "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": "nodejs20.x" } }, "MyEC2Instance": { "Type": "AWS::EC2::Instance", "Properties": { "ImageId": "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}", "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 - t3.micro 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: !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: nodejs20.x MyEC2Instance: Type: AWS::EC2::Instance Properties: ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}' 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: !Join - ', ' - !GetAtt AllSecurityGroups.Value