Cloud Formation template add ingress rule to existing security group

Problem scope

I have an application built using multiple cloud formation templates. They need to interact with each other but are too large/complicated to build in one template.

Detail of scenario

Imagine there were only two template (there are significantly more)

  • Template A
  • Template B

Template A creates a security group (security group A) with itself as the only ingress rule. It is applied to a series of hosts in this template that perform the same function.

Template B creates another security group (Security group B) and a number of hosts (in an elastic beanstalk).

Question

How can I add an ingress rule to Security Group A for traffic from Security Group B using cloud formation?

What have I tried

I have looked through the documentation, I want to create a security group Ingress rule and associate it with security group A but that doesn't seem to be viable as far as I can see - http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group-rule.html

Other alternatives

I could just use the CIDR range of the hosts that are in Security Group B as that is known before any of this is built (all in VPC's with separate subnets) however I feel there must be a better more secure way than accepting traffic from a cidr range.


Solution 1:

Yes, it can be done.

You need to pass the security group identifier (for Security Group A) into the template for Template B as a parameter. From there, you can reference Security Group A in a AWS::EC2::SecurityGroupIngress resource.

{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Parameters" : {
        "SecurityGroupA" : {
            "Description" : "Security group to add Ingress rule to",
            "Type"        : "AWS::EC2::SecurityGroup::Id"
        }
    },
    "Resources" : {
        "LocalSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup"
        },
        "InboundRule": {
            "Type": "AWS::EC2::SecurityGroupIngress",
            "Properties":{
                "IpProtocol": "tcp",
                "FromPort": "80",
                "ToPort": "80",
                "SourceSecurityGroupId": {
                    "Fn::GetAtt": [ "LocalSecurityGroup", "GroupId" ]
                },
                "GroupId": {
                    "Fn::GetAtt": [ "SecurityGroupA", "GroupId" ]
                }
            }
        }
    }
}

Note that this example uses the security group ID, which is the case when your security groups are in a VPC. If they are in EC2-Classic, then you would use the GroupName instead.