Audyt konfiguracji urządzeń sieciowych z systemem Cisco IOS – narzędzia skryptowe

pentestAudyt sieci bywa czasem przedsięwzięciem żmudnym i długotrwałym. Jednym z elementów takiego audytu jest przegląd konfiguracji urządzeń sieciowych. Nie stanowi problemu manualne przeglądnięcie ustawień kilku czy nawet kilkunastu urządzeń, natomiast wzrost skali do stu lub tym bardziej kilkuset urządzeń czyni zadanie praktycznie niemożliwym do wykonania w rozsądnym czasie bez pomocy narzędzi automatyzujących ten proces.

Chcąc z pliku konfiguracyjnego wyekstrahować te fragmenty konfiguracji, które odnoszą się do badanej w ramach audytu funkcjonalności (na przykład bezpieczeństwa, routingu, jakości usług itp.), możemy posłużyć się różnymi narzędziami, spośród których ‚grep’ z zastosowaniem wyrażeń regularnych wydaje się być najprostszy, ale bynajmniej nie najlepszy. Grep pozwala na przetwarzanie pliku wiersz po wierszu, a to czasem nie wystarcza. Nie wystarcza mianowicie wtedy, gdy wymagana jest implementacja jakiejś logiki przetwarzania, a nie tylko proste wyszukiwanie informacji. Nie wystarcza także wtedy, gdy informacje trzeba przetwarzać blokami, a nie wierszami.

Dziś chciałbym skupić się na przykładach narzędzi do blokowego przetwarzania konfiguracji urządzeń sieciowych Cisco, tworzonych samodzielnie w oparciu o programowanie skryptowe w języku Python.

Będzie nam potrzebna biblioteka ‚ciscoconfparse’, więc należy ja zainstalować przy pomocy wykorzystywanego managera pakietów, na przykład:

pip install ciscoconfparse

Biblioteka implementuje klasę IOSCfgLine pozwalającą na tworzenie obiektów do hierarchicznego, blokowego przetwarzania plików konfiguracyjnych urządzeń z systemem operacyjnym Cisco IOS. Obiekty klasy IOSCfgLine po inicjalizacji pamiętają źródłowy plik konfiguracyjny oraz polecenia globalnego trybu konfiguracyjnego i poszczególnych podpoziomów konfiguracji. Na przykład:

policy-map QOS_1         <-- poziom globalny (rodzic 0)
 class GOLD              <-- pierwszy podpoziom (potomek I, rodzic dla potomka II)
  priority percent 10    <-- drugi podpoziom (potomek II)

Zaczynamy od przeczytania pliku konfiguracyjnego i inicjalizacji obiektów do przetwarzania konfiguracji:

parse = CiscoConfParse('cisco.conf')

Potem identyfikujemy określone obiekty globalnego trybu konfiguracyjnego, na przykład wszystkie interfejsy:

intf_object = parse.find_objects(r'^interface')

Posługujemy się w tym celu, jak widać, wyrażeniami regularnymi, jako parametrami metody find_objects().

W efekcie otrzymujemy listę wszystkich interfejsów urządzenia, którą możemy wyświetlić poleceniem:

for elem in intf_object:
    print elem.text

Potem można poszukać na przykład wszystkich interfejsów z przypisanymi adresami IP i bez adresacji IP.

# interfejsy bez adresów IP
for int in intf_object:
    if int.re_search_children(r'no\sip\s\address'):
        print int.text

# interfejsy z adresami IP
for int in intf_object:
    if not int.re_search_children(r'no\sip\s\address'):
        print int.text

Można to samo zrobić nawet prościej:

# interfejsy bez adresów IP
no_ip_intfs = parse.find_objects_w_child(parentspec=r"^interf", childspec=r"^no\sip\saddress")
# interfejsy z adresami IP
ip_interfs = parse.find_objects_wo_child(parentspec=r"^interf", childspec=r"^no\sip\saddress")

