Making Cloudformation Generic

Filed under AWS on February 13, 2020

I’ve spent the better part of the week pulling apart one of my own Cloudformation stacks trying to make it suitable to take with us between clients, and as such I’ve picked up some ideas on how to make it more portable between environments. I’ll probably read some more blogs on this stuff in the coming weeks, but here’s the small collection of tips I’ve come away with trying to get this stack into our new account.

Name things in obvious ways

Always use environment names (and client names, if applicable)

One easy way to make sure people have fewer excuses to delete things on me is to make sure EVERY resource has the client name and environment in their identifier, for example initrode-staging-bastion.

If people are looking at the console and manage to delete anything with production in its name with termination protection on, I can make a good guess that it was either deliberate or I have some serious education to spread around.

We split our environments into different accounts, but I still believe this is important to do. It’s one more check to make sure no one destroys anything important.

Always put the purpose in the name

Our system is going to need to handle multiple configurations. To deploy a new environment, it’s going to be incredibly difficult for us to know what to deploy (until my super secret environment deployment tool is ready) if we don’t have well named resources.

This is a pretty simple one to follow, initrode-production-contact-database or the like would suffice.

Prepend Lambdas With Their Source Events

This follows along with the suggestion above. Better visibility at a glance.

initrode-production-kinesis-event-insert

General Template Cleanliness

Use Parameters

Something I realised I did was peppering the client name all through my template instead of using !Ref ClientName to use the parameter value.

Mappings… Maybe

This is going to be a problem for me long term and I think I’m going to need a custom resource to control all this, but for handfuls of environments mappings are nice enough way to configure things like subnets and security groups which can be a pain to do as parameters in your deployment tool.

I like to lay mine out like this

Mappings:
    Foobar:
      initrode:
        production: foo
        staging: bar
      initech:
        production: baz
        training: fizz

which makes it easy to reference with Fn::FindInMap: [Foobar, !Ref ClientName, !Ref EnvironmentName]

Predictable Naming and Standard Variables

I have a defacto standard in my template of ClientName and EnvironmentName, meaning I know it’s going to be there when I need it.

Conclusion

I think this is mostly common sense if you’ve been a developer for a little while, but it can be a good thing to put your thoughts down to kind of quantify it.