Building And Testing a Basic Terraform Module

Terraform modules are a good way to abstract out repeated chunks of code, making them reusable across other Terraform projects and configurations. We'll create a basic Terraform module from scratch and then test it.

Prerequisite:

  1. Please ensure that you have the AWS CLI installed on your Linux VM.

  2. You can use the command sudo snap install aws-cli --classic

  3. Also, run aws configure to authenticate, you would have to generate your ‘Access key’ and ‘Secret access key’ from the AWS console.

    1. Open the terminal on your Linux VM, and type aws configure, put in the Access key and Secret access key, then press enter twice for the ‘region’ and ‘output format’.

Note: the Access key and Secret access key are very sensitive materials and, as such, are to be protected at all times, as they can be used to access your AWS account without permission. So once you are done with the project, kindly deactivate the access key from the console.

  1. Ensure you have installed Terraform on your Linux VM as well.

Create the Directory Structure for the Terraform Project:

  1. Check the Terraform status using the version command: terraform version

  2. Since the Terraform version is returned, you have validated that the Terraform binary is installed and functioning properly. Note: If you receive a notification that there is a newer version of Terraform available, you can ignore it

  3. Go into the root by typing: sudo su -

  4. Create a new directory called ‘terraform_project’ to house your Terraform code: mkdir terraform_project

  5. Switch to this main project directory: cd terraform_project

  6. Create a custom directory called modules and a directory inside it called vpc: mkdir -p modules/vpc

  7. Switch to the vpc directory using the absolute path: cd modules/vpc/

Write Your Terraform VPC Module Code:

  1. Using Vim, create a new file called main.tf: vim main.tf

  2. In the file, insert and review the provided code:

provider "aws" {

region = var.region

}

resource "aws_vpc" "this" {

cidr_block = "10.0.0.0/16"

}

resource "aws_subnet" "this" {

vpcid = awsvpc.this.id

cidr_block = "10.0.1.0/24"

}

data "aws_ssm_parameter" "this" {

name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"

}

  1. Press Escape and type :wq to save and exit the file.

  2. Create a new file called variables.tf: vim variables.tf

  3. In the file, insert and review the provided code:

    variable "region" {

    type = string

    default = "us-east-1"

    }

  4. Press Escape and type :wq to save and exit the file.

  5. Create a new file called outputs.tf: vim outputs.tf

  6. In the file, insert and review the provided code:

    output "subnet_id" {

    value = aws_subnet.this.id

    }

    output "ami_id" {

    value = data.aws_ssm_parameter.this.value

    }

Note: The code in outputs.tf is critical to exporting values to your main Terraform code, where you'll be referencing this module. Specifically, it returns the subnet and AMI IDs for your EC2 instance.

  1. Press Escape and type :wq to save and exit the file.

Write Your Main Terraform Project Code:

  1. Switch back to the main project directory: cd ~/terraform_project

  1. Create a new file called main.tf: vim main.tf

  1. In the file, insert and review the provided code:

    variable "main_region" {

    type = string

    default = "us-east-1"

    }

    provider "aws" {

    region = var.main_region

    }

    module "vpc" {

    source = "./modules/vpc"

    region = var.main_region

    }

    resource "aws_instance" "my-instance" {

    ami = module.vpc.ami_id

    subnet_id = module.vpc.subnet_id

    instance_type = "t2.micro"

    }

Note: The code in main.tf invokes the VPC module that you created earlier. Notice how you're referencing the code using the source option within the module block to let Terraform know where the module code resides.

  1. Press Escape and type :wq to save and exit the file.

  2. Create a new file called outputs.tf: vim outputs.tf

  1. In the file, insert and review the provided code:

    output "PrivateIP" {

    description = "Private IP of EC2 instance"

    value = aws_instance.my-instance.private_ip

    }

  1. Press Escape and type in:wq to save and exit the file.

Deploy Your Code and Test Out Your Module:

  1. Format the code in all of your files in preparation for deployment: terraform fmt -recursive

  2. Initialize the Terraform configuration to fetch any required providers and get the code being referenced in the module block: terraform init

  3. Validate the code to look for any errors in syntax, parameters, or attributes within Terraform resources that may prevent it from deploying correctly: terraform validate

  4. You should receive a notification that the configuration is valid.

  5. Review the actions that will be performed when you deploy the Terraform code: terraform plan

  6. In this case, it will create 3 resources, which include the EC2 instance configured in the root code and any resources configured in the module. If you scroll up and view the resources that will be created, any resource with module.vpc in the name will be created via the module code, such as module.vpc.aws_vpc.this.

  7. Deploy the code: terraform apply --auto-approve

    Note: The --auto-approve flag will prevent Terraform from prompting you to enter yes explicitly before it deploys the code.

  8. Once the code has executed successfully, note in the output that 3 resources have been created and the private IP address of the EC2 instance is returned as configured in the outputs.tf file in your main project code.

  9. View all of the resources that Terraform has created and is now tracking in the state file: terraform state list

  10. The list of resources should include your EC2 instance, which was configured and created by the main Terraform code, and 3 resources with the module.vpc in the name, which were configured and created via the module code.

  11. Tear down the infrastructure you just created before moving on: terraform destroy

  12. When prompted, type yes and press Enter.

    Conclusion:

    Congratulations — you've completed this hands-on lab!

0
Subscribe to my newsletter

Read articles from umeokoli vincent tochukwu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

umeokoli vincent tochukwu
umeokoli vincent tochukwu

Innovative and results-driven DevOps & Cloud Engineer with extensive experience in designing, implementing, and optimizing cloud-native infrastructure, CI/CD pipelines, and automation frameworks. Adept at leveraging cutting-edge technologies to enhance scalability, reliability, and security across distributed systems. Passionate about Infrastructure as Code (IaC), Kubernetes, AWS/GCP/Azure, and Site Reliability Engineering (SRE) principles to drive operational excellence. Core Competencies: ✅ Cloud Infrastructure: Expert in AWS, Azure, and GCP, designing highly available, fault-tolerant architectures using serverless, containers, and microservices. ✅ CI/CD & Automation: Strong background in Jenkins, GitLab CI/CD, GitHub Actions, ArgoCD, and Terraform for seamless deployments. ✅ Containerization & Orchestration: Proficient in Docker, Kubernetes (EKS/GKE/AKS), for scalable application deployments. ✅ Infrastructure as Code (IaC): Deep expertise in Terraform for automated provisioning. ✅ Scripting & Programming: Strong command of HTML, Python, Bash, Go, and PowerShell for automation and tooling. Technical Stack: Cloud: AWS (EC2, Lambda, S3, RDS, EKS), Azure (AKS, Functions), Oracle (OCI) DevOps Tools: Jenkins, GitHub Actions Containers: Docker, Kubernetes IaC: Terraform Professional Philosophy: "DevOps is not just about tools—it's a culture of collaboration, automation, and continuous improvement. I thrive in bridging the gap between development and operations, ensuring rapid, reliable, and secure software delivery."