Skip to content

Task 06 - Variables

Estimated Time to Complete: ~15 minutes

In this task you'll use variables in your Network as Code configurations. Variables let you define a value once (at the global, group, or device level) and reference it everywhere it's needed, so you can keep shared settings in one place while letting each device override only what's unique to it.

What you'll learn

By the end of this task you will have:

  • Used ${VARIABLE_NAME} placeholders inside a global configuration
  • Defined a global variable (${SITE}) that every device inherits
  • Defined a per-device variable (${HOSTNAME}) that resolves differently on each device

Variables in Network as Code

Variables in Network as Code work similarly to variables in programming languages. You define a variable with a value at one level (device, device group, or global), and then reference it elsewhere using the ${VARIABLE_NAME} syntax. When the Network as Code module processes your configuration, it substitutes the variable references with their actual values.

Benefits of using variables:

  • Consistency: Define a value once, use it everywhere
  • Maintainability: Change a value in one place, it updates everywhere it's used
  • Reusability: Same configuration template can be used with different variable values
  • Device-specific customization: Each device can have its own variable values while sharing configuration structure

Use case: dynamic hostname in banner and system hostname config

In this example, you'll touch two different pieces of configuration on each device: the hostname and the login banner.

  • You'll define the HOSTNAME variable per device.

  • You'll use that variable to set the system hostname in the global configuration.

  • You'll update the login banners on each device to display its own hostname. Instead of creating separate banner configurations for each device, you'll use the same global banner configuration with the HOSTNAME variable.

  • Let Network as Code substitute the variable automatically in both the system hostname and banner configuration

The power of variables

One banner template, multiple device-specific outputs!

One place to define the hostname variable per device, used in multiple configuration sections.

Step 1: Update the global configuration file

First, update the global configuration to use a variable in the banner. Open data/global.nac.yaml in VS Code and update it with the following content:

data/global.nac.yaml
---
iosxe:
  global:
    variables:
      SITE: "LTRXAR-2008 Lab"
    configuration:
      banner:
        login: |-
          #########################################
          #                                       #
          #   Welcome to the IOS XE as Code Lab!  #
          #                                       #
          #########################################
          Site:   ${SITE}
          Device: ${HOSTNAME}
      system:
        hostname: ${HOSTNAME}

Two kinds of variable reference at work here:

  • ${SITE} - defined globally (at the iosxe.global.variables level). Every device inherits the same value unless a device explicitly overrides it. This is how you keep organization-wide constants (site name, location, lab ID, DNS domain) in exactly one place.
  • ${HOSTNAME} - referenced globally, but you'll define it per-device in Step 2 so each device resolves it to its own value.

Banner config:

  • banner: login: - the login banner shown on SSH connect.
  • |- - YAML block-scalar indicator; preserves newlines and indentation inside the string while removing the trailing newline.

System config:

  • system: hostname: - sets the IOS XE hostname CLI to the resolved value of ${HOSTNAME}.

Variable syntax

Variables use the ${VARIABLE_NAME} syntax. Names are case-sensitive: ${HOSTNAME} and ${hostname} are different variables. The lab uses uppercase by convention - it makes variables visually distinct from the surrounding YAML, and is a common pattern across Network as Code data models.

The image below illustrates the updated global configuration in VS Code:

VS Code Global Variables

YAML Formatting

When pasting multi-line strings in YAML (like this banner), ensure the indentation is correct. The | character indicates a multi-line string, and the following lines should be indented properly to be part of that string.

To learn more about the multi-line string (block scalar) YAML syntax, refer to yaml-multiline.info.

Step 2: Define variables at device level

Now you need to define the HOSTNAME variable for each device. Open data/devices/core.nac.yaml in VS Code and update it with the following content:

data/devices/core.nac.yaml
---
iosxe:
  devices:
    - name: core
      host: 198.18.130.10
      variables:
        HOSTNAME: core
      configuration:
        interfaces:
          loopbacks:
            - id: 0
              description: "Router-ID loopback"
              ipv4:
                address: 198.51.100.10
                address_mask: 255.255.255.255

What's new:

  • variables: - section where you define device-specific variables.
  • HOSTNAME: core - sets ${HOSTNAME} to core for this device only. The system.hostname and banner.login in global.nac.yaml will resolve to this value when the merged model is rendered for core.

The image below illustrates the device configuration with variables in VS Code:

VS Code Device Variables

Step 3: Add variables to other devices

Now add the HOSTNAME variable to the other device configuration files.

Update data/devices/border.nac.yaml:

data/devices/border.nac.yaml
---
iosxe:
  devices:
    - name: border
      host: 198.18.130.20
      variables:
        HOSTNAME: border

Update data/devices/access01.nac.yaml:

data/devices/access01.nac.yaml
---
iosxe:
  devices:
    - name: access01
      host: 198.18.130.11
      variables:
        HOSTNAME: access01

Update data/devices/access02.nac.yaml:

