Installazione automatica di router Cisco XR con Zero Touch Provisioning

Andrea Dainese
18 Ottobre 2023
Post cover

In questo articolo vediamo come ottimizzare il provisioning di un centinaio di apparati Cisco XR in modo che siano configurati con il minor intervento umano possibile. A seconda del contesto i dispositivi potrebbero essere spediti direttamente dalla fabbrica e configurati automaticamente in loco, o più probabilmente potrebbero essere configurati automaticamente in laboratorio, verificati e spediti per la loro installazione. Ci affideremo a quello che è detto ZTP o Zero Touch Provisioning. Il protocollo ZTP permette di configurare un dispositivo arrivato da fabbrica, senza alcun intervento umano. ZTP è vendor-specific, e in particolare su Cisco XR richiede di

  • predisporre un server DHCP per assegnare un indirizzo IP ai dispositivi;
  • predisporre un server web che generi le configurazioni per ciascun dispositivo;
  • accendere i dispositivi in modo che possano acquisire un indirizzo via DHCP e raggiungere il server web.

Nello scenario che ci siamo prefigurati, predisponiamo un ambiente di laboratorio dove i dispositivi verranno sballati, configurati in modo automatico, imballati e spediti nella destinazione finale, dove personale non tecnico procederà all’installazione fisica, al collegamento dei cavi di rete e all’accensione. Supponiamo di non avere competenze tecniche nei siti remoti e di non poter inviare personale tecnico.

Vediamo quindi i dettagli.

Configurazione della rete di laboratorio

Predisponiamo un ambiente di laboratorio utilizzando un sistema Linux con due schede di rete: la prima pnet0 connetterà il sistema alla rete corporate, la seconda pnet9 sarà collegata ad una rete dedicata e isolata. I dispositivi da configurare verranno quindi connessi ad uno switch fisico, dedicato, il cui gateway è la scheda pnet9 del sistema Linux.

Lab topology

Sul sistema Linux useremo Dnsmasq configurato come segue:

port=0
interface=pnet9
dhcp-range=169.254.1.0,169.254.1.253,30d
dhcp-option=67,http://169.254.1.1:8080/ztp
log-dhcp

Dnsmasq servirà quindi la rete 169.254.1.0/24 assegnando gli IP liberi ai client e mantenendo l’assegnazione per 30 giorni. Sempre via DHCP verrà comunicato ai client l’URL da chiamare per l’autoconfigurazione via ZTP. Le richieste DHCP verranno loggate tramite syslog, e verranno generalmente salvate su /var/log/syslog.

Predisposizione delle configurazioni

Il server web, raggiungibile all’indirizzo configurato nel paragrafo precedente, dovrà:

  • rendere accessibile uno script Bash unico tutti i dispositivi;
  • generare una configurazione specifica per ciascun dispositivo;
  • rendere accessibile la configurazione corretta a ciascun dispositivo.

Useremo Flask per creare una piccola applicazione web in grado di generare in modo dinamico la configurazione per ciascun dispositivo. L’applicazione risponderà a due URL:

  • /ztp (GET) che renderà disponibile lo script Bash ai dispositivi Cisco XR;
  • /config (POST) che renderà disponibile la configurazione specifica a ciascun dispositivo che dovrà inviare il proprio numero di serie.

Una volta pronta, l’applicazione Flask può essere eseguita con:

flask --app ztp run -p 8080 -h 169.254.1.1

Ci assicuriamo che l’applicazione sia in ascolto sull’interfaccia corretta e che i due URL rispondano correttamente:

wget -q -O- http://169.254.1.1:8080/ztp
wget -q -O- --post-data="serial=1234" http://169.254.1.1:8080/config

L’URL /ztp restituirà un testo simile al seguente, e uguale per tutti i dispositivi:

#!/bin/bash

export CONFIG_FILE="/tmp/config.txt"
source /pkg/bin/ztp_helper.sh

