Share your cloud infra with Terraform modules

Cloud comes with many advantages and one really nice feature is infrastructure as code (IaC). IaC allows one to manage data center trough definition files instead of physically configuring and setting up resources. Very popular tool for the IaC is Terraform.

Terraform is a tool for IaC and it works with multiple clouds. With Terraform configuration files are run from developers machine or part of the CI/CD pipelines. Terraform allows one to create modules, parts of the infrastructure that can be reused. A module is a container for multiple resources that are used together. Even for simple set up, modules are nice, as one does not need to repeat oneself, but they are very handy with some of the more resource-heavy setups. For example, setting up even somewhat simple AWS virtual private cloud (VPC) network can be resource heavy and somewhat complex to do with IaC. As VPC are typically setup in a similar fashion, generic Terraform modules can ease these deployments greatly.

Share your work with your team and the world

Nice feature of these Terraform modules is that you can fairly easily share them. As you are using these modules, you can source them from multiple different locations such as local file system, version control repositories, GitHub, Bitbucket, AWS S3 or HTTP URL. If, and when, you have your configuration files in version control, you can simply point your module’s source to this location. This makes sharing the modules across teams handy.

Terraform also has Terraform Registry, which is an index of modules shared publicly. Here you can share your modules with the rest of the world and really help out fellow developers. Going back to the VPC configuration, you can find really good Terraform modules to help you get started with this. Sharing your own code is really easy and Terraform has very good documentation about it [1]. What you need is GitHub repo named according to Terraform definitions, having description, right module structure and tag. That’s all.

Of course, when sharing you should be careful not to share anything sensitive and specific. Good Terraform Registry modules are typically very generic and self-containing. When sourcing directly from the outside locations, it is good to keep in mind that at times they might not be available and your deployments might fail. To overcome this, taking snapshots of used modules might be a good idea.

Also, I find it a good practice to have a disable variable in the modules. This way user of the module can choose whether to deploy the module by setting a single variable. This kind of variable is good to take into consideration all the way from the beginning because in many cases it affects all the resources in the module. I’ll explain this with the example below.

Send alarms to Teams channel – example

You start to build an application and early on want to have some monitoring in place. You identify the first key metric and start thinking about how to notify yourself on these. I run into this problem all the time. I’m not keen on emails, as those seem to get lost and require you to define who to send them to. On the other hand, I really like chats. Teams and Slack give you channels where you can collaborate on the rising issues and it is easy to add people to the channels.

In AWS, I typically create CloudWatch alarms and route them to one SNS topic. By attaching a simple Lambda function on this SNS one can send the message to the Teams, for example. In Teams, you control the message format with Teams cards. I created a simple card that has some information about the alarm and a link to the metric. I found myself doing this over again, so I decided to build a Terraform module for it.

Here is a simple image of the setup. Terraform module sets up SNS that in turn triggers Lambda function. Lambda function sends all the messages it receives to Teams channel. Set up is really simple, but handy. All I need is to route my CloudWatch alarms to the SNS that is setup by the module and I will get notifications to my Teams channel.

Simple image of the module and how it plugs into CloudWatch events and Teams

Module requires you only to give the Teams channel webhook URL where the messages are sent to. When you create CloudWatch alarm metrics you just need to send them to the SNS topic that the module creates. SNS topic arn is in the module output.

You can now find the Terraform module from the Terraform Registry with a name “alarm-chat-notification” or by following the link in the footer [2]. I hope you find it useful to get you going with alarms.

Disable variable

As I mentioned before, it is a good practice to have disable variable in the module. To do this in Terraform, it is a bit tricky. First, create a variable to control this, in my repo it is called “create” and it is a type of boolean defaulting true. Now all the resource my module has had to have the following line:

count = var.create ? 1 : 0

In Terraform this simply means that if my variable is false, this count is 0 and no resource will be created. Not the most intuitive, but makes sense. This also means that all the resources will be a type of list. Therefore, if you refer to other resources, you have to do it with list operation, even when we know that there is only one. For example, my lambda function refers to the role, it does it by referring to the first element in the list as follows:

aws_iam_role.iam_for_lambda[0].arn

Again this makes sense and it is good to keep in mind.

I hope this blog inspires you to create reusable Terraform modules for the world to use. And please, feel free to source the alarm module.

[1] https://www.terraform.io/docs/registry/modules/publish.html
[2] https://registry.terraform.io/modules/aloukiala/alarm-chat-notification/aws/

Author of this blog post is a data engineer who has built many cloud-based data platforms for some of the largest Nordic companies.