data/devices/access02.nac.yaml
---
iosxe:
  devices:
    - name: access02
      host: 198.18.130.12
      variables:
        HOSTNAME: access02

Name and hostname

The name attribute under devices identifies the device in Network as Code. The HOSTNAME variable value you set is what will be used in the system hostname and banner configuration. They can be the same or different, depending on your design.

How variable substitution works

When Terraform processes your configuration, it performs variable substitution at each level, for each device.

Variable Substitution Variable Substitution

What access01 actually ends up with after substitution

After you run terraform apply in Step 4, open model.yaml. The access01 entry will have every ${HOSTNAME} reference already replaced with the literal string - no variable markers remain in the final model:

model.yaml (excerpt - access01 after resolution)
iosxe:
  devices:
    - name: access01
      host: 198.18.130.11
      configuration:
        banner:
          login: |
            ######################################
            #                                    #
            #   Welcome to Network as Code Lab!  #
            #                                    #
            ######################################
            Device: access01               # ← ${HOSTNAME} resolved
        system:
          hostname: access01               # ← ${HOSTNAME} resolved

Substitution happens once, at merge time, before the Terraform provider ever opens a connection to a device. By the time anything hits NETCONF, the payload is fully-resolved concrete YAML - no ${...} strings ever travel to the device. The model.yaml file is the authoritative record of "what was actually sent."

Running access02, core, and border through the same logic produces hostname: access02, hostname: core, and hostname: border respectively - same template, four different results.

Variable precedence

Variables can be defined at multiple levels. When the same variable is defined at different levels, the more specific level takes precedence:

  1. Device variables (highest precedence) - Override everything
  2. Device group variables (medium precedence) - Override global
  3. Global variables (lowest precedence) - Default values

This allows you to define default values globally and override them per device or device group when needed.

Variable Precedence Example

The config below is only an example, you do not need to add this in your lab.

example: variable precedence (illustrative)
---
iosxe:
  global:
    variables:
      TIMEZONE: UTC  # Global default
  devices:
    - name: example-device
      variables:
        TIMEZONE: America/New_York  # Overrides global default

Step 4: Apply configuration

Open your WSL Ubuntu terminal and navigate to your project directory:

cisco@wkst1:~$
cd ~/nac-iosxe

Optionally, preview the changes Terraform will make:

cisco@wkst1:~/nac-iosxe$
terraform plan

In the plan output, look for four separate hostname changes - one per device - even though you only edited one banner template in global.nac.yaml. That's variable substitution producing four distinct renders from one source, which is the whole point of this task.

Apply the configuration:

cisco@wkst1:~/nac-iosxe$
terraform apply
When prompted, type yes to confirm the deployment.

Step 5: Verify variable substitution

After Terraform completes successfully, verify the configuration was applied correctly on each device.

Use Solar-PuTTY to connect and verify:

  1. Open Solar-PuTTY from your desktop
  2. Connect to the core switch
  3. Verify the updated hostname and banner
  4. Repeat for other switches (border, access01, access02) to see their specific hostnames

Solar-PuTTY Core Banner

Each device shows its own hostname in the banner, demonstrating that the same template produced device-specific results.

Review the model.yaml file

After running terraform apply, open model.yaml in VS Code to see how variables are resolved. Each device appears with its variable values already substituted into the rendered configuration - this is the final form Terraform sends to the devices.

Common variable use cases

Variables are powerful for many scenarios beyond hostnames (device identity). Here are some common use cases:

Use Case Variable Example Benefit
Network segments ${MGMT_VLAN}, ${DATA_VLAN} Easy VLAN changes across devices
IP addressing ${LOOPBACK_IP}, ${GATEWAY} Device-specific IP configuration
Credentials ${SNMP_COMMUNITY} Centralized credential management
Thresholds ${LOG_LEVEL}, ${TIMEOUT} Environment-specific tuning

Environment variables

Environment variables can also be used in Network as Code configurations. They are defined outside of the configuration files and can be referenced using the syntax below:

Environment Variable Example

The config below is only an example, you do not need to add this in your lab.

example: !env reference (illustrative)
---
iosxe:
  devices:
    - name: example-device
      system:
        enable_secret: !env ENABLE_SECRET
        enable_secret_type: "0"

In the example above, the ENABLE_SECRET environment variable is referenced and used for the device's enable secret.

Security Best Practice

Using environment variables is good practice for sensitive information like passwords.

What you've accomplished

In this task, you have:

  • ✅ Learned how variables work in Network as Code configurations
  • ✅ Updated the global configuration to use a variable placeholder
  • ✅ Defined device-specific variable values
  • ✅ Understood variable substitution and precedence rules
  • ✅ Applied and verified variable-based configuration

What's next

Tasks 07-09 cover the three template types (model, file, cli) and are optional - they demonstrate advanced patterns but aren't prerequisites for any later task. If you're short on time, jump straight to Task 10 - Schema validation. Otherwise, continue with Task 07.


← Previous: Task 05 - Single device config · Next: Task 07 - Templates 'model'