SN=$(dmidecode | grep -m 1 "Serial Number:" | awk '{print $NF}')
PN=$(xrcmd "show inventory location 0/RP" | grep -m1 "PID" | awk '{print $2}')
RESULT=$(wget -O- --post-data="serial=${SN}&model=${PN}" {{ url }} > $CONFIG_FILE)

xrapply_with_reason "Initial ZTP configuration" $CONFIG_FILE

Il dispositivo, dopo aver acquisito via DHCP un indirizzo IP, recupererà lo script descritto sopra. Tale script recupera il numero di serie (via dmidecode) e il modello (via show inventory). Il dispositivo, usando tali parametri, chiederà il secondo URL che userà come configurazione iniziale.

L’URL /config restituirà, in base ai parametri passati in POST, la configurazione minima per rendere il dispositivo accessibile via SSH:

username cisco
 group root-lr
 password 0 cisco
!
hostname device01
!
domain name example.com
!
vrf OOB address-family ipv4 unicast
!
router static vrf OOB address-family ipv4 unicast
    0.0.0.0/0 169.254.1.1
!
interface MgmtEth0/0/CPU0/0
 vrf OOB
 ipv4 address 169.254.1.11 255.255.255.0
 no shutdown
!
ssh server v2
ssh server vrf OOB
!
line default
 transport input ssh

Accensione e verifica del processo ZTP

Siamo giunti al passaggio finale ma più critico: accensione del dispositivo e verifica che il processo ZTP funzioni correttamente. Avviando un dispositivo Cisco XR nuovo di fabbrica, il processo ZTP dovrebbe partire subito dopo la nota legale relativa alle feature crittografiche:

This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply third-party
authority to import, export, distribute or use encryption. Importers,
exporters, distributors and users are responsible for compliance with
U.S. and local country laws. By using this product you agree to comply
with applicable laws and regulations. If you are unable to comply with
U.S. and local laws, return this product immediately.

A summary of U.S. laws governing Cisco cryptographic products may be
found at:
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html

If you require further assistance please contact us by sending email to
export@cisco.com.



RP/0/RP0/CPU0:Oct 18 08:11:22.659 UTC: ifmgr[363]: %PKT_INFRA-LINK-3-UPDOWN : Interface MgmtEth0/RP0/CPU0/0, changed state to Down
RP/0/RP0/CPU0:Oct 18 08:11:22.661 UTC: ifmgr[363]: %PKT_INFRA-LINK-3-UPDOWN : Interface MgmtEth0/RP0/CPU0/0, changed state to Up
RP/0/RP0/CPU0:Oct 18 08:11:29.975 UTC: pyztp2[330]: %INFRA-ZTP-4-CONFIG_INITIATED : ZTP has initiated config load and commit operations
RP/0/RP0/CPU0:Oct 18 08:11:47.203 UTC: pyztp2[330]: %INFRA-ZTP-4-CONFIG_FINISHED : ZTP has finished config load and commit operations
RP/0/RP0/CPU0:Oct 18 08:11:53.034 UTC: pyztp2[330]: %INFRA-ZTP-4-PROVISIONING_COMPLETED : ZTP has successfully completed the provisioning
RP/0/RP0/CPU0:Oct 18 08:11:59.329 UTC: pyztp2[330]: %INFRA-ZTP-4-EXITED : ZTP exited

Se il processo ZTP ha funzionato correttamente, il server DHCP avrà rilasciato un IP:

