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
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.
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.
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
.
Il server web, raggiungibile all’indirizzo configurato nel paragrafo precedente, dovrà:
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 ciasun 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
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
[email protected].
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 .
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:
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:
bash
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.
Il laboratorio ZTP e l’applicazione Flask sono a disposizione nel repository Git dedicato ai subscriber di grado Learner o superiore .