Przejdźmy teraz do przykładowego audytu konfiguracji jakości usług (Quality of Service).

Oto fragment przykładowego pliku konfiguracyjnego, zawierający informacje istotne z punktu widzenia polityk QoS, bo ten temat będziemy na potrzeby przykładu badać.

policy-map QOS_1
 class GOLD
  priority percent 10
 class SILVER
  bandwidth 30
  random-detect
 class default
!
policy-map QOS_2
 class PLATINUM
  priority percent 30
 class DIAMOND
  bandwidth 45
  random-detect
 class default 
!
policy-map type loadbalance first-match LOAD_BALANCE
 class LB_CLASS
  serverfarm SF1
!
interface Ethernet0/0
 ip address 1.1.2.1 255.255.255.0
 no cdp enable
!
interface VLAN1
 ip address 10.1.1.1 255.255.255.0
 service-policy output LOAD_BALANCE
!
interface Serial1/0
 encapsulation ppp
 ip address 1.1.1.1 255.255.255.252
 service-policy output QOS_2
 service-policy input QOS_1
!
interface Serial1/1
 encapsulation ppp
 ip address 1.1.1.5 255.255.255.252
 service-policy output QOS_1
!
interface Serial1/2
 encapsulation hdlc
 ip address 1.1.1.9 255.255.255.252
!
class-map GOLD
 match access-group 102
class-map SILVER
 match protocol tcp
class-map PLATINUM
 match access-group 103
class-map DIAMOND
 match protocol udp
class-map type http loadbalance match-any LB_CLASS
 match http url /foo
 match http url /bar
 match access-group in_to_out
!
access-list 102 permit tcp host 10.1.1.2 host 10.2.1.1
access-list 102 permit ip any 10.240.1.1 0.0.255.255
!
access-list 103 permit tcp any any eq 22
access-list 103 permit tcp any host 10.34.1.101 eq 443
!
ip access-list extended in_to_out 
 permit tcp host 10.1.1.2 host 172.16.1.1 eq www 
 permit tcp host 10.1.1.2 host 172.16.1.1 eq 443

Oto przykład skryptu do audytu konfiguracji QoS:

# -*- coding: utf-8 -*-
from ciscoconfparse import CiscoConfParse
from optparse import OptionParser
import re, os.path, sys