2023-10-18T11:32:42.306237+02:00 kali dnsmasq-dhcp[3818]: 548912439 vendor class: PXEClient:Arch:00009:UNDI:003010:PID:N540-ACC-SYS
2023-10-18T11:32:42.306699+02:00 kali dnsmasq-dhcp[3818]: 548912439 user class: xr-config
2023-10-18T11:32:42.306856+02:00 kali dnsmasq-dhcp[3818]: 548912439 DHCPDISCOVER(pnet9) 40:14:82:c1:11:11
2023-10-18T11:32:42.307036+02:00 kali dnsmasq-dhcp[3818]: 548912439 tags: pnet9
2023-10-18T11:32:42.307208+02:00 kali dnsmasq-dhcp[3818]: 548912439 DHCPOFFER(pnet9) 169.254.1.11 40:14:82:c1:11:11
2023-10-18T11:32:42.309068+02:00 kali dnsmasq-dhcp[3818]: 548912439 requested options: 1:netmask, 28:broadcast, 2:time-offset, 3:router,
2023-10-18T11:32:42.309925+02:00 kali dnsmasq-dhcp[3818]: 548912439 requested options: 15:domain-name, 6:dns-server, 12:hostname,
2023-10-18T11:32:42.310094+02:00 kali dnsmasq-dhcp[3818]: 548912439 requested options: 67:bootfile-name, 43:vendor-encap, 143
2023-10-18T11:32:42.310183+02:00 kali dnsmasq-dhcp[3818]: 548912439 next server: 169.254.1.1
2023-10-18T11:32:42.310289+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  1 option: 53 message-type  2
2023-10-18T11:32:42.310366+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option: 54 server-identifier  169.254.1.1
2023-10-18T11:32:42.310433+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option: 51 lease-time  30d
2023-10-18T11:32:42.310531+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option: 58 T1  15d
2023-10-18T11:32:42.311451+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option: 59 T2  26d6h
2023-10-18T11:32:42.311641+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option:  1 netmask  255.255.255.0
2023-10-18T11:32:42.311775+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option: 28 broadcast  169.254.1.255
2023-10-18T11:32:42.312018+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size:  4 option:  3 router  169.254.1.1
2023-10-18T11:32:42.312554+02:00 kali dnsmasq-dhcp[3818]: 548912439 sent size: 25 option: 67 bootfile-name  http://169.254.1.1:8080/ztp

E il server Web sarà stato contattato sui due URL:

 * Serving Flask app 'ztp'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://169.254.1.1:8080
Press CTRL+C to quit
169.254.1.11 - - [18/Oct/2023 14:47:06] "GET /ztp HTTP/1.1" 200 -
169.254.1.11 - - [18/Oct/2023 14:47:33] "POST /config HTTP/1.1" 200 -

A questo punto il dispositivo sarà raggiungibile e pronto per essere configurato mediante sistemi di automazione secondari, come Ansible.

Sviluppo e troubleshooting

Apparentemente il processo ZTP descritto appare semplice e lineare. In realtà per farlo funzionare correttamente ha richiesto diverse ore di test per capire come e dove il processo ZTP si fermava. Vediamo quindi quali strumenti abbiamo per fare troubleshooting.

Lo stato di ZTP può essere visto mediante il comando show ztp status:

State             : Terminated
Current Fetcher   : No active fetcher

Il processo ZTP viene eseguito solo se il router ha le impostazioni di fabbrica. Diversamente viene omesso. Se il nostro router non è nuovo di fabbrica, abbiamo due possibilità, entrambi utili.

Possiamo forzare da riga di comando il processo ZTP:

ztp initiate

Oppure possiamo, sempre da riga di comando, cancellare la configurazione e resettare ZTP:

ztp clean
configure terminal
commit replace
reload

I log del processo ZTP sono archiviati nel dispositivo e possono essere visionati con show ztp logging. Tuttavia è scomodo basarsi solo su questi log, considerando che ogni boot richiede alcuni minuti. La miglior soluzione che ho trovato è stata quella di usare la Bash disponibile sui dispositivi Cisco XR e invocare manualmente lo script:

wget -O- http://169.254.1.1:8080/ztp | bash -x

I comandi precedenti, digitati da console, permettono di aprire una istanza Bash e di eseguire lo script reso disponibile dall’applicativo da noi sviluppato. Al termine dell’esecuzione dovremmo avere il dispositivo configurato secondo le aspettative.