+++
title = "Chapter 8: Infrastructure as Code: Terraform for Cloud and On-Prem VLANs"
topic = "devops"
date = 2026-01-24
draft = false
weight = 8
description = "Explore Infrastructure as Code (IaC) for VLAN management using Terraform across cloud environments (AWS, Azure) and on-premises networks. This chapter covers declarative configuration, state management, multi-vendor automation strategies, security best practices, and advanced troubleshooting for modern network infrastructures."
slug = "terraform-vlan-iac"
keywords = ["Terraform", "Infrastructure as Code", "IaC", "VLAN", "AWS VLAN", "Azure VLAN", "On-Prem VLAN", "Network Automation", "Cloud Networking", "Hybrid Cloud", "NetDevOps", "802.1Q", "802.1ad"]
tags = ["Networking", "VLAN", "IaC", "Terraform", "Cloud", "Automation", "NetDevOps"]
categories = ["Networking"]
+++
Introduction
In the rapidly evolving landscape of network engineering, manual configuration of Virtual Local Area Networks (VLANs) across diverse environments — from traditional on-premises data centers to dynamic cloud platforms — is becoming increasingly unsustainable. This chapter introduces Infrastructure as Code (IaC) principles, specifically focusing on Terraform, as the cornerstone for modern, automated VLAN management.
We will explore how Terraform enables declarative configuration of network segmentation, whether it’s provisioning Virtual Private Clouds (VPCs) and subnets in AWS or Azure, or orchestrating VLANs on multi-vendor on-premises switches. By treating network infrastructure as code, engineers can achieve unparalleled consistency, version control, auditability, and speed in deployments.
What this chapter covers:
- Core principles of Infrastructure as Code and its application to VLANs.
- Terraform’s architecture and its role in provisioning network resources.
- Configuring cloud-native network segmentation (VPC, VNet, subnets) using Terraform.
- Strategies for managing on-premises VLANs with Terraform, including integration with configuration management tools like Ansible.
- Security considerations, verification, troubleshooting, and performance optimization in an IaC context.
- Practical hands-on lab exercises to solidify your understanding.
Why it’s important:
Automating VLAN deployment and management with Terraform dramatically reduces human error, accelerates deployment cycles, and ensures configurations are always aligned with desired state, which is critical for compliance and operational efficiency in large-scale enterprise networks. This approach embodies NetDevOps principles, bringing software development best practices to network operations.
What you’ll be able to do after:
Upon completing this chapter, you will be able to design, implement, and manage VLANs and network segmentation across hybrid cloud environments using Terraform, troubleshoot common IaC and VLAN-related issues, and apply best practices for secure and performant network automation.
Technical Concepts
8.1. Infrastructure as Code (IaC) Principles
Infrastructure as Code is the management of infrastructure (networks, virtual machines, load balancers, etc.) in a descriptive model, using the same versioning and deployment practices as software code. Key principles include:
- Declarative vs. Imperative:
- Declarative (Terraform): You describe the desired end state of your infrastructure. Terraform figures out the steps to get there.
- Imperative (Traditional CLI, Ansible scripts): You define the sequence of commands to execute to achieve a state.
- Idempotency: Applying the same configuration multiple times yields the same result without unintended side effects. Terraform is inherently idempotent.
- Version Control: Infrastructure definitions are stored in Git, allowing for change tracking, collaboration, and easy rollback.
- Automation: Automates the provisioning, updating, and de-provisioning of infrastructure, reducing manual effort and errors.
- Immutability: Resources are often replaced rather than modified in-place, promoting consistency and easier rollbacks.
IaC Workflow with Terraform
digraph IaC_Workflow {
rankdir=LR;
node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial"];
edge [color="#555555", arrowsize=0.8];
User [label="Network Engineer"];
CodeEditor [label="Terraform HCL\n(VLAN Definitions)"];
GitRepository [label="Git Repository"];
CI_CD [label="CI/CD Pipeline\n(e.g., GitLab CI, GitHub Actions)"];
TerraformCLI [label="Terraform CLI"];
TerraformState [label="Terraform State File\n(Remote Backend)"];
CloudProvider [label="Cloud Provider APIs\n(AWS, Azure)"];
OnPremAPI_CLI [label="On-Prem APIs/\nNetwork Device CLIs"];
NetworkDevices [label="Network Devices\n(Switches, Routers)"];
User -> CodeEditor [label="Writes Code"];
CodeEditor -> GitRepository [label="Commits Code"];
GitRepository -> CI_CD [label="Triggers Pipeline"];
CI_CD -> TerraformCLI [label="Executes Terraform Commands"];
TerraformCLI -> TerraformState [label="Reads/Writes State"];
TerraformCLI -> CloudProvider [label="Manages Cloud Resources"];
TerraformCLI -> OnPremAPI_CLI [label="Manages On-Prem Resources\n(via Providers/Local-Exec)"];
CloudProvider -> NetworkDevices [label="Provisions Cloud Network\n(VPCs, Subnets)"];
OnPremAPI_CLI -> NetworkDevices [label="Configures On-Prem VLANs"];
}
8.2. Terraform Fundamentals for Network Engineering
Terraform, developed by HashiCorp, is an open-source IaC tool used to provision and manage cloud infrastructure. It uses a declarative configuration language called HashiCorp Configuration Language (HCL).
- Providers: Plugins that Terraform uses to interact with various cloud providers (AWS, Azure, GCP) and on-premises systems (vSphere, Kubernetes, network devices if specific providers exist, or via generic HTTP/Ansible integrations).
- Resources: The fundamental building blocks of infrastructure. Each resource block describes one or more infrastructure objects, like a VPC, a subnet, a virtual machine, or a VLAN.
- Data Sources: Allow Terraform to fetch information about existing infrastructure resources, which can then be used to configure other resources.
- Modules: Reusable, encapsulated sets of Terraform configurations that create multiple resources. They promote modularity and reduce code duplication.
- State File: Terraform stores the state of your managed infrastructure in a state file (
terraform.tfstate). This file maps the real-world resources to your configuration, tracks metadata, and improves performance for large infrastructures. The state file is highly sensitive and must be stored securely (e.g., S3, Azure Blob Storage) and encrypted.
8.3. VLANs in a Declarative IaC Context
Traditional VLANs (IEEE 802.1Q, IEEE 802.1ad for QinQ) provide Layer 2 segmentation. In an IaC context, the goal is to define these segments and their properties (ID, name, associated interfaces) declaratively.
IEEE 802.1Q and 802.1ad (QinQ) Overview
- IEEE 802.1Q (VLAN Tagging): The standard for VLAN trunking, adding a 4-byte tag to Ethernet frames to identify the VLAN. This allows multiple VLANs to share a single physical link (trunk).
- Tag Structure: Type (0x8100), Priority Code Point (PCP), Drop Eligible Indicator (DEI), VLAN ID (VID).
- IEEE 802.1ad (Provider Bridges / QinQ): An amendment to 802.1Q that allows for “stacked” VLAN tags, essentially encapsulating customer VLANs within a service provider’s VLAN. This is often called QinQ. The outer tag is a Service VLAN (S-VLAN), and the inner tag is a Customer VLAN (C-VLAN).
- Tag Structure: Uses EtherType 0x88a8 for the outer tag.
When using Terraform, you won’t typically define the bits of the 802.1Q tag, but rather the logical configuration parameters like VLAN ID, name, interface assignments (access or trunk), and native VLANs. The underlying network devices then implement the 802.1Q/ad standards based on your declarative input.
8.4. Cloud-Native Network Segmentation (VPC/VNet)
In cloud environments, the concept of a “VLAN” is often abstracted into constructs like Virtual Private Clouds (AWS VPC) or Virtual Networks (Azure VNet). These are logically isolated networks within the cloud provider’s infrastructure. Subnets within these VPCs/VNets further segment the network, analogous to how traditional VLANs segment a physical network.
Cloud Network Architecture (AWS/Azure)
@startuml
!theme mars
' Define all elements first
cloud "Internet" as INTERNET
rectangle "AWS Region (us-east-1)" as AWS_REGION {
component "AWS VPC (10.0.0.0/16)" as AWS_VPC {
rectangle "Public Subnet 1 (10.0.1.0/24)" as PUB_SUBNET_1
rectangle "Public Subnet 2 (10.0.2.0/24)" as PUB_SUBNET_2
rectangle "Private Subnet 1 (10.0.10.0/24)" as PRIV_SUBNET_1
rectangle "Private Subnet 2 (10.0.11.0/24)" as PRIV_SUBNET_2
node "Internet Gateway" as IGW
node "NAT Gateway" as NAT_GW
node "Route Tables" as RT
node "Security Groups" as SG
}
}
rectangle "Azure Region (East US 2)" as AZURE_REGION {
component "Azure VNet (172.16.0.0/16)" as AZURE_VNET {
rectangle "Frontend Subnet (172.16.1.0/24)" as FE_SUBNET
rectangle "Backend Subnet (172.16.10.0/24)" as BE_SUBNET
node "Public IP Gateway" as PIP_GW
node "Network Security Groups" as NSG
node "Route Tables (UDRs)" as UDR
}
}
' Then connect them
INTERNET [label="> IGW
IGW"] AWS_VPC
AWS_VPC [label="> PUB_SUBNET_1
AWS_VPC"] PUB_SUBNET_2
AWS_VPC [label="> PRIV_SUBNET_1
AWS_VPC"] PRIV_SUBNET_2
PUB_SUBNET_1 [label="> RT
PUB_SUBNET_2"] RT
PRIV_SUBNET_1 [label="> RT
PRIV_SUBNET_2"] RT
PRIV_SUBNET_1 [label="> NAT_GW
NAT_GW"] IGW
INTERNET [label="> PIP_GW
PIP_GW"] AZURE_VNET
AZURE_VNET [label="> FE_SUBNET
AZURE_VNET"] BE_SUBNET
FE_SUBNET [label="> NSG
BE_SUBNET"] NSG
FE_SUBNET [label="> UDR
BE_SUBNET"] UDR
@enduml
8.5. Hybrid Cloud Networking with IaC
IaC is critical for managing the complexity of hybrid cloud environments, where on-premises networks need to seamlessly integrate with cloud networks. This often involves:
- VPN/Direct Connect/ExpressRoute: Establishing secure, high-bandwidth connections between on-prem and cloud. Terraform can provision the cloud-side VPN gateways or direct connect interfaces.
- IP Address Management (IPAM): Ensuring non-overlapping IP spaces and efficient allocation across both environments.
- Routing: Configuring routes to ensure traffic flows correctly between on-prem VLANs and cloud subnets.
internet: Internet {
shape: cloud
}
cloud_aws: AWS Cloud {
shape: rectangle
aws_vpc: "AWS VPC (10.0.0.0/16)" {
shape: cylinder
public_subnet: "Public Subnet (10.0.1.0/24)"
private_subnet: "Private Subnet (10.0.10.0/24)"
}
aws_vpn_gw: "AWS VPN Gateway" { shape: hexagon }
}
on_prem: On-Premise Datacenter {
shape: rectangle
core_router: "Core Router"
core_switch: "Core Switch" {
vlan_10: "VLAN 10 (192.168.10.0/24)"
vlan_20: "VLAN 20 (192.168.20.0/24)"
}
on_prem_vpn_gw: "On-Prem VPN Gateway" { shape: hexagon }
}
internet -> aws_vpn_gw
internet -> on_prem_vpn_gw
aws_vpn_gw <-> on_prem_vpn_gw: VPN Tunnel
aws_vpc.public_subnet <-> aws_vpn_gw
aws_vpc.private_subnet <-> aws_vpn_gw
core_router <-> core_switch
core_router <-> on_prem_vpn_gw
core_switch -> vlan_10
core_switch -> vlan_20
# Terraform manages:
# - AWS VPC, Subnets, VPN Gateway
# - Could potentially configure on-prem VPN Gateway (if API supported)
# - Could trigger Ansible to configure on-prem VLANs
terraform: "Terraform/Ansible Control Plane" {
shape: flow_ellipse
}
terraform -> cloud_aws: "Provisions Cloud Network"
terraform -> on_prem: "Automates On-Prem Configuration"
Configuration Examples (Terraform)
This section demonstrates how to use Terraform to provision cloud network resources and manage on-premises VLANs.
8.6. Cloud VLANs (AWS VPC and Subnets)
This example provisions an AWS VPC with multiple subnets, effectively segmenting your cloud network in a “VLAN-like” manner.
# main.tf for AWS VPC and Subnets
# Configure the AWS provider
provider "aws" {
region = "us-east-1"
}
# Define a variable for the VPC CIDR block
variable "vpc_cidr_block" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
# Define a variable for subnet CIDR blocks
variable "public_subnet_cidrs" {
description = "List of CIDR blocks for public subnets"
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
variable "private_subnet_cidrs" {
description = "List of CIDR blocks for private subnets"
type = list(string)
default = ["10.0.10.0/24", "10.0.11.0/24"]
}
# Create a VPC
resource "aws_vpc" "main_vpc" {
cidr_block = var.vpc_cidr_block
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "ProductionVPC"
Environment = "Prod"
ManagedBy = "Terraform"
}
}
# Create Internet Gateway
resource "aws_internet_gateway" "main_igw" {
vpc_id = aws_vpc.main_vpc.id
tags = {
Name = "ProductionIGW"
}
}
# Create public subnets
resource "aws_subnet" "public_subnets" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main_vpc.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index] # Distribute across AZs
map_public_ip_on_launch = true # Instances in public subnets get public IPs
tags = {
Name = "PublicSubnet-${count.index + 1}"
Environment = "Prod"
Tier = "Public"
}
}
# Create private subnets
resource "aws_subnet" "private_subnets" {
count = length(var.private_subnet_cidrs)
vpc_id = aws_vpc.main_vpc.id
cidr_block = var.private_subnet_cidrs[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "PrivateSubnet-${count.index + 1}"
Environment = "Prod"
Tier = "Private"
}
}
# Data source to get available AZs
data "aws_availability_zones" "available" {
state = "available"
}
# Create Route Tables for public subnets
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main_igw.id
}
tags = {
Name = "PublicRouteTable"
}
}
# Associate public subnets with the public route table
resource "aws_route_table_association" "public_rt_associations" {
count = length(aws_subnet.public_subnets)
subnet_id = aws_subnet.public_subnets[count.index].id
route_table_id = aws_route_table.public_rt.id
}
# Output VPC and Subnet IDs
output "vpc_id" {
description = "The ID of the VPC"
value = aws_vpc.main_vpc.id
}
output "public_subnet_ids" {
description = "List of IDs of the public subnets"
value = aws_subnet.public_subnets[*].id
}
output "private_subnet_ids" {
description = "List of IDs of the private subnets"
value = aws_subnet.private_subnets[*].id
}
Verification Commands (AWS CLI):
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=ProductionVPC" --query "Vpcs[*].VpcId" --output text
aws ec2 describe-subnets --filters "Name=tag:Name,Values=PublicSubnet-*" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output table
aws ec2 describe-subnets --filters "Name=tag:Name,Values=PrivateSubnet-*" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output table
Expected Output (example):
vpc-0abcdef1234567890
----------------------------------------------------
| DescribeSubnets |
+--------------------------+-----------------+------+
| AZ | CIDR | ID |
+--------------------------+-----------------+------+
| us-east-1a | 10.0.1.0/24 | subnet-0fedcba9876543210 |
| us-east-1b | 10.0.2.0/24 | subnet-0123456789abcdef |
+--------------------------+-----------------+------+
----------------------------------------------------
| DescribeSubnets |
+--------------------------+-----------------+------+
| AZ | CIDR | ID |
+--------------------------+-----------------+------+
| us-east-1a | 10.0.10.0/24 | subnet-0987654321fedcba |
| us-east-1b | 10.0.11.0/24 | subnet-0fedcba123456789 |
+--------------------------+-----------------+------+
8.7. On-Prem VLANs with Terraform (via Ansible Integration)
Direct Terraform providers for specific network device CLIs are less common for generic VLAN management compared to cloud providers. A robust approach for on-premises is to use Terraform to orchestrate higher-level infrastructure (e.g., VMs for network controllers, physical server deployments) and then invoke a configuration management tool like Ansible to configure granular device settings like VLANs.
Here, Terraform uses a local-exec provisioner to trigger an Ansible playbook.
1. Terraform Configuration (main.tf):
# main.tf for On-Prem VLAN Orchestration
# Configure the local provider (for local-exec)
provider "local" {}
# Define variables for VLANs
variable "vlans_to_create" {
description = "A map of VLAN IDs to VLAN names to create on network devices."
type = map(string)
default = {
"10" = "Users_VLAN",
"20" = "Servers_VLAN",
"30" = "Voice_VLAN"
}
}
# Define network device inventory (could come from other Terraform resources or data sources)
variable "network_devices" {
description = "List of network device IPs to configure"
type = list(string)
default = ["192.168.1.10", "192.168.1.11"] # Example device IPs
}
# Null resource to trigger Ansible playbook
resource "null_resource" "configure_vlans_on_devices" {
# This makes Terraform re-run the provisioner if the vlans_to_create variable changes
triggers = {
vlans_config_hash = jsonencode(var.vlans_to_create)
devices_hash = jsonencode(var.network_devices)
}
provisioner "local-exec" {
command = <<-EOT
ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook \
-i "${path.module}/inventory.ini" \
"${path.module}/configure_vlans.yaml" \
--extra-vars '{"target_devices": ${jsonencode(var.network_devices)}, "vlans_data": ${jsonencode(var.vlans_to_create)}}'
EOT
# Working directory is the module root where inventory.ini and configure_vlans.yaml reside
working_dir = path.module
}
}
# Output confirmation
output "on_prem_vlan_status" {
description = "Status of on-prem VLAN configuration via Ansible"
value = "VLAN configuration playbook triggered for devices: ${join(", ", var.network_devices)}"
}
2. Ansible Inventory (inventory.ini):
This static inventory defines groups for different device types. You might dynamically generate this or fetch it from a source of truth.
# inventory.ini
[cisco_switches]
192.168.1.10
192.168.1.11
[all:vars]
ansible_user=admin
ansible_password=MySecurePassword!
ansible_network_os=ios
SECURITY WARNING: Storing plaintext passwords in inventory is highly discouraged for production. Use Ansible Vault or environment variables for sensitive data.
3. Ansible Playbook (configure_vlans.yaml):
This playbook will iterate through the vlans_data passed from Terraform and configure them on the target_devices.
# configure_vlans.yaml
---
- name: Configure VLANs on Network Devices
hosts: all
gather_facts: false
connection: network_cli
vars:
ansible_network_os: "cisco.ios.ios" # Or juniper.junos, arista.eos based on devices
ansible_connection: network_cli
ansible_become: true
ansible_become_method: enable # For privilege escalation
tasks:
- name: Ensure VLANs exist and have correct names
ansible.netcommon.cli_config:
config: |
vlan
name
match: strict
diff_against: running
loop: ""
loop_control:
label: "VLAN "
- name: Assign interfaces to VLANs (Example: Access Port)
ansible.netcommon.cli_config:
config: |
interface GigabitEthernet0/
switchport mode access
switchport access vlan
no shutdown
match: strict
diff_against: running
when: item.value.port is defined
loop: ""
loop_control:
label: "Interface Gig0/ for VLAN "
# NOTE: This is a simplified example. Real-world scenarios require dynamic port mapping.
# For example: vlans_to_create: {"10": {"name": "Users_VLAN", "ports": ["1", "2"]}, ...}
# You would then loop through ports for each VLAN.
- name: Configure trunk interfaces (Example: Between switches)
ansible.netcommon.cli_config:
config: |
interface GigabitEthernet0/24
switchport trunk encapsulation dot1q
switchport mode trunk
switchport trunk allowed vlan
no shutdown
match: strict
diff_against: running
when: inventory_hostname == '192.168.1.10' # Apply to specific device
# WARNING: This assumes a fixed trunk port for simplicity. In production, use more dynamic logic.
- name: Save configuration
ansible.netcommon.cli_config:
command: "write memory" # For Cisco IOS, adjust for other vendors
changed_when: false # This command doesn't change configuration itself, just saves
when: ansible_network_os == "cisco.ios.ios"
Verification Commands (Cisco IOS Example):
show vlan brief
show interfaces status
show interfaces trunk
Expected Output (Cisco IOS Example):
! (from show vlan brief)
VLAN Name Status Ports
---- -------------------------------- --------- -------------------------------
1 default active Gi0/1, Gi0/3-23
10 Users_VLAN active Gi0/0
20 Servers_VLAN active Gi0/4
30 Voice_VLAN active
! (from show interfaces trunk)
Port Mode Encapsulation Status Native VLAN
Gi0/24 on 802.1q trunking 1
Port Vlans allowed on trunk
Gi0/24 10,20,30
Network Diagrams
8.8. Terraform IaC for Hybrid VLAN Deployment
This diagram illustrates the comprehensive flow of using Terraform to manage network segmentation across both cloud and on-premises environments, incorporating configuration management for physical devices.
@startuml
!theme cerulean
' Define all elements first
actor "Network Engineer" as Engineer
component "Terraform CLI" as TF_CLI
cloud "Terraform Cloud/Remote State" as TF_STATE {
folder "State Files" as StateFiles
}
rectangle "Cloud Provider (AWS)" as AWS_CLOUD {
component "AWS Provider API" as AWS_API
rectangle "AWS VPC" as VPC {
rectangle "Public Subnet (VLAN-like)" as PublicSubnet
rectangle "Private Subnet (VLAN-like)" as PrivateSubnet
}
}
rectangle "On-Premises Data Center" as ON_PREM {
component "Ansible Control Host" as AnsibleHost
node "Core Switch 1 (Cisco)" as SW1
node "Access Switch 2 (Juniper)" as SW2
}
' Connections
Engineer --> TF_CLI : "Writes HCL"
TF_CLI <-> TF_STATE : "Manages State"
TF_CLI [label="> AWS_API : "Provision Cloud Resources"
AWS_API"] VPC : "Creates VPC/Subnets"
VPC [label="> PublicSubnet
VPC"] PrivateSubnet
TF_CLI --> AnsibleHost : "Triggers Ansible Playbook (via local-exec)"
AnsibleHost [label="> SW1 : "Configures VLANs (CLI over SSH)"
AnsibleHost"] SW2 : "Configures VLANs (CLI over SSH)"
SW1 <--> SW2 : "Trunk Links"
PrivateSubnet -[hidden]right-> AnsibleHost : "Logical segregation, but could connect via VPN"
@enduml
8.9. Cloud-Native VLAN Segmentation (AWS Example)
This nwdiag diagram visually represents a segmented AWS VPC with public and private subnets acting as logical VLANs.
nwdiag {
network "Internet Gateway" {
address = "0.0.0.0/0"
}
network "AWS VPC (10.0.0.0/16)" {
address = "10.0.0.0/16"
color = "#F0F8FF";
internet_gateway [address = "igw-xxxxxxxxxxxx"];
network "Public Subnet 1 (Web Tier)" {
address = "10.0.1.0/24"
color = "#E6F3F7";
web_server_01 [address = "10.0.1.10"];
web_server_02 [address = "10.0.1.11"];
load_balancer [address = "10.0.1.5"];
web_server_01 -- internet_gateway; # Direct access for public instances
}
network "Private Subnet 1 (App Tier)" {
address = "10.0.10.0/24"
color = "#FFF0F5";
app_server_01 [address = "10.0.10.10"];
app_server_02 [address = "10.0.10.11"];
}
network "Private Subnet 2 (DB Tier)" {
address = "10.0.20.0/24"
color = "#F5FFFA";
db_server_01 [address = "10.0.20.10"];
db_server_02 [address = "10.0.20.11"];
}
# Connections between logical segments within the VPC
load_balancer -- app_server_01;
app_server_01 -- db_server_01;
# NAT Gateway for outbound internet from private subnets (not explicitly drawn as a device here, but implied)
# Traffic from private subnets would route via NAT GW to Internet Gateway
}
}
8.10. On-Premises Multi-VLAN Topology
This nwdiag diagram shows a simplified on-premises network with multiple VLANs configured across switches, managed by an IaC approach.
nwdiag {
network "Management Network (VLAN 100)" {
address = "192.168.100.0/24"
color = "#F8F8FF";
ansible_control [address = "192.168.100.50", description = "Ansible/Terraform Control"];
}
network "Core Switch (Cisco)" {
address = "192.168.1.0/24" # Default management VLAN interface
color = "#E0FFFF";
core_sw [address = "192.168.100.10"];
core_sw -- ansible_control; # Management connection
network "User VLAN (VLAN 10)" {
address = "192.168.10.0/24"
color = "#F0FFFF";
core_sw; # Core switch participates in this VLAN
}
network "Server VLAN (VLAN 20)" {
address = "192.168.20.0/24"
color = "#F5FFFA";
core_sw; # Core switch participates in this VLAN
}
network "Voice VLAN (VLAN 30)" {
address = "192.168.30.0/24"
color = "#FFF0F5";
core_sw; # Core switch participates in this VLAN
}
}
network "Access Switch 1 (Juniper)" {
address = "192.168.1.0/24" # Default management VLAN interface
color = "#FFFAF0";
access_sw_1 [address = "192.168.100.20"];
access_sw_1 -- ansible_control; # Management connection
network "User VLAN (VLAN 10)" {
access_sw_1;
client_pc_1 [address = "192.168.10.100"];
}
network "Voice VLAN (VLAN 30)" {
access_sw_1;
ip_phone_1 [address = "192.168.30.10"];
}
}
network "Access Switch 2 (Arista)" {
address = "192.168.1.0/24" # Default management VLAN interface
color = "#F0FFF0";
access_sw_2 [address = "192.168.100.30"];
access_sw_2 -- ansible_control; # Management connection
network "User VLAN (VLAN 10)" {
access_sw_2;
client_pc_2 [address = "192.168.10.101"];
}
network "Server VLAN (VLAN 20)" {
access_sw_2;
server_a [address = "192.168.20.20"];
}
}
core_sw -- access_sw_1 [label = "Trunk (VLANs 10,20,30,100)"];
core_sw -- access_sw_2 [label = "Trunk (VLANs 10,20,30,100)"];
}
Automation Examples
While Terraform itself is an automation tool for provisioning, it often integrates with other automation tools for configuration management or dynamic data generation.
8.11. Python for Dynamic Terraform Inputs
Python can be used to generate complex Terraform variable files (e.g., tfvars files) or dynamic inventories for tools like Ansible, based on external data sources (CMDB, spreadsheets, APIs).
# generate_vlans_tfvars.py
import json
def generate_vlan_config(num_vlans=5, start_vlan_id=100, prefix="APP_VLAN"):
"""
Generates a dictionary suitable for Terraform's 'vlans_to_create' variable.
"""
vlans_data = {}
for i in range(num_vlans):
vlan_id = str(start_vlan_id + i)
vlan_name = f"{prefix}_{vlan_id}"
vlans_data[vlan_id] = vlan_name
return vlans_data
def write_tfvars_file(filename="terraform.tfvars", **kwargs):
"""
Writes the generated data to a terraform.tfvars.json file.
"""
with open(filename, 'w') as f:
json.dump(kwargs, f, indent=2)
print(f"Generated {filename} with dynamic VLAN data.")
if __name__ == "__main__":
# Example usage: Generate 3 VLANs starting from ID 50
dynamic_vlans = generate_vlan_config(num_vlans=3, start_vlan_id=50, prefix="MGMT_VLAN")
# You could also pull other variables from a database or API
network_devices = ["192.168.1.10", "192.168.1.11", "192.168.1.12"]
# Combine all variables into a dictionary for the tfvars file
tfvars_content = {
"vlans_to_create": dynamic_vlans,
"network_devices": network_devices,
"vpc_cidr_block": "172.31.0.0/16" # Example for AWS VPC
}
write_tfvars_file("dynamic.tfvars.json", **tfvars_content)
# To use this in Terraform, you would run:
# python generate_vlans_tfvars.py
# terraform plan -var-file=dynamic.tfvars.json
# terraform apply -var-file=dynamic.tfvars.json
Security Considerations
Implementing IaC for VLANs introduces new security considerations alongside traditional network security.
8.12. IaC Security Best Practices
- Secure Terraform State:
- CRITICAL: Never store the
terraform.tfstatefile locally in production. Use a remote backend (AWS S3, Azure Blob Storage, Terraform Cloud/Enterprise) configured with encryption and versioning. - Control access to the state file using IAM policies (AWS), RBAC (Azure), or team-based access in Terraform Cloud.
- CRITICAL: Never store the
- Sensitive Data Management:
- Avoid hardcoding API keys, passwords, or other sensitive information directly in HCL.
- Use environment variables, HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault to securely inject credentials into Terraform runs.
- Code Review and Version Control:
- Store all Terraform configurations in a Git repository.
- Implement pull request (PR) workflows requiring peer review before merging changes to production branches.
- Use static code analysis tools (e.g.,
tflint, Checkov) to scan for security vulnerabilities or misconfigurations in HCL.
- Principle of Least Privilege:
- Grant Terraform (or the CI/CD pipeline executing it) only the minimum necessary permissions to manage the required resources.
- Use specific IAM roles/service principals for different environments (dev, staging, prod).
- Drift Detection:
- Regularly run
terraform planin a read-only mode to detect any changes made to the infrastructure outside of Terraform (configuration drift). - Integrate drift detection into your CI/CD pipeline.
- Regularly run
8.13. VLAN Security in an IaC Context
IaC, by enforcing desired state, helps mitigate many common VLAN security vulnerabilities:
- VLAN Hopping (Switch Spoofing/Double Tagging):
- Mitigation: Declaratively configure all switch ports as
accessfor end devices and explicitly definetrunkports. Disable Dynamic Trunking Protocol (DTP) where not needed (e.g.,switchport mode access,switchport nonegotiate). Ensure the native VLAN on trunks is an unused VLAN ID. - IaC Benefit: These configurations can be standardized and applied consistently across all devices, preventing manual misconfigurations.
- Mitigation: Declaratively configure all switch ports as
- Private VLANs (PVLANs):
- Mitigation: Use PVLANs to isolate ports within the same VLAN at Layer 2, preventing direct communication between devices on “promiscuous” ports or within “isolated” communities.
- IaC Benefit: Some network device Terraform providers (or Ansible modules) support PVLAN configuration, ensuring complex PVLAN setups are consistently applied.
- Unused Ports:
- Mitigation: All unused switch ports should be shut down and assigned to an unused “blackhole” VLAN.
- IaC Benefit: Terraform/Ansible can enforce this policy across all ports not explicitly defined in the configuration.
- Default VLAN (VLAN 1):
- Mitigation: Do not use VLAN 1 for user or production traffic. Change the native VLAN on trunks from VLAN 1 to an unused VLAN.
- IaC Benefit: Enforced by default configurations in your HCL or Ansible playbooks.
- VLAN Access Control Lists (VACLs)/Network Security Groups (NSGs):
- Mitigation: Implement L3/L4 filtering between VLANs/subnets to control traffic flow.
- IaC Benefit: Terraform is excellent for managing cloud NSGs/Security Groups and can manage VACLs via network device providers.
Security Configuration Example (AWS Security Group with Terraform):
This example shows how Terraform enforces ingress/egress rules for a web server in a public subnet.
# Security Group for Web Servers
resource "aws_security_group" "web_sg" {
name = "web-server-sg"
description = "Allow HTTP/HTTPS inbound traffic"
vpc_id = aws_vpc.main_vpc.id # Reference the VPC created earlier
ingress {
description = "Allow HTTP from anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
ingress {
description = "Allow HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1" # All protocols
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "WebSG"
}
}
Verification & Troubleshooting
8.14. Terraform Verification Commands
Terraform provides a robust set of commands for verifying configurations and inspecting state.
terraform init: Initializes a working directory containing Terraform configuration files. Downloads providers and modules.terraform validate: Checks the configuration for syntax errors and internal consistency.terraform plan: Generates an execution plan, showing what actions Terraform will take (create, modify, destroy) without actually performing them. CRITICAL for reviewing changes.terraform apply: Executes the actions proposed in aplan(or a freshly generated one if no plan file is specified).terraform show: Reads the current state file and outputs the managed infrastructure resources.terraform state list: Lists all resources currently managed by the Terraform state.terraform state show <resource_address>: Shows the attributes of a specific resource in the state file.terraform refresh: Updates the state file by checking the real infrastructure’s current state. Useful for detecting drift.
Expected Output (terraform plan example):
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_vpc.main_vpc will be created
+ resource "aws_vpc" "main_vpc" {
+ arn = (known after apply)
+ assign_generated_ipv6_cidr_block = false
+ cidr_block = "10.0.0.0/16"
+ default_dhcp_options_id = (known after apply)
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ enable_classiclink = (known after apply)
+ enable_classiclink_dns_support = (known after apply)
+ enable_dns_hostnames = true
+ enable_dns_support = true
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Environment" = "Prod"
+ "ManagedBy" = "Terraform"
+ "Name" = "ProductionVPC"
}
+ tags_all = {
+ "Environment" = "Prod"
+ "ManagedBy" = "Terraform"
+ "Name" = "ProductionVPC"
}
}
# aws_subnet.public_subnets[0] will be created
+ resource "aws_subnet" "public_subnets" {
+ arn = (known after apply)
+ assign_ipv6_address_on_creation = false
+ availability_zone = "us-east-1a"
+ availability_zone_id = (known after apply)
+ cidr_block = "10.0.1.0/24"
+ id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ ipv6_cidr_block_association_id = (known after apply)
+ map_public_ip_on_launch = true
+ owner_id = (known after apply)
+ tags = {
+ "Environment" = "Prod"
+ "Name" = "PublicSubnet-1"
+ "Tier" = "Public"
}
+ tags_all = {
+ "Environment" = "Prod"
+ "Name" = "PublicSubnet-1"
+ "Tier" = "Public"
}
+ vpc_id = (known after apply)
}
# ... (truncated for brevity) ...
Plan: 6 to add, 0 to change, 0 to destroy.
8.15. Troubleshooting Terraform & VLANs
Common Terraform Issues:
| Issue | Description | Resolution Steps |
|---|---|---|
| Provider Not Found/Configured | Terraform cannot find or initialize the necessary provider plugin. | 1. Run terraform init. 2. Check provider block syntax. 3. Ensure AWS/Azure credentials are configured (environment variables, CLI config). |
| State File Lock/Corruption | Multiple users or processes trying to modify the state, or a corrupted state. | 1. Ensure remote state locking is configured (e.g., DynamoDB for AWS). 2. If locked, check for active terraform apply processes. 3. If corrupted, consider terraform state pull, manual editing (with extreme caution!), or rollback. |
| Configuration Drift | Infrastructure resources manually changed outside Terraform. | 1. Run terraform refresh to update state. 2. Run terraform plan to see differences. 3. terraform apply to converge to desired state or manually update HCL. |
| Resource Not Found (ID) | Referencing a resource ID that doesn’t exist or is incorrect. | 1. Verify resource exists in the cloud/on-prem. 2. Check data source filters. 3. Ensure correct id attribute is used from existing resources or outputs. |
| Syntax Errors (HCL) | Typos, missing brackets, incorrect variable usage. | 1. Run terraform validate. 2. Carefully review Terraform logs for line numbers and error messages. 3. Use an IDE with HCL syntax highlighting and linting. |
Common VLAN Configuration Issues (and IaC’s Role):
| Issue | Description | IaC Impact/Resolution |
|---|---|---|
| VLAN ID Mismatch | Different VLAN IDs or names on interconnected switches for the same logical segment. | IaC (Terraform+Ansible) ensures consistent VLAN ID and name definitions across all targeted devices, eliminating manual typos. Verification: show vlan brief (Cisco), show vlans (Juniper). |
| Trunking Issues | Incorrect encapsulation (dot1q), allowed VLANs, or native VLAN mismatch on trunk ports. | IaC enforces standardized trunk port configurations (mode, encapsulation, allowed VLANs, native VLAN). terraform plan reviews these. Verification: show interfaces trunk. |
| Access Port Assignment Error | End-device ports assigned to the wrong VLAN or in trunk mode. | IaC explicitly sets switchport mode access and switchport access vlan <ID> for end-device ports, reducing misconfiguration. Verification: show interfaces status, show interfaces switchport. |
| Routing Between VLANs | Layer 3 connectivity missing or incorrect for inter-VLAN routing (SVI/IRB). | While IaC can configure SVIs/IRBs, troubleshooting often involves checking IP addresses, routing protocols, and ACLs. Terraform provisions cloud routing policies and virtual routers for cloud subnets. |
| VLAN Pruning Issues | VLANs unnecessarily propagating over trunks. | IaC can enforce VLAN pruning (e.g., switchport trunk allowed vlan remove <ID>) or configure cloud network segmentation to minimize unnecessary traffic propagation. Verification: show interfaces trunk. |
Root Cause Analysis:
When troubleshooting, combine Terraform’s desired state (terraform show) with actual device state (show commands). Any discrepancy indicates drift or a failed IaC application. For on-premises issues, check Ansible logs (ansible-playbook -v) for connection errors or failed commands.
Performance Optimization
While Terraform primarily focuses on provisioning and configuration consistency, it contributes to network performance indirectly by enabling optimal design and reducing misconfigurations.
8.16. Terraform for Efficient Network Design
- Optimal Subnetting/VLAN Sizing: IaC encourages thoughtful IP address management and subnet sizing from the outset, preventing inefficient use of IP space or overly large broadcast domains.
- VLAN Pruning: For on-premises networks, Terraform (via Ansible or direct provider) can ensure VLAN pruning is configured consistently, preventing unnecessary broadcast traffic from flowing across trunk links.
- Cloud Network Segmentation: By deploying well-designed VPCs/VNets and subnets, Terraform ensures logical isolation, traffic flow optimization, and efficient application of security policies (Security Groups, NSGs).
- Resource Sizing: Terraform allows you to parameterize and consistently deploy network resources (e.g., VPN gateway bandwidth, NAT gateway capacity) according to performance requirements.
8.17. Terraform Run Optimization
- Terraform Workspaces: Use workspaces to manage multiple environments (dev, staging, prod) with the same configuration, isolating state files.
- Modularization: Break down large configurations into smaller, reusable modules to improve readability, maintainability, and execution speed.
- Targeting: For specific changes, use
terraform apply -target=resource_type.nameto only apply changes to a subset of resources (use with caution in production). - Parallelism: Terraform executes many operations in parallel by default, but you can control this with
-parallelismfor specific needs (e.g., reduce for API rate limits, increase for faster deployment).
8.18. Monitoring Recommendations
Integrate monitoring solutions (e.g., Prometheus, Grafana, cloud-native monitoring like CloudWatch/Azure Monitor) with your IaC workflow. While Terraform doesn’t monitor directly, it can provision monitoring agents, dashboards, and alerts, ensuring that performance metrics for VLANs (e.g., interface utilization, error rates on trunks) are collected and analyzed consistently.
Hands-On Lab
This lab will guide you through deploying a hybrid network setup using Terraform, comprising a cloud VPC/VNet and simulated on-premises VLANs.
8.19. Lab Topology
nwdiag {
network "Internet" {
shape = cloud;
}
network "AWS Cloud Environment" {
address = "10.0.0.0/16"
Internet; # Connection to Internet
aws_igw [label="AWS IGW"];
network "AWS Public Subnet (VLAN-like)" {
address = "10.0.1.0/24"
aws_web_ec2 [label="Web Server EC2"];
}
network "AWS Private Subnet (VLAN-like)" {
address = "10.0.10.0/24"
aws_app_ec2 [label="App Server EC2"];
}
aws_vpn_gw [label="AWS VPN Gateway"];
aws_igw -- aws_vpn_gw; # VPN traffic passes via IGW
}
network "On-Premises Lab Network" {
address = "192.168.0.0/16"
on_prem_router [label="On-Prem VPN Router"];
on_prem_switch [label="On-Prem Core Switch"];
ansible_controller [label="Ansible Controller (VM)"];
network "VLAN 10 (Users)" {
address = "192.168.10.0/24"
user_pc_1 [label="User PC"];
}
network "VLAN 20 (Servers)" {
address = "192.168.20.0/24"
lab_server_1 [label="Lab Server"];
}
ansible_controller -- on_prem_switch; # Management path
on_prem_router -- on_prem_switch; # Routing path
on_prem_switch -- user_pc_1;
on_prem_switch -- lab_server_1;
on_prem_router -- Internet [label="VPN Tunnel to AWS"]; # Simulated/conceptual
}
}
8.20. Objectives
- Provision an AWS VPC with public and private subnets using Terraform.
- Deploy a simulated Ansible Control Host (e.g., a basic EC2 instance in AWS, or use your local machine).
- Use Terraform’s
local-execto trigger an Ansible playbook that “configures” (simulates) VLANs on your local machine (acting as an on-prem device). - Verify the cloud resources and the simulated on-prem configuration.
8.21. Step-by-Step Configuration
Prerequisites:
- AWS account with programmatic access configured (AWS CLI installed and configured).
- Terraform installed.
- Ansible installed (if running locally).
- A basic understanding of network concepts.
Lab Setup (Files):
Create a directory named terraform_vlan_lab. Inside it, create:
main.tf(for AWS VPC)on_prem_config.tf(for Ansible integration)variables.tfoutputs.tfinventory.iniconfigure_vlans.yaml
variables.tf:
variable "aws_region" {
description = "AWS region to deploy resources"
type = string
default = "us-east-1"
}
variable "vpc_cidr" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "public_subnet_cidr" {
description = "CIDR block for the public subnet"
type = string
default = "10.0.1.0/24"
}
variable "private_subnet_cidr" {
description = "CIDR block for the private subnet"
type = string
default = "10.0.10.0/24"
}
variable "on_prem_vlans" {
description = "Map of VLAN ID to Name for on-prem devices"
type = map(string)
default = {
"10" = "Users",
"20" = "Servers"
}
}
variable "on_prem_device_ip" {
description = "IP address of the simulated on-prem device (your local machine)"
type = string
default = "127.0.0.1" # Use localhost for simulation
}
outputs.tf:
output "aws_vpc_id" {
description = "ID of the created AWS VPC"
value = aws_vpc.lab_vpc.id
}
output "aws_public_subnet_id" {
description = "ID of the created public subnet"
value = aws_subnet.public_subnet.id
}
output "aws_private_subnet_id" {
description = "ID of the created private subnet"
value = aws_subnet.private_subnet.id
}
output "ansible_vlan_config_status" {
description = "Status of on-prem VLAN configuration via Ansible"
value = null_resource.configure_local_vlans.id
}
main.tf (AWS VPC and Subnets):
provider "aws" {
region = var.aws_region
}
resource "aws_vpc" "lab_vpc" {
cidr_block = var.vpc_cidr
tags = {
Name = "terraform-vlan-lab-vpc"
}
}
resource "aws_internet_gateway" "lab_igw" {
vpc_id = aws_vpc.lab_vpc.id
tags = {
Name = "terraform-vlan-lab-igw"
}
}
resource "aws_subnet" "public_subnet" {
vpc_id = aws_vpc.lab_vpc.id
cidr_block = var.public_subnet_cidr
availability_zone = data.aws_availability_zones.available.names[0]
map_public_ip_on_launch = true
tags = {
Name = "public-subnet"
}
}
resource "aws_subnet" "private_subnet" {
vpc_id = aws_vpc.lab_vpc.id
cidr_block = var.private_subnet_cidr
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "private-subnet"
}
}
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.lab_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.lab_igw.id
}
tags = {
Name = "public-route-table"
}
}
resource "aws_route_table_association" "public_rt_assoc" {
subnet_id = aws_subnet.public_subnet.id
route_table_id = aws_route_table.public_rt.id
}
on_prem_config.tf (Ansible Integration):
# This resource will trigger the Ansible playbook
resource "null_resource" "configure_local_vlans" {
triggers = {
# Re-run Ansible if VLAN definitions change
vlans_hash = jsonencode(var.on_prem_vlans)
}
provisioner "local-exec" {
command = <<-EOT
ansible-playbook \
-i "${path.module}/inventory.ini" \
"${path.module}/configure_vlans.yaml" \
--extra-vars '{"target_device_ip": "${var.on_prem_device_ip}", "vlans_to_create": ${jsonencode(var.on_prem_vlans)}}'
EOT
working_dir = path.module
}
}
inventory.ini:
[local_device]
ansible_connection=local
(Note: target_device_ip will be passed via --extra-vars)
configure_vlans.yaml:
---
- name: Simulate On-Prem VLAN Configuration
hosts: local_device
gather_facts: false
tasks:
- name: Display VLANs to be "configured"
debug:
msg: "Simulating creation of VLAN () on "
loop: ""
loop_control:
label: "VLAN "
- name: Create dummy files for VLANs (simulation)
ansible.builtin.copy:
content: "This is a simulated configuration for VLAN ()\n"
dest: "/tmp/vlan_.cfg"
loop: ""
loop_control:
label: "VLAN "
Steps:
- Initialize Terraform:
terraform init - Review the Plan:Carefully examine the output to ensure Terraform plans to create the VPC, subnets, and trigger the Ansible playbook as expected.
terraform plan - Apply the Configuration:Type
terraform applyyeswhen prompted. Terraform will provision the AWS resources and then execute the Ansible playbook. You should see output from Ansible indicating the simulated VLAN creation.
8.22. Verification Steps
Verify AWS Resources:
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=terraform-vlan-lab-vpc" --query "Vpcs[*].VpcId" --output text aws ec2 describe-subnets --filters "Name=tag:Name,Values=public-subnet" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock}" --output table aws ec2 describe-subnets --filters "Name=tag:Name,Values=private-subnet" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock}" --output tableConfirm that the VPC and subnets have been created with the correct CIDR blocks.
Verify Simulated On-Prem VLANs: Check your local
/tmpdirectory for the dummy configuration files created by Ansible.ls /tmp/vlan_*.cfg cat /tmp/vlan_10.cfg cat /tmp/vlan_20.cfgThis confirms the Ansible playbook was executed successfully.
8.23. Challenge Exercises
- Add more VLANs: Modify
variables.tfto add a new VLAN (e.g., VLAN 30 for “Voice”). Rerunterraform planandterraform apply. - Add a Security Group: Create an
aws_security_groupresource inmain.tfto allow SSH (port 22) into the public subnet. Modify the web server EC2 resource (if you add one later) to use this SG. - Clean up: After completing the lab, destroy the resources to avoid incurring costs:Type
terraform destroyyeswhen prompted.
Best Practices Checklist
[x] Configuration Best Practices:
* [x] Use a consistent naming convention for all resources (cloud and on-prem).
* [x] Organize Terraform code into logical modules (e.g., vpc, subnets, network_devices).
* [x] Define variables for all configurable parameters.
* [x] Leverage data sources to query existing infrastructure.
* [x] Ensure terraform fmt is run on all HCL files for consistent formatting.
* [x] Implement terraform validate as part of your CI/CD pipeline.
* [x] For on-prem, use idempotency in configuration management tools like Ansible.
* [x] Plan for IP address management (IPAM) for both cloud and on-prem.
[x] Security Hardening:
* [x] Store Terraform state in a secure, remote, and versioned backend.
* [x] Encrypt Terraform state at rest.
* [x] Use secrets management solutions (Vault, AWS Secrets Manager, Azure Key Vault) for sensitive data.
* [x] Apply the principle of least privilege to Terraform execution roles/users.
* [x] Conduct regular code reviews and static analysis of IaC code.
* [x] Implement explicit access and trunk port configurations for on-prem.
* [x] Disable Dynamic Trunking Protocol (DTP) on unused or access ports.
* [x] Set unused ports to an unused VLAN and shut them down.
* [x] Change native VLAN on trunks to an unused VLAN (not VLAN 1).
* [x] Implement network security groups (cloud) or VACLs (on-prem) for inter-VLAN filtering.
[x] Monitoring Setup: * [x] Terraform configurations include provisioning of monitoring agents and logging configurations for network resources. * [x] Alerting is configured for critical network events (e.g., high traffic on trunk, interface errors). * [x] Dashboards are created to visualize VLAN/subnet performance and connectivity.
[x] Documentation: * [x] All Terraform configurations are well-commented. * [x] Git commit messages clearly describe changes. * [x] Network diagrams (nwdiag, PlantUML, D2) are generated from code and kept up-to-date. * [x] README files for modules and root configurations describe their purpose and usage.
[x] Change Management:
* [x] All infrastructure changes flow through a Git-based pull request (PR) workflow.
* [x] terraform plan output is reviewed and approved before applying changes to production.
* [x] Implement CI/CD pipelines for automated plan, validate, and apply stages.
* [x] Enable state locking for remote backends to prevent concurrent modifications.
* [x] Define rollback procedures (e.g., revert Git commit, terraform state rm, terraform import).
Reference Links
Terraform Documentation:
- Terraform Getting Started: https://developer.hashicorp.com/terraform/intro
- AWS Provider Documentation: https://registry.terraform.io/providers/hashicorp/aws/latest/docs
- Azure Provider Documentation: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
- Terraform State: https://developer.hashicorp.com/terraform/language/state
VLAN Standards:
- IEEE 802.1Q (VLAN Tagging): Refer to the latest version of the standard on https://standards.ieee.org/ (e.g., IEEE 802.1Q-2022).
- IEEE 802.1ad (QinQ / Provider Bridges): Refer to the latest version of the standard on https://standards.ieee.org/.
Network Automation Tools:
- Ansible Documentation: https://docs.ansible.com/ansible/latest/index.html
- Ansible Network Modules: https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/index.html
Diagramming Tools:
- nwdiag: http://blockdiag.com/en/nwdiag/
- Graphviz (DOT language): https://graphviz.org/doc/info/lang.html
- PlantUML: https://plantuml.com/
- D2: https://d2lang.com/
What’s Next
This chapter has equipped you with the foundational knowledge and practical skills to manage VLANs and network segmentation using Terraform across cloud and on-premises environments. You’ve learned about IaC principles, Terraform’s core components, multi-vendor automation strategies, and critical security and troubleshooting considerations.
In the next chapter, we will delve into Chapter 9: Advanced VLAN Features: VXLAN, PVLANs, and EVPN, exploring more complex segmentation technologies that build upon traditional VLANs to meet the demands of modern data centers and highly scalable network architectures. We will examine how these advanced features are implemented and managed, often still leveraging IaC for consistent deployment.