Your Terraform Module Needs an Opinion

Your Terraform Module Needs an Opinion

I have been known to have strong opinions. When building terraform modules, you should draw some inspiration from me.

At this point in time, Terraform is the most popular Infrastructure as Code framework. Hashicorp lists providers for many different platforms including all the major cloud providers and many popular SaaS products. Many users and teams wrap these providers in modules to provide more targeted functionality.

Many of the public Terraform modules are a grouping of related resources. While this can be useful, some are nothing more than a few resources with all the configuration options exposed via variables. Often the variable names have been changed to confuse the innocent. Some of these wrapper modules are quite complex to understand as they try to be all this to all people. In some cases these modules are produced by companies that offer Terraform support and consulting services.

Often there is little value in these complex wrapper modules. You would be better off just using the resources directly. There will be less abstraction and so it’s likely to be easier to debug when things go wrong.

Terraform modules are still very useful, but they must add value. The value in a module, its opinions. If a module isn’t opinionated, then it isn’t adding value. Decide how things should be done and create a module to implement your preferred approach.

When building a module think about its responsibilities. Each time the description has “or” or “and”, that should be a sign that you probably need multiple modules with different implementations. When mapping out the variables for your module, unless it is a more complex module that aggregates functionality from other modules, it should only have around 5 to 10 variables. Any less it may not be doing enough, any more and it probably too flexible.

For example a S3 bucket module is too generic, you will end up exposing most of the config as variables. Create one bucket module for backups, another one for logs and if you need it a third for public resources. Each of these have quite distinct configurations.

In the case of the backup bucket module you will want to create a unique KMS key, setup replication, use lifecycle rules, deny all public access and so on. The logging bucket on the other hand will need to use SSE-S3 and have a different set of lifecycle rules. You really don’t want to have a module variable or two be the only thing that stops all your backups or logs from being open to the world. The name of the public bucket module needs to make it clear that it will provision a public bucket, so there is never any confusion.

Don’t build Swiss Army knife modules. Valuable modules are the ones that enforce policies and provide reusable building blocks.