if __name__ == "__main__":
    CONFIG_INFILE = 'cisco.conf'
        
    usage = u"""
   ____ _                                  __ _       
  / ___(_)___  ___ ___     ___ ___  _ __  / _(_) __ _ 
 | |   | / __|/ __/ _ \   / __/ _ \| '_ \| |_| |/ _` |
 | |___| \__ \ (_| (_) | | (_| (_) | | | |  _| | (_| |
  \____|_|___/\___\___/   \___\___/|_| |_|_| |_|\__, |
                                                 |___/
 ==== Quality of Service configuration audit tool ====
                                   Janusz Nawrat (2015) 
    """
    parser = OptionParser(usage=usage)
    
    parser.add_option('-i', '--input_file', type='string',
                      help='input config file (default: cisco.conf)',
                      dest='infile', default="cisco.conf")
    
    options, args = parser.parse_args()

    if options.infile:
        CONFIG_INFILE = options.infile
        
        if not os.path.isfile(CONFIG_INFILE):
            print usage
            print >> sys.stderr, "FATAL ERROR: %s doesn't exist" % CONFIG_INFILE
            sys.exit(1)
    
    # parser.print_help()
    print usage

    parse = CiscoConfParse(CONFIG_INFILE)
    class_map_object = parse.find_objects(r'^class-map')
    policy_map_object = parse.find_objects(r'^policy-map')
    
    print '{:-^56}'.format(" CLASS MAP ")
    print r'''| You can classify inbound network traffic destined    |
| to or passing through,the ACE based on a series of   |
| flow match criteria specified by a class map.        |
| Each class map defines a traffic classification:     |
| network traffic that is of interest to you.          |
| Policy map defines a series of actions (functions)   |
| that you want applied to a set of classified inbound |
| traffic.                                             |
| Creating a class map by using the class-map command  |
| and the associated match commands, which comprise    |
| a set of match criteria related to Layer 3 and Layer |
| 4 traffic classifications or Layer 7 protocol        |
| classifications allows you to distinguish varous     |
| traffic categories for QoS purposes.                 |
--------------------------------------------------------'''
    acls = []
    for map in class_map_object:
        print map.text
        map_child = map.re_search_children(r"^.*$")
        if map_child:
            for child in map_child:
                print child.text
                if 'access-group' in child.text:
                    matchObj = re.search( r'access-group (\S+)', child.text, re.M|re.I)
                    if matchObj:
                        acl = matchObj.group(1)
                        acls.append(acl)
    if len(acls):
        print '{:-^56}'.format(" ACCESS LISTS involved as a traffic class selectors ")
        for acl_item in acls:
            acl_object = parse.find_objects(r'^access-list %s' % acl_item)
            for acl_entry in acl_object:
                print acl_entry.text
            named_acl_object = parse.find_objects(r'^ip access-list extended %s' % acl_item)
            for acl_entry in named_acl_object:
                print acl_entry.text
                named_acl_child = acl_entry.re_search_children(r"^.*$")
                if named_acl_child:
                    for entry in named_acl_child:
                        print entry.text
    
    print '{:-^56}'.format(" POLICY MAP ")
    print '''| The policy-map command creates the traffic policy.   | 
| The purpose of a traffic policy is to implement      |
| specific ACE functions associated with a traffic     |
| class. A traffic policy contains the following       |
| components:                                          |
|   - Policy map name                                  |
|   - Previously created traffic class map or,         |
|     optionally, the class-default class map          |
|   - One or more of the individual Layer 3 and Layer 4| 
|     or Layer 7 policies that specify the actions     |
|     (functions) to be performed by the ACE           |
--------------------------------------------------------'''
    for polic in policy_map_object:
        print polic.text
        polic_child = polic.re_search_children(r"^.*$")
        if polic_child:
            for polic in polic_child:
                print polic.text
                subchild = polic.re_search_children(r"^.*$")
                if subchild:
                    for sub in subchild:
                        print sub.text 

    qos_intfs = parse.find_objects_w_child(parentspec=r"^interf", childspec=r"service-policy")

    print '{:-^56}'.format(" Interfaces with QoS policy applied ")

    for intf in qos_intfs:
        print intf.text
        for item in intf.re_search_children(r"service-policy"):
            print item.text

    print '{:-^56}'.format("-")        

Efekt działania skryptu po przetworzeniu danych zawartych w przykładowym pliku konfiguracyjnym wygląda tak:

