Select Page

Modules in the Terraform ecosystem are a way to organize the code to:
  • be more reusable
  • avoid code duplication
  • improve the code organization and its readability

If we compare them to a programming language, writing a Terraform module is the equivalent of writing a function and calling it many times with different parameters.


By using modules, you will save time because you write the code once, test it and reuse it many times with different parameters. You can also use modules written by other people. In this git repo you can find some example community modules: https://github.com/terraform-community-modules When you want to change something you change it only in the module and all the infrastructure parts where the module is used will reflect the change when the next “terraform apply” will be run. On the other side you need to be very careful when you change something or when you use a module maintained by another person and you want to update to a new version.


Installing Terraform is pretty easy. You can find the download page of the latest version here: https://www.terraform.io/downloads.html. At the moment the 0.78 version is available. In order to install it in Linux these 4 commands are enough:

Test if it is ok, with the command version you should obtain something like this:

You can of course edit terraform code using Gedit or Vim or Notepad but the code will grow and having a syntax checker and color highlighter will surely simplify your life. My advice for a Terraform code editing tool is Atom. You can download it for free from the main website https://atom.io/ and you will also need to add the additional package for Terraform published on https://github.com/GiantToast/language-terraform After installing Atom, in order to add the package in Linux it is necessary only to run the command

For the purpose of this tutorial you can also use Vim or another editor because it is a proof of concept and fairly simple example.

A module is an independent piece of code and you can get it from many sources. There is a full list of possible sources on the official page https://www.terraform.io/docs/modules/sources.html, and you can get one of them and save your code from four kinds of repositories:

  1. Local File System
  2. AWS S3
  3. HTTP URLs
  4. Standard code repos mercurial/git, and there are also direct connections to BitBucket/GitHub

Let’s create our first module to see this useful Terraform feature in action. We will use as AWS as the provider. In the main Terraform code we will create a security group, call a module, and use the security group as a parameter. In the next paragraph we will see a more complex module but for our first steps in the Terraform module world this example module is complex enough. We will do this twice using two kinds of repositories: “Local File System” and “Standard git repos”.

For the module using the “Local File System” as the repo, we create a directory and place the code inside:

The main-module.tf code is:

The variables.tf code is (find a subnet id in your default vpc for the chosen region):

Run a Terraform validate to check for possible mistakes

For our Terraform project let’s create a directory and create the file resources.tf. Please remember that all the .tf files present in the directory (but not in the subdirectory) will be considered by the command line utility:

Insert in the resource.tf this code:

Note that your shared_credentials_file may be in a different directory. Check ~/.aws/credentials on Linux, OS X, or Unix. Check C:UsersUSERNAME.awscredentials on Windows. We’ll take a look at creating this file in a moment if you don’t have one already. Choose a region (I chose Mumbai) and use the default VPC ID for that region. Insert in the variables.tf this code:

Run a Terraform validate to check for mistakes. You also need to configure the Amazon credentials file and make sure you have the rights to creating resources in the Aws account:

If you don’t have access key credentials, here’s how you can create them. If you check the directory at this point with an ls -a command you will notice that there aren’t hidden directories and if you run the Terraform apply you will get an error like this:

This happens the first time you use the module in this Terraform project because you haven’t imported the module yet. This is what happens when you run the Terraform get command for the first time:

A new directory “.terraform/modules” is created and inside of it there will be a symlink to the module: this happens because we are using a module in the same file system. If you are running in a mounted file system where you don’t have the rights to create symlinks you will get an error like this:

Now you can run the module and you will obtain something like:

As you can see a new file was stored in the directory called terraform.tfstate. This file contains information regarding the state of the infrastructure you just created. If you do not change the files and the infrastructure in AWS and you run the Terraform apply command again you will see that nothing changes but a new file called terraform.tfstate.backup will appear.

This happens because, just like CloudFormation, Terraform tries to modify the infrastructure for it to be equal to the one described by the .tf files and if it already matches it will not perform any change. The last two copies of the tfstate file will be kept in the future runs as well. If you check in your AWS console you can find two resources: the Security Group and the Elastic Load Balancer. Now that we have a working module let’s clarify some points:

  • You can pass parameters from the command line to the main Terraform code. In a similar way you can also pass values from the main Terraform code to the module
  • If you specify a default value in the variables file you can omit to pass a value when you name the module or the function, or you can choose to overwrite that default value

Let’s test the same module using a git repos. For this purpose, I have used AWS CodeCommit but for Terraform there is no difference between CodeCommit and a standard git repo. Commit the two module files (main-module.tf and variables.tf) in your personal git repo. Setup a passwordless connection from your machine and your git repo. More info on using git  https://linuxacademy.com/cp/modules/view/id/88 Modify the resources.tf this way:

Replace both “source” values with your own repository source. I have declared the module twice and the only difference is the source line. Now run the Terraform update, this time with the –update option. It is convenient to use this option because if in the future the module will be updated you can download the latest version and replace the one you have saved:

If you look inside the .terraform/modules directory you will notice two subdirectories instead of one because the module was used twice and there is no symbolic link because the module source is not in the same file system.

Now by running the Terraform apply command three resources instead of two will be created:

Don’t forget to destroy all the resources at the end of the tutorial so the cost of this exercise will be close to zero dollars:

As you can understand, if you extend the example with these module features you can create a complex module and use it many times with different parameters. The code will become shorter and simpler to manage compared to repeating the same code many times.

In this example you can see more complex code which uses a Terraform module. Inside the module you have an AutoScaling Group, a Launch Configuration, an Elastic Load Balancer and a Route53 record definition and all these components assume different values every time you edit the module with different parameters. This is the code which names the module from the main Terraform code part:

Feel free to play with this more advanced example to get an understanding of how the different pieces work together, based on what we learned with our basic example.