Automatiser son infrastructure réseau n’est pas une mince affaire. J’ai rédigé à ce sujet un article complet dans le cadre de la conférence JRES2019, dont les fondamentaux restent valides. Si vous ne l’avez pas lu vous pouvez le retrouver ici. Quand on souhaite automatiser soi-même son réseau avec un outil comme Ansible, un des challenges qui va se poser est de garantir que le réseau atteint bien la cible désirée. Quand on pousse une configuration cible en CLI sur un équipement, on ne tient pas compte de l’existant. La configuration poussée depuis l’automate va s’ajouter à celle actuellement en place et cela peut devenir un challenge sur une grand parc.
Il est tout à fait possible de customiser un playbook Ansible pour effectuer des opérations plus sophistiquées que juste pousser du CLI en effectuant des opérations complémentaires (par exemple en supprimant des CLI statements existants), cela peut nécessiter un peu de travail et demander à comprendre la logique interne de l’équipement. Une solution peut être d’utiliser le protocole NETCONF qui va pouvoir gérer ces opérations nativement. Le protocole NETCONF a été créé pour pouvoir configurer les équipements réseau de manière programmatique, en utilisant un language structuré approprié pour les machines, et décrit dans des modèles YANG documentés et publiés. Là aussi je vous renvoie à mon article JRES pour plus d’informations ainsi qu’à ce récent post. NETCONF va entre autres nous permettre de faire une opération de type “replace” qui permettra de remplacer un élément de configuration par un autre. Il suffit de spécifier notre objectif, et l’équipement va faire les opérations nécessaires pour y parvenir. On reste bien dans une logique “Intent-Based”!
Pour illustrer mes propos nous allons voir comment faire une modification sur un Catalyst 9000 d’une interface NVE d’une fabric BGP EVPN VXLAN. Si besoin vous pouvez vous référer au guide de configuration BGP EVPN VXLAN sur Catalyst 9000 ici. L’équipement a la configuration initiale suivante avec 3 VNI members et les VRF associées.
interface nve1 no ip address member vni 66666 vrf TATA member vni 77777 vrf TUTU member vni 88888 vrf TOTO
Je veux arriver à la configuration cible suivante:
member vni 11111 vrf TATA member vni 22222 vrf TUTU
Si je pousse brutalement ces configurations en CLI, je vais avoir des messages d’erreur. Il faut au préalable dé-configurer les VNI member existants associés aux vrf TATA et TUTU (on ne peut avoir qu’un VNI member par VRF). Comme expliqué plus tôt, je peux donc utiliser le protocole NETCONF pour configurer cette interface NVE et atteindre ma cible, quelque soit le point de départ. Je vais utiliser pour cela la structure définie dans le modèle YANG Cisco-IOS-XE-native. Comme je ne suis pas moi-même un robot, j’ai besoin d’un peu d’aide pour créer mon payload NETCONF. J’utilise donc l’outil Yang Suite qui va me permettre de naviguer dans les modèles avec une interface graphique et générer automatiquement le payload NETCONF.
Sur YANG Suite il y a aussi la possibilité d’utiliser un outil de conversion automatique de CLI en GUI que je n’ai pas utilisé ici. Vous pouvez-voir sur le screenshot ci-dessous à quoi ressemble cet outil de conversion, très pratique aussi pour démarrer sur des configurations basiques.
Le payload ci-dessous va demander de remplacer la configuration de l’interface NVE1 avec la nouvelle cible. Attention à ne rien oublier! Ne vous affolez pas sur la structure, rappelez-vous que ce n’est pas vous qui allez générer ce payload mais votre outil d’automatisation! Et pour lui ce format structuré en XML est du pain béni!
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"> <edit-config> <target> <candidate/> </target> <config> <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"> <interface> <nve xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="replace"> <name>1</name> <member-in-one-line> <member> <vni> <vni-range>11111</vni-range> <vrf>TATA</vrf> </vni> </member> <member> <vni> <vni-range>22222</vni-range> <vrf>TUTU</vrf> </vni> </member> </member-in-one-line> </nve> </interface> </native> </config> </edit-config> </rpc> <rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="102"> <commit/> </rpc> |
Vous noterez que NETCONF permet de faire les opérations en 2 étapes: d’abord on peut modifier la “candidate configuration” sur IOS-XE, et ensuite on peut demander un commit si la première configuration a été réalisée correctement.
Quand on va réaliser le commit, on peut voir avec les logs adéquats que l’équipement va réaliser de lui-même toutes les opérations nécessaires pour atteindre la cible, et ce dans le bon ordre.
*Nov 19 2021 22:57:46.120 UTC: %DMI-5-AUTH_PASSED: Switch 1 R0/0: dmiauthd: User 'admin' authenticated successfully from 10.209.217.219:52496 for netconf over ssh. External groups: PRIV15 *Nov 19 2021 22:57:46.906 UTC: %SYS-5-CONFIG_P: Configured programmatically by process iosp_dmiauthd_conn_100001_vty_100001 from console as admin on vty63 *Nov 19 2021 22:57:47.241 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:interface nve1 *Nov 19 2021 22:57:47.245 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:no member vni 66666 *Nov 19 2021 22:57:47.247 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:no member vni 77777 *Nov 19 2021 22:57:47.250 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:no member vni 88888 *Nov 19 2021 22:57:47.253 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:member vni 11111 vrf TATA *Nov 19 2021 22:57:47.257 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:member vni 22222 vrf TUTU *Nov 19 2021 22:57:47.258 UTC: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:exit *Nov 19 2021 22:57:47.269 UTC: %SYS-5-CONFIG_P: Configured programmatically by process iosp_dmiauthd_conn_100001_vty_100001 from console as admin on vty63 *Nov 19 2021 22:57:47.259 UTC: %DMI-5-CONFIG_I: Switch 1 R0/0: dmiauthd: Configured from NETCONF/RESTCONF by admin, transaction-id 10119
Après le commit, on peut constater que la configuration sur l’équipement correspond bien à notre objectif (notre “intent”).
interface nve1 no ip address member vni 11111 vrf TATA member vni 22222 vrf TUTU
Peu importe le point de départ, je sais atteindre nativement ma cible grâce au protocole NETCONF.
Un autre avantage énorme de NETCONF est que l’on est en mode transactionnel, à savoir qu’on va appliquer toute la configuration en une fois, et ce uniquement si l’ensemble est valide. Si je souhaite configurer maintenant la cible suivante pour mon interface nve1, en ayant omis au préalable de configurer ma VRF TITI:
member vni 33333 vrf TOTO member vni 44444 vrf TITI
Si je devais pousser mes changements en CLI, ces derniers seraient réalisés ligne à ligne et l’équipement réseau serait configuré jusqu’à ce que le CLI statement erroné soit atteint. Ici aussi, NETCONF va aider en n’appliquant la configuration que si l’ensemble est valide. Je vous propose de visualiser cela en pratique. Pour ça je génère tout d’abord mon payload NETCONF en utilisant le principe décrit plus haut afin d’effectuer le changement désiré.
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"> <edit-config> <target> <candidate/> </target> <config> <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"> <interface> <nve xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="replace"> <name>1</name> <member-in-one-line> <member> <vni> <vni-range>33333</vni-range> <vrf>TOTO</vrf> </vni> </member> <member> <vni> <vni-range>44444</vni-range> <vrf>TITI</vrf> </vni> </member> </member-in-one-line> </nve> </interface> </native> </config> </edit-config> </rpc> <rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="102"> <commit/> </rpc> |
Cette requête NETCONF génère l’erreur suivante assez explicite, qui peut elle aussi être analysée de manière programmatique (c’est-à-dire par un automate) qui peut même automatiquement déclencher les actions de correction nécessaires.
<error-message xml:lang="en">/native/interface/nve[name='1']/member-in-one-line/member/vni[vni-range='44444']/vrf (value "TITI"): VRF must be created 1st, deleted last</error-message> <error-info> <bad-element>vrf</bad-element> </error-info>
Comme l’ensemble de la configuration dans le payload NETCONF n’est pas valide, aucun changement n’est opéré sur notre commutateur. On a bien le modèle transactionnel désiré: on configure tout ou rien, et tout à la fois.
Rassurez-vous je ne suis pas en train de vous dire de faire toutes vos configurations avec le protocole NETCONF. Vous n’êtes pas des automates et le mode CLI reste le plus simple pour le commun des mortels. Mais quand vous allez automatiser votre infrastructure, demandez-vous si le mode CLI reste le plus efficace. Nos divers IOS (IOS-XE, NX-OS et IOS-XR) disposent d’API pour permettre une configuration programmatique et réellement dépasser le cap du fameux “fire & forget”. Vos automates vous diront merci!
Références:
- Livre IOS-XE programmability
- Article JRES2019 – Automatiaer son infrastructure réseau
- Guide de configuration BGP EVPN VXLAN sur Catalyst 9300
- IOS-XE 17.6 Programmability configuration guide