Więcej

    Pierwsze kroki w automatyzacji sieci – Python i pexpect()

    W poprzednim artykule przybliżyłem wszystkie elementy, które w mojej opinii są potrzebne do zbudowania pełnego zestawu umiejętności NetDevOps’a. Czas przyjrzeć się bliżej poszczególnym technologiom wylistowanym we wspomnianym materiale. W dzisiejszym artykule porozmawiamy o Pythonie oraz przedstawię Ci pierwszy prosty skrypt, który będziesz w stanie wykorzystać w swojej sieci w ciągu zaledwie kilku minut. Zaczynajmy!

    👉 Po co w sumie ten Python?

    Na wstępie wyjaśnijmy sobie jedną kluczową kwestię – aby być dobrym w automatyzowaniu swojej pracy jako sieciowiec musisz się nauczyć programować chociażby w podstawowym stopniu. Ale nie znaczy to, że koniecznie musisz programować w Pythonie! Jeżeli znasz już jakiś inny język programowania, którego użytkowanie sprawia Ci przyjemność to mam dla Ciebie dobrą wiadomość – istnieje spora szansa, że z powodzeniem będziesz w stanie go wykorzystać do automatyzowania sieci. 

    Dlaczego jednak większość sieciowców ma takie ciśnienie na programowanie właśnie w Pythonie? Powody są dwa:

    • Python jest bardzo prostym składniowo językiem i wyróżnia się dobrą czytelnością kodu, co ma duże znaczenie podczas korzystania ze skryptów autorstwa innych osób. Analiza kodu napisanego w C++ przez nieznajomą nam osobę może zająć sporo czasu (zakładając brak komentarzy w kodzie). Python dzięki swojej czytelności trochę nam ułatwia w takich przypadkach zrozumienie kodu,
    • Python jest już z nami dość długo i powstała do niego ogromna liczba zewnętrznych bibliotek, które dają nam do dyspozycji wiele użytecznych funkcji. Sprawia to, że bardzo często kod potrzebny do wykonania pewnego zadania na danym urządzeniu sieciowym już istnieje. Daje to nam przede wszystkim oszczędność czasu i umożliwia korzystanie z już zoptymalizowanych pod kątem działania funkcji. Wiele najlepszych bibliotek do programowania sieciowego jest dostępne właśnie w Pythonie.

    Ponadto, jak słusznie zauważył Rafał w komentarzach pod artykułem, kod Pythona jest wykonywany przez interpreter co powoduje, że działa on niezależnie od systemu operacyjnego (nie musi być ponadto kompilowany, w przeciwieństwie do np. C++). W dodatku fakt, że kod jest zapisywany w plikach tekstowych ułatwia jego przenoszenie i późniejszą edycję. 

    No dobra, czyli już wiemy, że uczenie się Pythona to nie jakieś tam „widzimisię”. Ale jak się nauczyć Pythona?

    👉 Jak się nauczyć Pythona?

    Od razu przyznaję bez bicia, że nie jestem ekspertem w dziedzinie programowania. Idąc na studia informatyczne miałem intencję zostania programistą, ale życie potoczyło się inaczej (jeśli jesteś ciekawy jak, to opisałem to w osobnym artykule). Zostałem sieciowcem, ale podstawowe umiejętności programistyczne w C++ gdzieś się ostały, co zdecydowanie ułatwia mi naukę pisania w Pythonie. Najważniejsze to zdawać sobie sprawę z tego, że nie musisz być programistyczną Alfą i Omegą. Według mnie wystarczy sam zapał do nauki, umiejętność analitycznego myślenia i doświadczenie w obsługiwaniu Google’a. Ale oczywiście doświadczenie z programowaniem jest zawsze w cenie.

    Cała wiedza, którą posiadam odnośnie programowania w Pythonie pochodzi z jednego kursu na Udemy (który mogę zdecydowanie polecić). Jeśli chciałbyś się mu przyjrzeć to do niego linkuję:

    Kurs Udemy – Python 3 Network Programming

    Poza samym kursem dużo się również idzie nauczyć samodzielnie analizująć znalezione w sieci skrypty. Nie wykluczam, że w przyszłości zgłębię bardziej Pythona i sięgnę po bardziej ustrukturyzowane źródła wiedzy (np. książki) ale póki co nie miałem takiej potrzeby. W tym miejscu mam do Ciebie prośbę – jeżeli znasz inne godne polecenia źródła dzięki którym dobrze się można nauczyć Pythona to podziel się swoją wiedzą w komentarzu pod artykułem. Ja i inni czytelnicy na pewno będą Ci wdzięczni 🙂 Z dodatkowych źródeł możesz zwrócić uwagę np na:

    • Codecamy – polecony przez Rafała Rudewicza
    • Książka „Python dla każdego. Podstawy programowania” – polecona przez Krzysztofa Mroczka

    👉 Czas na pierwszy skrypt – use-case

    Wiemy już po co nam Python i gdzie się go nauczyć. Przyjrzyjmy się zatem pierwszemu dość prostemu problemowi, który możemy dzięki Pythonowi rozwiązać.

    Topologia, na której będzie oparty przykład wygląda następująco:

    Sieć jest oczywiście celowo uproszczona żeby nie komplikować niepotrzebnie tematu. Mamy tu do czynienia z płaską siecią LAN spiętą pojedynczym przełącznikiem warstwy trzeciej. Do przełącznika mamy podłączony komputer Admina zaadresowany w dedykowanej sieci dla administratorów – 10.1.0.0/24. Ponadto jest podłączony jeden komputer recepcji zaadresowany w sieci dla użytkowników 10.2.0.0/24. W ostatniej, trzeciej sieci 10.3.0.0/24 mamy zaadresowany Linux Server, na którym będziemy programować, SMTP Server na potrzeby wysyłania maili oraz WLAN Controller (WLC), który zarządza Access Pointami w naszej przykładowej organizacji.

    Problem jaki przed nami stoi jest następujący: firmie nie zależy na stworzeniu wyrafinowanego rozwiązania Guest WiFi (które notabene zostało opisane przez Łukasza w dedykowanym artykule). Zamiast tego sieć Wi-Fi dla gości jest zabezpieczona zwykłym 10-znakowym hasłem (czyli użyto zabezpieczenie L2 Security typu PSK – pre-shared key). Naszym przełożonym nie podoba się fakt, że hasło do naszej sieci dla gości bardzo szybko się rozchodzi na portalach war-driving’owych i do naszej sieci dla gości podłączają się ludzie wątpliwej reputacji. Dotychczas więc hasło zmieniano ręcznie co miesiąc za pośrednictwem GUI kontrolera WLC:

    Zmiana PSK w ustawieniach SSID na WLC

    Jest to oczywiście bardzo proste i mało czasochłonne zadanie, ale jednak… należy o nim co miesiąc pamiętać. Zadanie wręcz idealne do zautomatyzowania.

    Dochodzimy tutaj do bardzo istotnego faktu – WLC Cisco 5508, które posiada firma nie posiada API, czyli interfejsu programistycznego, który pozwalałby nam na bardzo wygodną interakcję między skryptem a kontrolerem. Na API przyjdzie jeszcze naszej nauce czas. W naszym scenariuszu natomiast będziemy musieli zastosować znacznie bardziej „łopatologiczne” podejście (wymuszone właśnie brakiem API). Jak będzie miał działać skrypt?

    Zadaniem skryptu będzie:

    • zestawienie sesji SSH z kontrolerem,
    • wygenerowanie w sposób losowy nowego hasła,
    • przesłanie do kontrolera komend, które zmienią dotychczasowe hasło sieci Guest Wi-Fi
    • wysłanie do recepcji maila z informacją o nowym haśle

    Chcemy aby taki skrypt wykonywał się automatycznie pierwszego dnia każdego miesiąca w nocy, 5 minut po północy. Do roboty!

    👉 Pisanie skryptu

    Zaczynamy od przygotowania sobie środowiska. Z komputera Admina (10.1.0.10/24) logujemy się za pomocą SSH na nasz Linux Server, który będziemy wykorzystywali do dalszego skryptowania. Logowanie do serwera jest oczywiście należycie zabezpieczone, abyśmy tylko my mieli do niego dostęp.

    1. Instalujemy Pythona (yum lub apt-get):

    sudo apt-get install python3

    2. Tworzymy i przechodzimy do katalogu roboczego dla skryptów:

    mkdir /etc/scriptscd /etc/scripts

    3. Tworzymy plik skryptu z rozszerzeniem .py, nadajemy mu uprawnienia, które pozwolą jedynie bieżącemu użytkownikowi na jakąkolwiek interakcję z tym plikiem i przechodzimy do edycji (używając nano, nie chcemy się już na wstępie zniechęcić więc unikamy edytora vi 😉 ):

    touch guestpass.py
    chmod 700 guestpass.py
    nano guestpass.py

    4. W pliku ze skryptem wklejamy poniższy kod. Podaję go w całości – jeśli chcesz się zapoznać z wyjaśnieniami poszczególnych elementów to opisuję je w dalszej części artykułu:

    #!/usr/bin/env python3

    import random
    import os
    import pexpect
    import time
    import sys
    import socket
    import subprocess

    alphabet = "abcdefghjkmnpqrstuvwxyz"
    upperalphabet = alphabet.upper()
    pw_len = 10
    pwlist = []

    for i in range(pw_len//3):
        pwlist.append(alphabet[random.randrange(len(alphabet))])
        pwlist.append(upperalphabet[random.randrange(len(upperalphabet))])
        pwlist.append(str(random.randrange(10)))
    for i in range(pw_len-len(pwlist)):
        pwlist.append(alphabet[random.randrange(len(alphabet))])

    random.shuffle(pwlist)
    pwstring = "".join(pwlist)

    ssh = "ssh 10.3.0.33"
    newpass = "config wlan security wpa akm psk set-key ascii " + pwstring + "2"

    c1=pexpect.spawn(ssh)
    c1.delaybeforesend = 2.0
    c1.expect("User:")
    c1.sendline("admin")
    c1.expect("assword:")
    c1.sendline("SuperSecureAdminPassword")
    c1.expect(">")
    c1.sendline("config wlan disable 2")
    c1.expect(">")
    c1.sendline(newpass)
    c1.expect(">")
    c1.sendline("config wlan enable 2")
    c1.expect(">")
    c1.sendline("logoutr")
    c1.expect("(y/N)")
    c1.sendline("yr")
    c1.close()

    text_file = open("CurrentGuestPass.txt", "w")
    text_file.write("Hello. Please be informed that Guest Wi-Fi password for has changed. New password is: %snnPlease distribute the password to all whom it may concern and remember that in some cases the previous Wi-Fi connection profile must first be removed in order to get a prompt for a new password." % pwstring)
    text_file.close()

    os.system("mail -s 'IMPORTANT! Guest Wi-Fi password has changed!' reception@acme.com< /etc/scripts/CurrentGuestPass.txt")

    👉 Analiza kodu

    Przyjrzyjmy się teraz bliżej poszczególnym blokom kodu:

    1. Kod zaczyna się od linijki, która wskazuje jakiego interpretera kodu chcemy użyć podczas odpalania programu. Piszemy w Pythonie więc wskazujemy sztywno na Pythona:

    #!/usr/bin/env python3

    2. Importujemy biblioteki, które będą używane w naszym kodzie. Najważniejsze z nich to random, który będziemy używać do generowania nowego hasła, os do interakcji z powłoką systemową Unixa oraz pexpect do zestawiania połączenia z kontrolerem:

    import random
    import os
    import pexpect
    import time
    import sys
    import socket
    import subprocess

    3. Definiujemy alfabet, który będzie używany do generowania losowego hasła oraz określamy długość generowanego ciągu znakowego na 10 znaków. Do przechowywania hasła będziemy używali tablicę pwlist:

    alphabet = "abcdefghjkmnpqrstuvwxyz"
    upperalphabet = alphabet.upper()
    pw_len = 10
    pwlist = []

    4. Pętle for odpowiedzialne za generowanie nowego hasła. Nie będziemy ich tutaj dokładnie opisywali natomiast zachęcam do samodzielnej analizy tych pętli w celu zrozumienia ich mechaniki. Wygenerowane hasło ląduje w zmiennej pwstring:

    for i in range(pw_len//3):
    pwlist.append(alphabet[random.randrange(len(alphabet))])
    pwlist.append(upperalphabet[random.randrange(len(upperalphabet))])
    pwlist.append(str(random.randrange(10)))
    for i in range(pw_len-len(pwlist)):
    pwlist.append(alphabet[random.randrange(len(alphabet))])
    random.shuffle(pwlist)
    pwstring = "".join(pwlist)

    5. Definicja zmiennej ssh zawierającej komendę do połączenia się z kontrolerem:

    ssh = "ssh 10.3.0.33"

    6. Definicja zmiennej newpass zawierającej komendę CLI dla kontrolera, która zmieni PSK dla wskazanego SSID na wygenerowane przez nas nowe hasło. Zwróć uwagę na to, że musisz znać numer SSID, dla którego zmieniasz hasło. Numer ten możesz sprawdzić w GUI kontrolera Cisco – sekcja WLANs, kolumna WLAN ID:

    newpass = "config wlan security wpa akm psk set-key ascii " + pwstring + "2"

    7. Wykorzystanie funkcji pexpect() do zestawienia połączenia z kontrolerem. Ustawiamy dwusekundowe opóźnienie dla wysyłania komend aby zrekompensować ewentualne spadki w prędkości połączenia. Zwróć uwagę, że podajemy tutaj cleartextem dane logowania do kontrolera. Dlatego też bardzo istotne jest zapewnienie bezpieczeństwa serwera Linux oraz samego skryptu:

    c1=pexpect.spawn(ssh)
    c1.delaybeforesend = 2.0
    c1.expect("User:")
    c1.sendline("admin")
    c1.expect("assword:")
    c1.sendline("SuperSecureAdminPassword")

    8. Tak jak wskazuje sama nazwa biblioteki, pexpect działa na zasadzie oczekiwania na konkretny prompt. Mówimy skryptowi czego ma oczekiwać – jeśli skrypt widzi dany output w ostatniej linijce na zalogowanym urządzeniu to przechodzi dalej wysyłając za pomocą metody sendline następną komendę. Przed zmianą hasła wyłączamy SSID:

    c1.expect(">")
    c1.sendline("config wlan disable 2")
    c1.expect(">")
    c1.sendline(newpass)

    9. Włączamy SSID z powrotem po zmianie hasła:

    c1.expect(">")
    c1.sendline("config wlan enable 2")

    10. Wylogowujemy się i zamykamy sesję:

    c1.expect(">")
    c1.sendline("logoutr")
    c1.expect("(y/N)")
    c1.sendline("yr")
    c1.close()

    11. Hasło zostało zmienione. Teraz czas zadbać o powiadomienie recepcji o nowym haśle. W tym celu zapisujemy do pliku tekstowego treść wiadomości, którą będziemy wysyłać:

    text_file = open("CurrentGuestPass.txt", "w")
    text_file.write("Hello. Please be informed that Guest Wi-Fi password for has changed. New password is: %snnPlease distribute the password to all whom it may concern and remember that in some cases the previous Wi-Fi connection profile must first be removed in order to get a prompt for a new password." % pwstring)
    text_file.close()

    12. Tak przygotowany plik tekstowy następnie wysyłamy przy pomocy bashowej komendy mail. Definiujemy temat wiadomości i odbiorców, a jako treść podajemy zawartość przygotowanego pliku tekstowego:

    os.system("mail -s 'IMPORTANT! Guest Wi-Fi password has changed!' reception@acme.com< /etc/scripts/CurrentGuestPass.txt")

    Uff, było tego sporo, nieprawdaż? Nie wgłębiłem się w komentarzach powyżej zanadto w to co robią poszczególne linijki. Skupiłem się raczej na tym by opisać poszczególne bloki kodu w taki sposób, abyś zrozumiał przebieg skryptu. W celu pełnego zrozumienia komend powyżej odsyłam do wspomnianego wcześniej kursu i samodzielnej nauki Pythona.

    Na koniec został nam jeszcze jeden krok – edycja crontaba w taki sposób, aby skrypt się uruchamiał samodzielnie pierwszego dnia każdego miesiąca o godzinie 00:05:

    crontab -e
    00 05 * * 1 cd /etc/scripts && /etc/scripts/guestpass.py
    :wq!

    To by było na tyle! Możesz zapomnieć o ręcznym zmienianiu hasła dla sieci Guest Wi-Fi!

    Mamy za sobą napisanie pierwszego skryptu w Pythonie. Jeśli zainteresował Cię ten temat to nie zatrzymuj się i zacznij naukę Pythona już dziś. Umiejętność ta przyda Ci się nie tylko do pisania takich prostych skryptów wykorzystujących pexpect(), ale również przy bardziej wyrafinowanych skryptach wykorzystujących API.

    A Ty, jakie materiały poleciłbyś do nauki programowania w Pythonie?

    🗳 Jak przydatna była ta publikacja?

    Średnia ocena 4.9 / 5. Ilość głosów: 17

    Brak ocen. Bądź pierwszy!

    Dziękujemy za ocenę! Zapraszamy Cię do obserwowania NSS w mediach społecznościowych!

    Przykro nam, że ta publikacja okazała się być dla Ciebie nieprzydatna!

    Uwaga: Twój głos będzie liczony tylko jeśli udzielisz feedbacku używając formularza poniżej.

    Jak możemy poprawić tę publikację?

    Damian Michalak
    Network Consultant, Twórca Na Styku Sieci

    9 KOMENTARZE

    guest
    9 - Ilość komentarzy
    Sortuj wg najstarszych
    Sortuj wg najnowszych Sortuj wg najlepszych
    Inline Feedbacks
    View all comments
    Rafał Rudewicz

    Python poprzez swoją czytelność i budowę języka bardzo zbliżoną do naszej naturalnej mowy zdecydowanie ułatwia debugowanie oraz późniejszą modyfikację kodu. Muszę tylko zwrocić Ci uwagę, że wskazany przez Ciebie shebang odwołuje się do wersji 2, a nie do 3 jak podałeś podczas instalacji (python3 jest prawidłowo) oraz nie nie zawsze jest taki sam (zależy od dystrybucji).

    Ze swojej strony polecamy codecamy do nauki Pythona.

    Rafał Rudewicz

    Proszę bardzo, choć nawet najlepszy kurs nie zastąpi samodzielnych projektów. Dla mnie osobiście najlepszą formą nauki była automatyzacja/pisanie skryptów które przyspieszały moją pracę. W końcu najlepszy inżynier to leniwy inżynier 😉
    Co do $path to miami by to sens gdybyś miał pythona zainstalowanego w innym katalogu i bodajże jest zmienna środowiskowa do tego $pythonpath. Można by w sumie też zapisać skrypt z rozszerzeniem pytanie i też powinno działać bez shebang.

    W akapicie o tym dlaczego python, warto również wspomnieć, że jest on wykonywany przez interpreter czyli działa niezależnie od systemu operacyjnego oraz skrypty są zapisywane w formie pliku tekstowego, co znacząco ułatwia ich przenoszenie i późniejsza edycję.

    Krzysiek Mroczko

    Dziękuje za artykuł. Ja zacząłem się uczyć z książki \”Python dla każdego. Podstawy programowania\” – Michael Dawson i śmiało mogę polecić. Nauka na przykładach, czyli najlepszy dla mnie sposób.

    Krzysiek Mroczko

    Przepraszam za offtopic, ale natrafiłem ostatnio na książkę \”101 zabezpieczeń przed atakami w sieci komputerowej\”, czy mieliście okazję się z nią zapoznać? Porusza dość ciekawe tematy, jednak jest już dość leciwa (2005 r.) jak na tempo rozwoju sieci i nie wiem czy jest sens ją czytać. A może ktoś poleci coś podobnego?

    Łukasz Sędek

    Dodałbym od siebie tworzenie venv/wirtualnego środowiska pythona. Korzystanie z bibliotek systemowych prędzej czy później kończy się bałaganem. Do tego – automatyzacja to kod. Kod to programowanie. Najlepsza nauka programowania to po prostu pisanie kodu. Jak najwięcej.

    Marcin Kita

    Też nigdy nie byłem fanem programowania, ale nadchodzą takie czasy, że niedługo bez tych skilli będzie ciężko. Ja zaczynalem od LPTHW (Learn Python The Hard Way). Jeśli chodzi o automatyzację CLI to nie ma chyba nic bardziej dojrzałego niż netmiko. Sam większość swoich projektów opieram właśnie o tą bibliotekę. Warto też zapoznać się z NAPALMem, który jest vendor neutral i zawsze dostaniemy z niego ustrukturyzowane dane. Jeśli chodzi o API to wszystko i jeszcze więcej można zrobić za pomocą biblioteki requests.

    Przygotowujesz się do certyfikacji CCNA?

    Zapisz się na nasz NSSletter, a co tydzień we wtorek rano otrzymasz porcję sieciowej wiedzy oraz porady dotyczące certyfikacji.

    Uzupełniając powyższe pole wyrażasz zgodę na otrzymywanie od GetGoodNet Damian Michalak z siedzibą we Wrocławiu newslettera zawierającego treści edukacyjne. Zgodę możesz wycofać w każdym czasie.

    NSS na Social Media

    1,611FaniLubię
    72ObserwującyObserwuj
    133ObserwującyObserwuj
    1,220SubskrybującySubskrybuj

    Najnowsze artykuły

    spot_img

    Może Cię też zainteresować...

    9
    0
    Co sądzisz na temat tej publikacji? Zostaw proszę komentarzx
    ()
    x