$ python cisco_config_audit.py -i cisco.conf
   ____ _                                  __ _
  / ___(_)___  ___ ___     ___ ___  _ __  / _(_) __ _
 | |   | / __|/ __/ _ \   / __/ _ \| '_ \| |_| |/ _` |
 | |___| \__ \ (_| (_) | | (_| (_) | | | |  _| | (_| |
  \____|_|___/\___\___/   \___\___/|_| |_|_| |_|\__, |
                                                 |___/
 ==== Quality of Service configuration audit tool ====
                                   Janusz Nawrat (2015)
								   
---------------------- CLASS MAP -----------------------
| You can classify inbound network traffic destined    |
| to or passing through,the ACE based on a series of   |
| flow match criteria specified by a class map.        |
| Each class map defines a traffic classification:     |
| network traffic that is of interest to you.          |
| Policy map defines a series of actions (functions)   |
| that you want applied to a set of classified inbound |
| traffic.                                             |
| Creating a class map by using the class-map command  |
| and the associated match commands, which comprise    |
| a set of match criteria related to Layer 3 and Layer |
| 4 traffic classifications or Layer 7 protocol        |
| classifications allows you to distinguish varous     |
| traffic categories for QoS purposes.                 |
--------------------------------------------------------
class-map GOLD
 match access-group 102
class-map SILVER
 match protocol tcp
class-map PLATINUM
 match access-group 103
class-map DIAMOND
 match protocol udp
class-map type http loadbalance match-any LB_CLASS
 match http url /foo
 match http url /bar
 match access-group in_to_out
-- ACCESS LISTS involved as a traffic class selectors --
access-list 102 permit tcp host 10.1.1.2 host 10.2.1.1
access-list 102 permit ip any 10.240.1.1 0.0.255.255
access-list 103 permit tcp any any eq 22
access-list 103 permit tcp any host 10.34.1.101 eq 443
ip access-list extended in_to_out
 permit tcp host 10.1.1.2 host 172.16.1.1 eq www
 permit tcp host 10.1.1.2 host 172.16.1.1 eq 443
---------------------- POLICY MAP ----------------------
| The policy-map command creates the traffic policy.   |
| The purpose of a traffic policy is to implement      |
| specific ACE functions associated with a traffic     |
| class. A traffic policy contains the following       |
| components:                                          |
|   - Policy map name                                  |
|   - Previously created traffic class map or,         |
|     optionally, the class-default class map          |
|   - One or more of the individual Layer 3 and Layer 4|
|     or Layer 7 policies that specify the actions     |
|     (functions) to be performed by the ACE           |
--------------------------------------------------------
policy-map QOS_1
 class GOLD
  priority percent 10
 class SILVER
  bandwidth 30
  random-detect
 class default
policy-map QOS_2
 class PLATINUM
  priority percent 30
 class DIAMOND
  bandwidth 45
  random-detect
 class default
policy-map type loadbalance first-match LOAD_BALANCE
 class LB_CLASS
  serverfarm SF1
---------- Interfaces with QoS policy applied ----------
interface VLAN1
 service-policy output LOAD_BALANCE
interface Serial1/0
 service-policy output QOS_2
 service-policy input QOS_1
interface Serial1/1
 service-policy output QOS_1
--------------------------------------------------------

Dalsze doskonalenie skryptu może pójść w kierunku:

  • Zapisywania wyników audytu do bazy SQL.
  • Parametryzacji skryptu w celu określenia rodzaju informacji, które możemy poddać audytowi, a tym samym uczynienia go narzędziem bardziej uniwersalnym w porównaniu z zaprezentowanym przykładem.
  • Poprawiania błędów konfiguracyjnych.

W jednym z kolejnych artykułów napiszę o generowaniu plików konfiguracyjnych na podstawie zdefiniowanych wzorców konfiguracji.

Informacje Janusz Nawrat
Just ordinary man who likes thinking...

One Response to Audyt konfiguracji urządzeń sieciowych z systemem Cisco IOS – narzędzia skryptowe

  1. Pingback: Standaryzacja konfiguracji urządzeń sieciowych Cisco – narzędzia skryptowe | TECH&DEV&SEC - technology, development & security

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s

TOMASZ WEŁNA

artysta grafik | wykładowca

PRACOWNIA OKO

Szkoła Rysunku Malarstwa i Grafiki DR TOMASZA WEŁNY | KRAKÓW | Plac Matejki 10 | tel 691 81 75 74

Piękno neurobiologii

Blog Jerzego Vetulaniego

Teoria muzyki, zasady muzyki, podstawy muzyki

Teoria muzyki, zasady muzyki, podstawy muzyki - czyli to co każdy amator muzyki wiedzieć powinien :)

Personal Development & Inspirations

Przemyślenia i refleksje, którymi warto się podzielić (blog by Janusz Nawrat)

Business IT Cooperation Platform

Biznes i IT - dwa światy, które muszą współdziałać

%d bloggers like this: