Supply optional Security Groups to an EC2 instance in CloudFormation

When developing your Infrastructure as Code CloudFormation templates, you sometimes need to associate your resources with a list of Security Groups (SG) which may need to be configurable. For example, your resource may have a primary SG, and a list of optional SGs that can be specified at template deployment time.

I recently went through a somewhat painful exercise figuring out how to implement this, and that’s what I’m here to share with you.

As they say – “failure is mother of all learning”, or something on those lines (actually I just made it up), but anyway.

What I failed to achieve is make it work with optional SGs Parameter type List<AWS::EC2::SecurityGroup::Id>, that displays a nice drop-down of all your existing SGs when deploying through UI. Instead, I have to use CommaDelimitedList, which isn’t nearly as nice, but hey – at least it works.

The sticker was in the validation logic (see Gist below): when user doesn’t make any selection for Parameter with type List<AWS::EC2::SecurityGroup::Id>, CloudFormation declares this Parameter as “unknown”, so it can’t be used for things like Fn::Equals and such. That’s what I learned (and proudly twitted about with the #awswishlist tag, asking for a way to validate if such Parameter is empty) 🙂

So, enough talking, off to show the goods.

{
"AWSTemplateFormatVersion" : "2010-09-09",
"Parameters": {
"PrimarySG": {
"Description": "Primary Security Group for the instance",
"Type": "String",
"Default": "sg-863ab0e0",
"ConstraintDescription": "must be an EC2 security group id"
},
"AdditionalSGs": {
"Description": "Additional security groups for the instance",
"Type": "CommaDelimitedList",
"Default": "sg-e23ab084,sg-bb27addd",
"ConstraintDescription": "must be a list of EC2 security group ids"
}
},
"Conditions" : {
"MoreSGs": { "Fn::Not": [
{ "Fn::Equals": [ "",
{ "Fn::Join": [ "", { "Ref": "AdditionalSGs" } ] }
] }
] }
},
"Resources": {
"InstanceLaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"InstanceType": "t2.nano",
"KeyName": "SecretKey",
"ImageId": "ami-deadbeef",
"SecurityGroups": {
"Fn::If": [
"MoreSGs",
{ "Fn::Split": [ ",",
{ "Fn::Join": [ ",", [
{ "Ref": "PrimarySG" },
{ "Fn::Join": [ ",", { "Ref": "AdditionalSGs" } ] }
] ] }
] },
{ "Fn::Split": [ ",",
{ "Ref": "PrimarySG" }
] }
]
}
}
}
}
}

Notes:

  1. Yes, the logic spider nest in SecurityGroup attribute of InstanceLaunchConfig looks, um, unattractive; but it works.
  2. You may probably want to make sure the value you supply for AdditionalSGs doesn’t have any spaces in it.
  3. I declare PrimarySG as a Parameter here – it’s just for brevity so I don’t have to include an actual AWS::EC2::SecurityGroup Resource that in turn requires a VPC, and so on.
  4. What’s with all Splits and Joins? Well, SecurityGroups is a List, which means that we first must make a String from all our SGs, and then Split the result. Since AdditionalSGs is a CommaDelimitedList (and not a String), it needs to be run through Fn::Join (line 46), as well. Yeah, ugly.

I am making a buch of assumptions about what you, dear reader, already know – so shout out in comments if something is still muddy.

About Dmitri Kalintsev

Some dude with a blog and opinions ;) View all posts by Dmitri Kalintsev

2 responses to “Supply optional Security Groups to an EC2 instance in CloudFormation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: