Network Automation

Automatically Configure switchports for 802.1x, based on assigned VLANs, using Ansible

Conscias Senior Nettverkskonsulent – William Lindberg –  har blogget om hvordan du automatisk kan konfigurere switchporter for 802.1x, basert på tildelt VLAN, ved hjelp av Ansible.

The Scenario

Depending on where you are in the rollout of an 802.1x implementation, some switchports may be configured for 802.1x authentication, while others may not. For example, maybe you have a phased implementation where you focus on the low-hanging fruit first, like user machines and printers. Then you gradually implement more access control.

Also, some ports might need to be configured differently. For example, client ports may use host-mode multi-domain, while access points uses host-mode multi-host.

! Client Closed Mode
interface GigabitEthernetX/X/X
no logging event link-status
switchport mode access
switchport voice vlan X
access-session host-mode multi-domain
source template dot1x_closed

!AP Closed Mode
interface GigabitEthernetX/X/X
switchport mode access
access-session host-mode multi-host
source template dot1x_closed

 

Note: While you could dynamically assign an interface template to a port via ISE, based on the type of client connected, some parameters are not configurable inside a template. access-session host mode is one of the commands that can’t be applied to an interface template.

Challenges

We see the usual challenges here, if we were to configure every port manually:

  • Larger deployments takes longer time to implement. You might forget a switch
  • We have to verify the VLAN assignment of every port on every switch. High risk for error, especially if the VLAN assignments are not in any consecutive order.

The Goal

The Goal is to make a playbook that automatically configures the switchports based on the VLAN assignment. I assume the reader has some experience working with Ansible from before.

Automate switchport configuration using Ansible

Step 1: Gather the necessary information

Note: I’m running Ansible version 2.9 and Python version 3.6

First we need a list of all the switchports, excluding the uplink ports (they are not interesting for 802.1x configuration). A basic show running-config with a regex filter will do.

When we have the list of all the switchports, we can use that to check the VLAN assignment of those ports. If the VLAN number is the same on every switch in your environment, you can just use the information from the running-configuration. If your environment uses different VLAN numbers with the same name on different locations, you can use the name from the show interface switchport command.

Example from a Catalyst 9300:

! Lists all regular switchports, even when stacked
Switch#show running-config | i interface GigabitEthernet./0/
interface GigabitEthernet1/0/1
interface GigabitEthernet1/0/2
interface GigabitEthernet1/0/3
interface GigabitEthernet1/0/4
interface GigabitEthernet1/0/5
interface GigabitEthernet1/0/6
interface GigabitEthernet1/0/7
interface GigabitEthernet1/0/8
interface GigabitEthernet1/0/9

! Only Check for 802.1x-ready VLANS.
Switch#show interface Gi1/0/29 switchport | i \(native\)|\(CLIENT\)|\(AP\)
Access Mode VLAN: 2 (native)

Now we can write the first part of our playbook that will gather this information for us.

Note: Only the tasks are included in these examples.

Note: block is optional. There are many different reasons to use blocks. In this case it’s just to make the playbook look nice and ordered.

Step 2: Create lists

This was the hardest part to figure out. Right now we have 2 separate lists that needs to be combined. Also, interfaces with no 802.1x-ready VLANs needs to be omitted.

In order to combine 2 lists, we can create a dictionary, where the interface IDs are the key attributes, and the VLANs are the value attributes of those keys. In the output from the show interface switchport command, you can see that there is a colon (:) inside the output. That must be removed for this to work.

Note: The filters inside the curly brackets, after the |, have to be in the correct order. They are interpreted from left to right. Ansible documentation about filters: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_filters.html

Step 3: Create a filtered list

As I learnt the hard way, dictionaries are different from lists, so regular expression filters don’t seem to work so well for those. However, when you know what you are dealing with, you can match either the key or the value from the dictionary by converting it to a list, then convert it back to a dictionary.

Note: The “flatten” filter at the end of each above variable, converts the dictionary back to a list with only the filtered interface IDs in it. I don’t understand the logic behind it, but it is very beneficial for this purpose. Behaviors like this may change when upgrading to a newer version of Ansible. But for now, it works perfectly.

Step 4: Configure the Switchports

The hardest part is already done. Now we just need to create ios_config tasks that will automatically configure the ports for us.

Note: All through this playbook I have been using the loop function until now, because ansible is recommending that. But for some reason, the module ios_config didn’t work with loop, so I had to make an exception here and use with_items instead.

Special Mentions

Thank you Konstantin Suvorov. I don’t know you, but I see your name on stackoverflow all the time when I’m researching. If our paths crosses one day, I want to buy you a beer.

William har også blogget om hvordan du oppgraderer ISE fra versjon 2.4 til 3.1 og versjon 2.7 til 3.1 .