Terraform Essentials: A Network Engineer's Guide to IaC
How Infrastructure as Code Simplifies Multi-Cloud and On-Prem Networking
Understand the purpose and history of Terraform
Terraform is an open-source Infrastructure as Code (IaC) tool developed by HashiCorp around 2014. It allows you to define, provision, and manage infrastructure using a declarative language called HCL (HashiCorp Configuration Language), which is designed to be readable by both humans and machines.
The Problem with Manual Provisioning
Before Terraform, engineers set up cloud resources like virtual machines, networks, firewalls, and databases using graphical interfaces (GUIs) or command-line tools (e.g., AWS CLI). This worked for small setups but became problematic as cloud use grew. Manual provisioning was:
Time-consuming: Each resource had to be created and configured individually through different interfaces, with each cloud provider implementing their own unique workflow.
Error-prone: Human mistakes often led to misconfigurations and downtime.
Difficult to scale: Replicating environments for testing, development, or disaster recovery was tedious and often resulted in inconsistencies.
Difficult to track: Without a record of changes, auditing and version control were nearly impossible.
These pain points highlighted the need for a more efficient, reliable approach to infrastructure management, setting the stage for tools like Terraform.
How Terraform Solves These Problems
In July 2014, HashiCorp launched Terraform to simplify provisioning resources across multiple cloud providers. Its goal? Let users define infrastructure in code using a declarative approach. Unlike imperative methods—where you list every step (e.g., "Create a VPC, then a subnet")—Terraform lets you describe the desired end state (e.g., "I want a VPC with a subnet"), and it figures out how to get there.
The most interesting part is that Terraform being cloud-agnostic which means the configuration you write (in HCL) can be used to provision same resources across any cloud provider or even with on-premises environments.
For example, companies like Airbnb use Terraform to manage their multi-cloud infrastructure, ensuring consistency and saving countless hours of manual work.
Infrastructure as Code: Explained Simply
Imagine you could build and manage your servers, networks, or cloud resources the same way you write a recipe. Instead of manually clicking buttons in a dashboard or typing commands one by one, you write down exactly what you need in a simple text file (like a to-do list for your infrastructure).
This "recipe" (code) tells Terraform:
What to create (e.g., "Set up 3 virtual servers in AWS").
How to configure them (e.g., "Install this security rule on all servers").
Where to deploy everything (e.g., "Put the database in Europe and the web servers in the U.S.").
Just like a recipe, you can reuse it anytime to recreate the same setup perfectly, share it with others, or tweak it to scale up (e.g., "Now I need 10 servers instead of 3").
This declarative model, combined with Terraform's ability to work with various providers (AWS, Azure, Google Cloud, VMware, etc.), made it an instant hit among engineers, who could now:
Automate provisioning: Write code to create, update, or delete resources.
Ensure consistency: Reuse configurations across development, staging, and production.
Track changes: Store code in version control (e.g., Git) for collaboration and auditing.
Reduce errors: Limit manual steps to minimize mistakes.
In short, IaC turns IT infrastructure into something you can design, version, and automate—just like software.
Manual vs. Terraform: A Side-by-Side Comparison
To fully appreciate Terraform’s value, let’s first explore how infrastructure is typically built manually in AWS and then see how Terraform simplifies the process. let’s create an EC2 instance as an example.
Manual Process via AWS Console
Log into the AWS web interface.
Navigate through multiple screens to manually create resources like VPCs, subnets, route tables, internet/NAT gateways, and EC2 instances.
Configure routes and security settings.
Test connectivity to ensure everything works.
This approach might work for a single instance but scaling it across multiple accounts or environments becomes slow and error prone.
Using Terraform (IaC Tool)
Instead of manual clicks, Terraform lets you define infrastructure in a text file using HCL. For example:
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
}
This configuration uses HashiCorp Configuration Language (HCL), which is designed to be readable by both humans and machines. You're declaring the end state you want and Terraform figures out how to make it happen.
When you run Terraform with this configuration, it communicates directly with AWS's APIs to create exactly what you've specified. No clicking, no navigation through multiple screens, just a single command to create everything.
Terraform's Core Mechanism: Providers and APIs
Beneath Terraform's simple interface lies a sophisticated architecture that enables it to communicate with a vast array of platforms and services. Understanding how this works gives you valuable insight into Terraform's capabilities and limitations.
Terraform operates using a provider-based architecture. Providers are plugins—pieces of code downloaded from the Terraform Registry—that act as translators between Terraform HCL file and your target platform (e.g., AWS, Azure, Cisco IOS XE). You define your infrastructure in Terraform’s language (HCL), and the provider converts those instructions into API calls that the target platform understands.
Providers
What they do: Each platform (AWS, Azure, Cisco IOS XE) has its own provider. These plugins map Terraform configurations to platform-specific APIs.
Example: The AWS provider translates aws_instance blocks into EC2 API calls.
APIs
What they do: Most modern platforms—whether cloud services or network devices—offer APIs (Application Programming Interfaces). An API is like a menu listing actions you can request, such as creating a server or updating a network. Terraform uses these APIs to execute your instructions, create, update, or delete resources.
Example: AWS uses RESTful APIs, while Cisco IOS XE uses RESTCONF/NETCONF.
How Terraform Works with Cloud Providers (e.g., AWS, Azure)
When working with cloud platforms like AWS or Azure, Terraform follows a specific approach:
Authentication
Terraform needs permission to interact with a cloud provider’s API. You provide credentials—like AWS access keys or an Azure service principal—which act as a key to unlock the provider’s services. These can be added to your Terraform configuration, set as environment variables, or stored in a credentials file.
API Requests
Once authenticated, Terraform uses the provider to send secure web requests (HTTPS) to the cloud’s APIs, targeting specific addresses called endpoints. For example:
AWS: To create a virtual server (an EC2 instance), Terraform contacts the
RunInstances
API.Azure: Setting up a virtual network calls the /subscriptions/.../virtualNetworks endpoint.
Response Handling
The API sends back details about the new resource—like a server’s ID or IP address. Terraform stores this in its state file (more on this later), so it can track and manage the resource moving forward, such as updating or deleting it.
How Terraform Works with On-Premises Devices (e.g., Cisco Routers)
Terraform isn't limited to cloud environments. It can also manage on-premises infrastructure like Cisco routers (doing configuration management)
Authentication
Similar to cloud providers, Terraform needs access to the device. This often involves SSH credentials (username/password or key-based authentication) or HTTP-based authentication, depending on the device's API setup.
API Requests
Modern network devices support management APIs like RESTCONF or NETCONF, standard methods for controlling them programmatically. Terraform uses the Cisco IOS XE provider to send requests to these APIs. For instance:
Configuring a router interface sends a PUT request to
/restconf/data/Cisco-IOS-XE-native:native/interface/GigabitEthernet.
The payload includes details like IP addresses from your HCL configuration.
Configuration Push
The provider converts your HCL configuration into commands or API calls the router understands. This lets you manage on-premises devices with the same Terraform approach as cloud resources, sparing you from learning device-specific syntax.
Summary
Terraform’s provider-based architecture simplifies managing both cloud and on-premises infrastructure. Providers act as bridges, handling communication with each platform’s APIs so you can define everything in a consistent, efficient way.
Terraform's Components & Terminologies
Learning Terraform might seem daunting, but it’s designed to be beginner friendly. To use it effectively—whether provisioning cloud resources or configuring network devices—you need to grasp a few core concepts first. Let’s break them down one by one:
1. Resources: The Foundation of Terraform
What they are:
Resources are the fundamental building blocks in Terraform—they represent the actual infrastructure components you're creating, managing, or configuring.
The smallest unit in Terraform hierarchy, representing specific infrastructure components like a router interface, virtual machine, or database.
For network engineers, resources could include:
Virtual routers in the cloud
Router interfaces, VLANs, firewall rules, or OSPF configurations
How they work:
Each resource has a type and name, along with configuration attributes, here's how a resource is defined using HCL syntax:
resource "cisco_ios_interface_loopback" "csr1_loopback" {
provider = cisco.CSR1
name = "Loopback100"
shutdown = false
ipv4_address = "10.10.10.1"
ipv4_address_mask = "255.255.255.255"
}
Translation: “Create a loopback interface named Loopback100 on the Cisco device CSR1 with IP 10.10.10.1.”
2. Providers: The Communication Layer
Providers form the crucial link between Terraform and the platforms where you're creating resources.
What they are:
Plugins that connect Terraform to platforms (AWS, Azure, Cisco IOS XE).
They translate HCL code into API calls or CLI commands the target platform understands.
For Network Engineers: Providers typically use protocols like NETCONF, RESTCONF, SSH, and vendor-specific APIs to communicate with network devices.
Here's how a provider is defined in HCL:
provider "cisco_ios" {
alias = "CSR1"
url = "https://192.168.122.111"
username = "cisco"
password = "cisco"
}
Tip: Always configure authentication securely (no hardcoded credentials!).
3. Configuration Files: Where It All Comes Together
Configuration files are the heart of Terraform—they contain all the instructions Terraform needs to build and manage your infrastructure.
Basic Properties:
Configuration files end with a .tf
They're written in HashiCorp Configuration Language (HCL)
Use multiple files to organize code (e.g., network.tf for VLANs, security.tf for firewalls).
Terraform treats all .tf files in the same directory as one large configuration file
Keep credentials out of configuration files—use variables or environment variables (more about variables below)
terraform-config/
├── main.tf # Primary resources & providers
├── vars.tf # Reusable variables
└── outputs.tf # Output values (e.g., IP addresses)
Common Practice: You might have main.tf for your primary configuration and variables.tf for reusable values like IP addresses, usernames, and passwords.
Let's look at a complete (though simple) configuration file that represents a scenario where we're configuring a loopback interface for a Cisco CSR1000v in Azure:
# Define providers
provider "azurerm" {
features {}
}
provider "iosxe" {
alias = "CSR1" # Unique identifier for this device
url = "https://192.168.1.1" # Device IP/API endpoint
username = "admin" # SSH/RESTCONF username
password = "cisco123" # SSH/RESTCONF password
}
# Azure Resource Group
resource "azurerm_resource_group" "cisco_network_rg" {
name = "cisco-rg"
location = "East US"
}
# Cisco IOS XE Loopback Interface
resource "iosxe_interface_loopback" "csr1_loopback" {
provider = iosxe.CSR1 # Reference the IOS XE provider alias
name = "Loopback100"
ipv4_address = "10.10.10.1"
ipv4_address_mask = "255.255.255.255"
}
This configuration does two main things:
Sets up the necessary providers (Azure and Cisco IOS XE) with proper authentication
Defines the resources we want to create (an Azure resource group and a loopback interface on our Cisco router)
Config Takeaways:
Providers are mandatory: Terraform uses them to authenticate and communicate with platforms.
Aliases: If managing multiple devices (e.g., CSR1, CSR2), aliases let you differentiate between them.
4. Variables: Making Configurations Flexible
Think of Terraform variables as placeholders in your HCL Configuration file that make it flexible and reusable. Instead of hardcoding values like server sizes, locations, or passwords directly in your configuration, you can use variables.
For example: rather than writing: "Create a server with 4 CPUs in the London data center"
You'd use variables: " Create a server with [cpu_count] CPUs in the [region] data center"
Purpose: Think of Terraform variables as placeholders in your configuration that make it flexible and reusable.
Benefits:
Change values without editing your main code
Use the same code for different environments (development, testing, production)
Keep sensitive information separate from your main configuration
For example, rather than hardcoding:
resource "aws_instance" "server" {
instance_type = "t2.micro"
region = "us-west-2"
}
You can use variables:
resource "aws_instance" "server" {
instance_type = var.instance_size
region = var.region
}
Then provide those values separately through default values, variable files, command-line inputs, or environment variables (more about this in upcoming LAB session)
5. Modules: Creating Reusable Components
The word "module" in programming usually refers to a reusable piece of code. In context of terraform modules are like reusable blueprints for your infrastructure. They let you bundle together a set of resources—like servers, databases, or networks—and use them in different projects. Instead of rewriting the same code every time, you create a module once and call it whenever you need that setup.
Benefits:
Think of them as templates you can call repeatedly.
Standardization: Ensure consistency across projects.
Reusability: Deploy 10 servers with the same code.
Simplified maintenance: Update the module, and changes propagate everywhere.
For example, a "web server" module could include everything needed for a server (compute, security rules, storage). You could then use this module multiple times without duplicating code.
module "web_server" {
source = "./modules/web_server"
cpu = 4
region = "East US"
}
In summary, all the files ending with
.tf
extension (including configuration and variable files) within a single Terraform directory can be considered a module, which you can then reuse in different projects.
Making Sense of It All
Understanding these components gives you a solid foundation for working with Terraform. The tool's logical structure—with resources being provisioned through providers, configured via HCL, and made flexible with variables and modules—creates a powerful yet approachable system for managing infrastructure as code.
As you work more with Terraform, you'll see how these components interact to create a consistent, repeatable process for building and managing your infrastructure.
Terraform Workflow: A Step-by-Step Guide
When using Terraform to provision or configure resources, there’s a specific sequence of command-line operations you must follow, known as the "workflow." This structured process ensures that changes to your infrastructure are deliberate, predictable, and safe. Below, we’ll explore why a workflow is necessary and walk through each step in detail, assuming you’ve created a Terraform configuration file (written in HashiCorp Configuration Language, or HCL) in a specific directory (often called a "module").
Why Do We Need a Workflow?
Manual infrastructure changes are risky and error prone. Terraform’s workflow addresses this by:
Providing Structure: A repeatable process for managing infrastructure as code.
Isolating Environments: Each directory/module is self-contained, preventing unintended cross-environment impacts.
Important: The workflow steps must be executed separately in each directory containing Terraform configuration files. For example, if you have one directory with a configuration file for Azure resources and another for AWS resources, you'll need to run the workflow commands in each directory independently.
Ensuring Safety: Syntax checks and previews of changes before execution.
The Terraform workflow allows you to verify your configuration syntax and logic before making any actual changes to your infrastructure. It checks whether you've installed all necessary provider plugins and dependencies, validates your syntax, and sometimes offers guidance if you've made errors.
Enabling Control: Deliberate, auditable changes instead of ad-hoc updates.
By following a defined sequence, Terraform ensures that infrastructure changes are intentional and predictable, reducing the risk of unintended consequences.
The Core Workflow Commands
If this is your first time running a Terraform configuration in a directory, you’ll need to execute the following commands in sequence. Let’s break them down:
step-1: Initialize: terraform init
$ terraform init
Initializing provider plugins...
- Downloading cisco/iosxe 1.2.0...
- Downloading hashicorp/azurerm 3.75.0...
Purpose: Initializes the working directory containing your configuration files.
What It Does:
Downloads necessary provider plugins (e.g., Azure, AWS, IOS XE).
Initializes backend configuration (where state files are stored).
Prepares the environment for subsequent Terraform operations.
Why It’s Important:
Providers act as translators, interpreting your HCL configuration to interact with specific infrastructure (e.g., Azure cloud or on-premises routers).
For example:
In one directory, you might use an Azure provider to provision cloud resources.
In another, you might use an IOS XE provider to configure OSPF on routers.
The command downloads these provider plugins and their dependencies into the respective directory.
When to Run It:
Run once per directory/module.
Re-run if you add/remove providers or change backend settings.
Step-2 Validate: terraform validate
(Optional but Recommended)
$ terraform validate
Success! The configuration is valid.
Purpose: Checks your Terraform configuration files for syntax errors.
What It Does:
Verifies that the configuration is syntactically valid and internally consistent.
Ensures all required arguments are present (e.g., a process ID for OSPF).
Why It’s Important:
HCL can be tricky—common mistakes include forgetting to close brackets or omitting mandatory fields.
This command catches errors early, saving you time before applying changes.
Step-3 Plan: terraform plan
terraform plan
Purpose: Creates an execution plan by comparing your current infrastructure state with the desired state in your configuration files.
What It Does:
Reads your configuration files (what you want).
Checks the Terraform state file (what currently exists).
Shows a preview of changes—resources to add, modify, or delete.
What Is a Terraform State File?
The state file (terraform.tfstate) is Terraform’s record of what it has previously provisioned or configured—essentially its "memory."
Example:
Day 1: You configure OSPF and a loopback interface on a Juniper router. After applying, the state file records these settings.
Day 2: You update the configuration to add BGP while keeping OSPF and the loopback.
Running terraform plan compares the updated configuration (OSPF + loopback + BGP) with the state file (OSPF + loopback) and shows that only BGP will be added.
Why It’s Important:
It acts as a preview, letting you review changes before they happen.
Terraform only plans to modify what’s necessary, making the process efficient.
Step-4 Apply: terraform apply
$ terraform apply
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions? [yes/no]
Purpose: Executes the actions outlined in the plan, applying changes to your infrastructure.
What It Does:
Creates, updates, or deletes resources as planned.
Updates the state file to reflect the new infrastructure state.
Why It’s Important:
This is the step where your configuration becomes reality.
It ensures your infrastructure matches your HCL files.
Step-5: Destroy: terraform destroy
(Use with Caution)
$ terraform destroy
Plan: 0 to add, 0 to change, 2 to destroy.
Purpose: Removes all resources managed by Terraform in the current directory.
What It Does:
Deletes everything Terraform has provisioned or configured.
Why It’s Important:
Useful for tearing down test environments or when resources are no longer needed (saving costs)
Double-check before running to avoid unintended data loss.
When to use it:
Cleaning up test environments.
Decommissioning outdated infrastructure.
The Complete Workflow in Action
Let's summarize the entire workflow:
Write your configuration in one or more
.tf
files using HCL syntaxInitialize your working directory with
terraform init
Validate your configuration with
terraform validate
(optional but recommended)Plan your changes with
terraform plan
to see what will be modifiedApply your changes with
terraform apply
to implement the modificationsDestroy your resources with
terraform destroy
if needed (use with caution)
By following this workflow consistently, you'll gain confidence in making infrastructure changes, reduce the risk of errors, and maintain a clear record of what's been deployed in your environment.
The power of Terraform's workflow lies in its predictability and safety—you always know what will happen before any changes are made to your critical infrastructure.
Final Thoughts
Learning a new technology like Terraform can initially feel like facing an overwhelming mountain of concepts, commands, and syntax. However, approaching it like a jigsaw puzzle can transform this experience into something manageable and even enjoyable.
Start by examining the complete picture on the puzzle box. In technology terms, this means understanding the core purpose and value of the tool before diving into specifics. With Terraform, the big picture is straightforward: it allows you to define infrastructure in simple text files and automatically creates that infrastructure for you in the cloud or on other platforms.
Once you grasp this fundamental concept, you can begin identifying the key pieces and where they fit. Just as you might sort puzzle pieces by color or edge pieces, categorize Terraform concepts into logical groups:
The configuration files are your puzzle pieces. The providers connect you to specific platforms like AWS or Azure. Resources are the actual infrastructure components you're creating. The workflow (init, plan, apply) is how you put these pieces together.
As you place each conceptual piece in its proper context, the complete picture gradually emerges. You'll start seeing how variables make your configurations flexible, how modules let you reuse common patterns, and how state files track what's been created.
The beauty of this approach is that you don't need to understand every detail at once. You can start with a simple configuration that creates just one resource, then gradually expand your knowledge to more complex scenarios. Each new concept builds upon what you already know.
What's next?
Now that we’ve covered the fundamentals of Terraform, it’s time to roll up our sleeves and dive into the trenches! The next phase involves setting up a hands-on lab environment to experiment with Terraform across multiple cloud platforms (like AWS, Azure, or GCP) and even configure physical network devices, such as routers.
In the next deep dive, we’ll explore:
Multi-cloud testing: Deploying resources across different providers.
Network automation: Applying Terraform to real-world router configurations.
Replicable setups: Step-by-step guides and lab files will be shared so you can mirror the experiments in your own environment.
Stay tuned—practical examples and “how-to” details are coming soon! 🛠️