Skip to content

First Steps

This guide walks you through configuring a Cisco IOS-XE device using Network as Code — starting from a single YAML file and a one-line Terraform module, then progressively introducing the IOS-XE-specific constructs that make it easy to scale to multi-device deployments.

Prerequisites:

  1. NETCONF must be enabled on each IOS-XE device before Terraform can communicate with it. Connect to each device and run:

    config t
    netconf-yang
    end

    Ensure the device management IP is reachable from the machine running Terraform.

  2. The IOS-XE provider authenticates using environment variables. Set the following in your terminal:

    Terminal window
    export IOSXE_USERNAME=admin
    export IOSXE_PASSWORD=password
  3. In a new project directory, create a file named inventory.nac.yaml with the following content. Replace the host with your device’s management address:

    iosxe:
    devices:
    - name: SWITCH1
    host: 10.1.1.1
    configuration:
    system:
    hostname: SWITCH1
    mtu: 9198

    This file describes the desired state of a single device. The configuration block uses the same structure as the IOS-XE CLI, so you can describe any setting you would normally configure via the command line.

  4. In the same directory, create a file named main.tf:

    module "iosxe" {
    source = "netascode/nac-iosxe/iosxe"
    version = "0.1.0"
    yaml_files = ["inventory.nac.yaml"]
    }

    This is the only Terraform configuration required. The nac-iosxe module reads the YAML file and maps its contents to the underlying IOS-XE provider resources automatically.

  5. Run the following command to download the provider and module:

    Terminal window
    terraform init
  6. Preview and apply your changes:

    Terminal window
    terraform apply

    Review the plan and type yes to confirm. Terraform pushes the configuration to the device via NETCONF.

Congratulations! You have configured your first IOS-XE device using Network as Code. The sections below show how to extend this foundation to multi-device deployments using global configuration, device groups, templates, and interface groups.

When managing multiple devices, it is common to have settings that apply to all of them — such as NTP servers or syslog destinations. Rather than repeating these in every device block, you can define them once under the global key.

Add a second device and move shared configuration to global:

iosxe:
global:
configuration:
ntp:
servers:
- ip: 10.0.0.10
devices:
- name: SWITCH1
host: 10.1.1.1
configuration:
system:
hostname: SWITCH1
mtu: 9198
- name: SWITCH2
host: 10.1.1.2
configuration:
system:
hostname: SWITCH2
mtu: 9198

The IOS-XE module merges configuration at three levels — global → device group → device — with more specific levels taking precedence. NTP is now applied to both devices without duplication.

Device groups let you apply a shared configuration block to a set of devices. This is useful for anything that is common to a role (e.g., all access switches share the same spanning-tree settings).

Add a device_groups section and reference the group from each device:

iosxe:
global:
configuration:
ntp:
servers:
- ip: 10.0.0.10
device_groups:
- name: SWITCHES
configuration:
spanning_tree:
mode: rapid-pvst
devices:
- name: SWITCH1
host: 10.1.1.1
device_groups:
- SWITCHES
configuration:
system:
hostname: SWITCH1
mtu: 9198
- name: SWITCH2
host: 10.1.1.2
device_groups:
- SWITCHES
configuration:
system:
hostname: SWITCH2
mtu: 9198

Both devices now inherit the spanning_tree setting from the SWITCHES group. A device can belong to multiple groups, and each group is merged in order before the device-level configuration is applied.

Templates allow you to define reusable configuration blocks that are rendered per device using variable substitution. This avoids writing nearly-identical YAML blocks for each device when only a few values differ.

The simplest template type is model — defined inline in your YAML. Add a loopback template that uses a per-device variable:

First, register the template in your YAML (you can add this to inventory.nac.yaml or a separate file):

iosxe:
templates:
- name: LOOPBACK
type: model
configuration:
interfaces:
loopbacks:
- id: 0
ipv4:
address: ${lo0_ip}
address_mask: 255.255.255.255

Then assign the template and provide the variable on each device:

iosxe:
device_groups:
- name: SWITCHES
templates:
- LOOPBACK
configuration:
spanning_tree:
mode: rapid-pvst
devices:
- name: SWITCH1
host: 10.1.1.1
device_groups:
- SWITCHES
variables:
lo0_ip: 10.0.0.1
- name: SWITCH2
host: 10.1.1.2
device_groups:
- SWITCHES
variables:
lo0_ip: 10.0.0.2

When Terraform runs, the LOOPBACK template is rendered once per device, substituting ${lo0_ip} with the value from each device’s variables block. SWITCH1 gets 10.0.0.1 and SWITCH2 gets 10.0.0.2 as their loopback address.

Interface groups define a named set of interface configuration that can be reused across multiple interfaces or devices. They are especially useful for enforcing consistent settings on a class of interface — for example, all loopbacks should have the same MTU and shutdown state.

Add an interface group and reference it from the loopback template:

iosxe:
interface_groups:
- name: LOOPBACK_INTERFACE
configuration:
mtu: 1500
shutdown: false
templates:
- name: LOOPBACK
type: model
configuration:
interfaces:
loopbacks:
- id: 0
interface_groups: [LOOPBACK_INTERFACE]
ipv4:
address: ${lo0_ip}
address_mask: 255.255.255.255

The interface_groups key on an interface is a list, so a single interface can inherit from multiple groups. Group configuration is merged before any inline interface configuration is applied.


You now have the full building blocks of a Network as Code IOS-XE deployment. Explore the IOS-XE Data Models section for the complete list of configurable attributes, and the VXLAN example repository for a production-scale reference implementation.