Auditer la configuration d'un switch Cisco (python+regexp) 🛠
Bon Dieu! Si vous connaissiez le nombre d'entreprises qui n'ont absolument rien à foutre de leur configuration d'équipement réseau (exemple: switch Cisco)... 😢
Pourtant il est plus que nécessaire de prendre le temps, de temps en temps de les auditer. Faut avouer que ça peut être très chiant, pour palier à ça, on peut très bien le scripter.
Cet article ne va pas expliquer comment auditer de A à Z une configuration avec Python mais plutôt vous donner des petits tips.
Je vais ainsi me concentrer sur les expressions rationnelles (REGEX) pour analyser la configuration des interfaces.
En effet, le plus courrament, nous allons chercher à auditer ces interfaces. C'est quelque chose qui peut être assez compliqué à réaliser, les expressions rationnelles sont là pour nous aider (enfin vite fait). 😒
Un fichier d'exemple
Et oui, je ne vais pas vous donner d'astuce sans vous présenter au moins un exemple de configuration à analyser, bien sûr, celle-ci est totalement factice.
interface Vlan1
no ip address
shutdown
!
interface Vlan10
ip address 10.0.0.1 255.2555.255.0
no ip route-cache
!
interface Vlan20
no ip address
!
interface GigabitEthernet1/0/5
description PC-05
switchport access vlan 20
switchport mode access
switchport nonegotiate
shutdown
spanning-tree portfast
spanning-tree bpduguard enable
!
interface GigabitEthernet1/0/6
description PC-06
switchport access vlan 10
switchport mode access
switchport nonegotiate
switchport port-security maximum 2
switchport port-security aging time 2
switchport port-security violation restrict
switchport port-security mac-address aaaa.aaaa.aaaa vlan access
switchport port-security mac-address bbbb.bbbb.bbbb vlan access
spanning-tree portfast
spanning-tree bpduguard enable
!
end
no ip http server
Effectivement, j'en vois certains venir, la configuration ne va pas casser 3 pattes à un canard mais c'est que pour l'exemple!
Vérifier qu'une interface contient/ne contient pas une configuration donnée
Pour l'exemple, on va vérifier le nom des interfaces contenant port-security.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
def main():
f = open("config.txt")
file = f.read()
# Stockage de la REGEX dans une variable
pattern = '(?sm)interface (\S*)(?:(?!^!$).)*port-security.*?!$'
result = re.findall(pattern, file)
for r in result:
print(r)
if __name__ == "__main__":
main()
Le résultat retourné est donc GigabitEthernet1/0/6
.
Pratique, n'est-ce pas! Vous pouvez obtenir une information détaillée en cliquant sur le lien suivant: explication.
Maintenant on va faire l'inverse, c'est-à-dire, lister toutes les interfaces qui ne contiennent pas la configuration port-security
.
Le principe reste donc le même, seule la REGEXP change.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
def main():
f = open("config.txt")
file = f.read()
# Stockage de la REGEX dans une variable
pattern = '(?sm)interface (\S*)(?:(?!port-security).)*?!$'
result = re.findall(pattern, file)
for r in result:
# Bypass des interfaces type Vlan
pattern = 'Vlan.*'
if re.match(pattern, r):
pass
else:
print(r)
if __name__ == "__main__":
main()
J'ai ajouté un condition pour éviter que les interfaces type Vlan
ne ressortent au test. Ainsi j'obtiens le retour GigabitEthernet1/0/5
qui est effectivement, l'interface qui ne détient par de switchport port-security
.
Alors bien sûr on pourrait aller encore plus loin, ce n'est pas le but de cet article.
Vérifier que notre switch contient telle ou telle configuration
Comme vous le savez sûrement, par exemple, il n'est pas très utile d'avoir l'interface web d'active sur celui-ci, ce qui d'ailleurs consitue facilement un vulnérabilité sur notre équipement (de l'exposer).
Ce pour quoi il est conseillé de la désactiver. On peut donc ainsi le vérifier de la manière suivante, vous verrez que la REGEXP est bien plus simple cette fois-ci!
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
def main():
f = open("config.txt")
file = f.read()
pattern = '^ip http server'
if re.match(pattern, file):
print("match")
else:
print("not match")
if __name__ == "__main__":
main()
Ça nous retourne bien not match
puisque ip http server
est précédé de no
dans notre configuration d'exemple.
A savoir que ces méthodes sont adaptables sur des fichiers déjà sauvegardés par Rancid, Oxidized ou autre! 😁
Maintenant, vous n'avez plus d'excuse pour auditer vos configurations réseau.