Question

I've got a CloudFormation script that generates a SecurityGroup and an ELB; I'm trying to reference the SecurityGroup in the ELB creation; here's the resources bit:

    "ELBSecurityGroup" : {
        "Type" : "AWS::EC2::SecurityGroup",
        "Properties" : {
            "GroupDescription" : "Security group for the Arena dev stack",
            "SecurityGroupIngress" : [
                {"IpProtocol" : "tcp", "FromPort" : 80, "ToPort" : 80, "CidrIp" : { "Ref" : "OfficeIp" }}
            ]
        }
    },

    "ProjectLoadBalancerTest" : {
        "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
        "Properties" : {
            "AvailabilityZones" : { "Fn::GetAZs" : "" },
            "Instances" : [  ],
            "Listeners" : [ {
                "LoadBalancerPort" : "80",
                "InstancePort" : "12345",
                "Protocol" : "HTTP"
            } ],
            "HealthCheck" : {
                "Target" : {
                    "Fn::Join" : [ "", [ "HTTP:", "12345", "/status.json" ] ]
                },
                "HealthyThreshold" : "2",
                "UnhealthyThreshold" : "5",
                "Interval" : "60",
                "Timeout" : "30"
            },
            "SecurityGroups" : [
                { "Ref" : "ELBSecurityGroup" }
            ]
        }
    }

Unfortunately, this fails with:

Invalid id: "sebelbtest2-ELBSecurityGroup-1F5Z5DIIVQKD1" (expecting "sg-...")

So how can I reference ELBSecurityGroup for use as a property in the ELB creation?

Thanks!

Was it helpful?

Solution 2

As my CloudFormation script is all done within a VPC, I figured out what the problem was - I was creating the Security group, but not specifying the VpcId for it.

Security groups appear to be either normal security groups, or VPC security groups; if you do { "Ref": "MySecurityGroup" } on a normal one, you get the security group name, but not the ID. If you do { "Ref": "MySecurityGroup" } on a VPC one, you get back the sg-abcdef id, which is what is required for the ELB security group parameter.

So the full answer is:

"ELBSecurityGroup" : {
    "Type" : "AWS::EC2::SecurityGroup",
    "Properties" : {
        "GroupDescription" : "Security group for the ELB",
        "VpcId" : { "Ref" : "VpcId" },
        "SecurityGroupIngress" : [
            {"IpProtocol" : "tcp", "FromPort" : 80, "ToPort" : 80, "CidrIp" : { "Ref" : "OfficeIp" }}
        ]
    }
},
"MyELB": {
    "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
    "Properties" : {
        "AvailabilityZones" : { "Fn::GetAZs" : "" },
        "Listeners" : [ {
            "LoadBalancerPort" : "80",
            "InstancePort" : 8000,
            "Protocol" : "HTTP"
        } ],
        "SecurityGroups" : [ { "Ref" : "ELBSecurityGroup" } ]
    }
}

This all works perfectly (provided everything you're doing is within your VPC) and in my configuration, will successfully limit access to whatever OfficeIP is set to.

OTHER TIPS

As mytwocents mentioned, the solution is to use Fn::GetAtt. SecurityGroups are now supported by this function: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html

This works on the ELB:

...
"SecurityGroups" : [
    { "Fn::GetAtt" : [ "ELBSecurityGroup", "GroupId" ] }
]
...

Note. If you're putting this into a non-default VPC you'll also need to specify the VPC for the security group, and a subnet ID for the ELB.

Hmmm…

It appears as though the template is returning the Security Group's name instead of its ID.

Based on the documentation, it would appear that SecurityGroups can only be attached to a load balancer in a VPC.

If it were me, I would do one of two things (or both):

  • Post my question to the official AWS CloudFormation forum to try and get it answered from someone on that team.
  • Use the AWS Console, SDKs or CLI tools to set up your environment the way you want, then use the CloudFormer tool to generate a CloudFormation template that matches your environment.

I had the same issue - but decided that since this is just for initial set-up, the elastic load balancer can be managed seperate from cloud formation until they work this bug out. Also, cloud former is not totally reliable especially when you have security groups referencing other security groups.

I was hopeful that a GetAttr function call for the ID would work, but Security Groups are not in the supported list of GetAttr: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html

Try this for your SecurityGroup:

"ELBSecurityGroup" : {
    "Type" : "AWS::EC2::SecurityGroup",
    "Properties" : {
        "GroupDescription" : "Security group for the Arena dev stack",
        "SecurityGroupIngress" : [ {
            "IpProtocol" : "tcp",
            "FromPort" : 80,
            "ToPort" : 80,
            "SourceSecurityGroupOwnerId" : { "Fn::GetAtt" : [ "ProjectLoadBalancerTest", "SourceSecurityGroup.OwnerAlias" ] },
            "SourceSecurityGroupName" : { "Fn::GetAtt" : [ "ProjectLoadBalancerTest", "SourceSecurityGroup.GroupName" ] }
        } ]
    }
},

and remove "SecurityGroups" from your ELB definition. This will allow traffic from your ELB to your app servers.

It looks like you're also looking to limit ELB traffic to your office IP. That would be better done with something like apache directives.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top