Ukukhiqiza okuzenzakalelayo kanye nokugcwaliswa kwezinto zokucushwa kwedivayisi yenethiwekhi kusetshenziswa i-Nornir

Ukukhiqiza okuzenzakalelayo kanye nokugcwaliswa kwezinto zokucushwa kwedivayisi yenethiwekhi kusetshenziswa i-Nornir

Sawubona Habr!

Muva nje kuvele isihloko lapha I-Mikrotik ne-Linux. Umjikelezo kanye ne-automation lapho inkinga efanayo yaxazululwa kusetshenziswa izindlela zamathambo. Futhi nakuba umsebenzi ujwayelekile ngokuphelele, akukho okufanayo ngawo ku-Habré. Ngiyalokotha nginikele ngebhayisikili lami emphakathini ohlonishwayo we-IT.

Leli akulona ibhayisikili lokuqala lomsebenzi onjalo. Inketho yokuqala yasetshenziswa eminyakeni embalwa edlule emuva ansible inguqulo 1.x.x. Ibhayisikili lalingavamile ukusetshenziswa ngakho-ke lihlala ligqwalile. Ngomqondo wokuthi umsebenzi ngokwawo awuveli njalo lapho izinguqulo zibuyekezwa ansible. Futhi njalo uma udinga ukushayela, iketango liyawa noma isondo liyawa. Kodwa-ke, ingxenye yokuqala, ekhiqiza ama-configs, ihlala isebenza ngokucacile, ngenhlanhla ijinja2 Injini isinesikhathi eside yasungulwa. Kepha ingxenye yesibili - ukukhishwa kwe-configs - imvamisa iletha izimanga. Futhi njengoba kufanele ngikhiphe ukulungiselelwa ukude kumadivayisi ayingxenye yekhulu, amanye awo atholakala endaweni eqhele ngezinkulungwane zamakhilomitha, ukusebenzisa leli thuluzi bekuyisicefe kancane.

Lapha kufanele ngivume ukuthi ukungaqiniseki kwami ​​​​okungenzeka kulele ekungazazini kwami ansiblekunasekushiyekeni kwayo. Futhi lokhu, ngendlela, kuyiphuzu elibalulekile. ansible ihluke ngokuphelele, indawo yayo yolwazi ene-DSL yayo (Ulimi Olukhethekile Lwesizinda), okufanele lugcinwe ezingeni lokuzethemba. Awu, ngaleso sikhathi ansible Ikhula ngokushesha, futhi ngaphandle kokunaka okukhethekile ukuhambisana okubuyela emuva, ayifaki ukuzethemba.

Ngakho-ke, esikhathini esingengakanani edlule inguqulo yesibili yebhayisikili yasetshenziswa. Kulokhu i-python, noma kunalokho ohlakeni olubhalwe kulo i-python futhi i-python ubizile Nornir

Ngakho- Nornir i-microframework ebhalwe ngaphakathi i-python futhi i-python futhi yakhelwe ukuzishintshanisa. Okufanayo nasesimweni nge ansible, ukuxazulula izinkinga lapha, ukulungiswa kwedatha okunekhono kuyadingeka, i.e. uhlu lwababungazi nemingcele yabo, kodwa imibhalo ayibhalwanga ku-DSL ehlukile, kodwa ngendlela efanayo hhayi endala kakhulu, kodwa enhle kakhulu i-p[i|i]ton.

Ake sibheke ukuthi yini esebenzisa isibonelo esibukhoma esilandelayo.

Nginenethiwekhi yegatsha enamahhovisi amaningana ezweni lonke. Ihhovisi ngalinye linomzila we-WAN onqamula imigudu eminingana yokuxhumana evela kuma-opharetha ahlukene. Iphrothokholi yomzila yi-BGP. Amarutha e-WAN afika ngezinhlobo ezimbili: i-Cisco ISG noma iJuniper SRX.

Manje umsebenzi: udinga ukulungisa i-subnet ezinikele Yokubhekwa Kwevidiyo echwebeni elihlukile kuwo wonke amarutha e-WAN enethiwekhi yegatsha - memezela le subnet ku-BGP - lungiselela umkhawulo wesivinini wembobo ezinikele.

Okokuqala, sidinga ukulungiselela izifanekiso ezimbalwa, ngesisekelo lapho ukucushwa kuzokhiqizwa ngokwehlukana kweCisco kanye neJuniper. Kuyadingeka futhi ukulungiselela idatha yephuzu ngalinye kanye nemingcele yokuxhuma, i.e. ukuqoqa yokusungula efanayo

Isifanekiso esilungile se-Cisco:

$ cat templates/ios/base.j2 
class-map match-all VIDEO_SURV
 match access-group 111

policy-map VIDEO_SURV
 class VIDEO_SURV
    police 1500000 conform-action transmit  exceed-action drop

interface {{ host.task_data.ifname }}
  description VIDEOSURV
  ip address 10.10.{{ host.task_data.ipsuffix }}.254 255.255.255.0
  service-policy input VIDEO_SURV

router bgp {{ host.task_data.asn }}
  network 10.40.{{ host.task_data.ipsuffix }}.0 mask 255.255.255.0

access-list 11 permit 10.10.{{ host.task_data.ipsuffix }}.0 0.0.0.255
access-list 111 permit ip 10.10.{{ host.task_data.ipsuffix }}.0 0.0.0.255 any

Isifanekiso seJuniper:

$ cat templates/junos/base.j2 
set interfaces {{ host.task_data.ifname }} unit 0 description "Video surveillance"
set interfaces {{ host.task_data.ifname }} unit 0 family inet filter input limit-in
set interfaces {{ host.task_data.ifname }} unit 0 family inet address 10.10.{{ host.task_data.ipsuffix }}.254/24
set policy-options policy-statement export2bgp term 1 from route-filter 10.10.{{ host.task_data.ipsuffix }}.0/24 exact
set security zones security-zone WAN interfaces {{ host.task_data.ifname }}
set firewall policer policer-1m if-exceeding bandwidth-limit 1m
set firewall policer policer-1m if-exceeding burst-size-limit 187k
set firewall policer policer-1m then discard
set firewall policer policer-1.5m if-exceeding bandwidth-limit 1500000
set firewall policer policer-1.5m if-exceeding burst-size-limit 280k
set firewall policer policer-1.5m then discard
set firewall filter limit-in term 1 then policer policer-1.5m
set firewall filter limit-in term 1 then count limiter

Izifanekiso, vele, aziphumi emoyeni omncane. Lokhu empeleni kunomehluko phakathi kokucushwa kokusebenza obekukhona futhi obekungemuva kokuxazulula umsebenzi kumarutha amabili athile amamodeli ahlukene.

Kusuka kuzifanekiso zethu sibona ukuthi ukuxazulula inkinga, sidinga kuphela amapharamitha amabili weJuniper namapharamitha angu-3 weCisco. nazi:

  • ifname
  • isijobelelo
  • asn

Manje sidinga ukusetha le mingcele kudivayisi ngayinye, i.e. yenza okufanayo yokusungula.

Ukuze yokusungula Sizolandela ngokuqinile imibhalo Iqala u-Nornir

okungukuthi, masidale uhlaka lwamathambo lwefayela olufanayo:

.
├── config.yaml
├── inventory
│   ├── defaults.yaml
│   ├── groups.yaml
│   └── hosts.yaml

Ifayela le-config.yaml liyifayela elijwayelekile lokucushwa kwe-nornir

$ cat config.yaml 
---
core:
    num_workers: 10

inventory:
    plugin: nornir.plugins.inventory.simple.SimpleInventory
    options:
        host_file: "inventory/hosts.yaml"
        group_file: "inventory/groups.yaml"
        defaults_file: "inventory/defaults.yaml"

Sizokhombisa amapharamitha amakhulu efayelini ababungazi.yaml, iqembu (kwami ​​lawa amalogi/amaphasiwedi) ku amaqembu.yaml, futhi ngaphakathi okuzenzakalelayo.yaml Ngeke sikhombise lutho, kodwa udinga ukufaka amaminithi amathathu lapho - okubonisa ukuthi kunjalo yaml ifayela alinalutho.

Lena yindlela i-hosts.yaml ebukeka ngayo:

---
srx-test:
    hostname: srx-test
    groups: 
        - juniper
    data:
        task_data:
            ifname: fe-0/0/2
            ipsuffix: 111

cisco-test:
    hostname: cisco-test
    groups: 
        - cisco
    data:
        task_data:
            ifname: GigabitEthernet0/1/1
            ipsuffix: 222
            asn: 65111

Nawa amaqembu.yaml:

---
cisco:
    platform: ios
    username: admin1
    password: cisco1

juniper:
    platform: junos
    username: admin2
    password: juniper2

Kwenzeka lokhu yokusungula ngomsebenzi wethu. Ngesikhathi sokuqalisa, amapharamitha asuka kumafayela we-inventory afakwe imephu kumodeli yento I-InventoryElement.

Ngezansi kwe-spoiler kunomdwebo wemodeli ye-InventoryElement

print(json.dumps(InventoryElement.schema(), indent=4))
{
    "title": "InventoryElement",
    "type": "object",
    "properties": {
        "hostname": {
            "title": "Hostname",
            "type": "string"
        },
        "port": {
            "title": "Port",
            "type": "integer"
        },
        "username": {
            "title": "Username",
            "type": "string"
        },
        "password": {
            "title": "Password",
            "type": "string"
        },
        "platform": {
            "title": "Platform",
            "type": "string"
        },
        "groups": {
            "title": "Groups",
            "default": [],
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "data": {
            "title": "Data",
            "default": {},
            "type": "object"
        },
        "connection_options": {
            "title": "Connection_Options",
            "default": {},
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/ConnectionOptions"
            }
        }
    },
    "definitions": {
        "ConnectionOptions": {
            "title": "ConnectionOptions",
            "type": "object",
            "properties": {
                "hostname": {
                    "title": "Hostname",
                    "type": "string"
                },
                "port": {
                    "title": "Port",
                    "type": "integer"
                },
                "username": {
                    "title": "Username",
                    "type": "string"
                },
                "password": {
                    "title": "Password",
                    "type": "string"
                },
                "platform": {
                    "title": "Platform",
                    "type": "string"
                },
                "extras": {
                    "title": "Extras",
                    "type": "object"
                }
            }
        }
    }
}

Lo modeli ungabukeka udida kancane, ikakhulukazi ekuqaleni. Ukuze uyithole, sebenzisa imodi yokuxhumana ipython.

 $ ipython3
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.1.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from nornir import InitNornir                                                                           

In [2]: nr = InitNornir(config_file="config.yaml", dry_run=True)                                                

In [3]: nr.inventory.hosts                                                                                      
Out[3]: 
{'srx-test': Host: srx-test, 'cisco-test': Host: cisco-test}

In [4]: nr.inventory.hosts['srx-test'].data                                                                                    
Out[4]: {'task_data': {'ifname': 'fe-0/0/2', 'ipsuffix': 111}}

In [5]: nr.inventory.hosts['srx-test']['task_data']                                                     
Out[5]: {'ifname': 'fe-0/0/2', 'ipsuffix': 111}

In [6]: nr.inventory.hosts['srx-test'].platform                                                                                
Out[6]: 'junos'

Futhi ekugcineni, ake sidlulele kusikripthi ngokwaso. Akukho engingaziqhenya ngakho lapha. Ngisanda kuthatha isibonelo esenziwe ngomumo okokufundisa futhi wayisebenzisa cishe ingashintshiwe. Nansi indlela umbhalo osebenzayo oqediwe obukeka ngayo:

from nornir import InitNornir
from nornir.plugins.tasks import networking, text
from nornir.plugins.functions.text import print_title, print_result

def config_and_deploy(task):
    # Transform inventory data to configuration via a template file
    r = task.run(task=text.template_file,
                 name="Base Configuration",
                 template="base.j2",
                 path=f"templates/{task.host.platform}")

    # Save the compiled configuration into a host variable
    task.host["config"] = r.result

    # Save the compiled configuration into a file
    with open(f"configs/{task.host.hostname}", "w") as f:
        f.write(r.result)

    # Deploy that configuration to the device using NAPALM
    task.run(task=networking.napalm_configure,
             name="Loading Configuration on the device",
             replace=False,
             configuration=task.host["config"])

nr = InitNornir(config_file="config.yaml", dry_run=True) # set dry_run=False, cross your fingers and run again

# run tasks
result = nr.run(task=config_and_deploy)
print_result(result)

Naka ipharamitha dry_run=Iqiniso emgqeni wokuqalisa into nr.
Lapha kuyafana naku-in ansible kusetshenziswe ukuhlolwa lapho kuxhunywa khona umzila, kulungiselelwa ukucushwa okusha okulungisiwe, okube sekuqinisekiswa yidivayisi (kodwa lokhu akuqinisekile; kuncike ekusekelweni kwedivayisi nasekusetshenzisweni komshayeli ku-NAPALM) , kodwa ukucushwa okusha akusetshenziswanga ngokuqondile. Ukuze usebenzise ukulwa, kufanele ususe ipharamitha sula_gijima noma uguqule inani layo libe Amanga.

Uma iskripthi senziwa, uNornir ukhipha amalogi anemininingwane kukhonsoli.

Ngezansi kwe-spoiler kukhona okukhiphayo kwempi egijima kumarutha wokuhlola amabili:

config_and_deploy***************************************************************
* cisco-test ** changed : True *******************************************
vvvv config_and_deploy ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- Base Configuration ** changed : True ------------------------------------- INFO
class-map match-all VIDEO_SURV
 match access-group 111

policy-map VIDEO_SURV
 class VIDEO_SURV
    police 1500000 conform-action transmit  exceed-action drop

interface GigabitEthernet0/1/1
  description VIDEOSURV
  ip address 10.10.222.254 255.255.255.0
  service-policy input VIDEO_SURV

router bgp 65001
  network 10.10.222.0 mask 255.255.255.0

access-list 11 permit 10.10.222.0 0.0.0.255
access-list 111 permit ip 10.10.222.0 0.0.0.255 any
---- Loading Configuration on the device ** changed : True --------------------- INFO
+class-map match-all VIDEO_SURV
+ match access-group 111
+policy-map VIDEO_SURV
+ class VIDEO_SURV
+interface GigabitEthernet0/1/1
+  description VIDEOSURV
+  ip address 10.10.222.254 255.255.255.0
+  service-policy input VIDEO_SURV
+router bgp 65001
+  network 10.10.222.0 mask 255.255.255.0
+access-list 11 permit 10.10.222.0 0.0.0.255
+access-list 111 permit ip 10.10.222.0 0.0.0.255 any
^^^^ END config_and_deploy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* srx-test ** changed : True *******************************************
vvvv config_and_deploy ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- Base Configuration ** changed : True ------------------------------------- INFO
set interfaces fe-0/0/2 unit 0 description "Video surveillance"
set interfaces fe-0/0/2 unit 0 family inet filter input limit-in
set interfaces fe-0/0/2 unit 0 family inet address 10.10.111.254/24
set policy-options policy-statement export2bgp term 1 from route-filter 10.10.111.0/24 exact
set security zones security-zone WAN interfaces fe-0/0/2
set firewall policer policer-1m if-exceeding bandwidth-limit 1m
set firewall policer policer-1m if-exceeding burst-size-limit 187k
set firewall policer policer-1m then discard
set firewall policer policer-1.5m if-exceeding bandwidth-limit 1500000
set firewall policer policer-1.5m if-exceeding burst-size-limit 280k
set firewall policer policer-1.5m then discard
set firewall filter limit-in term 1 then policer policer-1.5m
set firewall filter limit-in term 1 then count limiter
---- Loading Configuration on the device ** changed : True --------------------- INFO
[edit interfaces]
+   fe-0/0/2 {
+       unit 0 {
+           description "Video surveillance";
+           family inet {
+               filter {
+                   input limit-in;
+               }
+               address 10.10.111.254/24;
+           }
+       }
+   }
[edit]
+  policy-options {
+      policy-statement export2bgp {
+          term 1 {
+              from {
+                  route-filter 10.10.111.0/24 exact;
+              }
+          }
+      }
+  }
[edit security zones]
     security-zone test-vpn { ... }
+    security-zone WAN {
+        interfaces {
+            fe-0/0/2.0;
+        }
+    }
[edit]
+  firewall {
+      policer policer-1m {
+          if-exceeding {
+              bandwidth-limit 1m;
+              burst-size-limit 187k;
+          }
+          then discard;
+      }
+      policer policer-1.5m {
+          if-exceeding {
+              bandwidth-limit 1500000;
+              burst-size-limit 280k;
+          }
+          then discard;
+      }
+      filter limit-in {
+          term 1 {
+              then {
+                  policer policer-1.5m;
+                  count limiter;
+              }
+          }
+      }
+  }
^^^^ END config_and_deploy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ifihla amaphasiwedi ku-ansible_vault

Ekuqaleni kwalesi sihloko ngadlula kancane ansible, kodwa akukubi kangako. Ngiyabathanda kakhulu i-vault efana, eklanyelwe ukufihla ulwazi olubucayi ukuze lungabonakali. Futhi mhlawumbe abaningi baye baqaphela ukuthi sinawo wonke ama-login/amagama-mfihlo awo wonke ama-router okulwa acwebezelayo efomini elivulekile efayeleni. gorups.yaml. Akukuhle, kunjalo. Masivikele le datha nge i-vault.

Masidlulise amapharamitha ukusuka ku-groups.yaml kuya ku-creds.yaml, futhi sikubethele nge-AES256 ngephasiwedi enezinhlamvu ezingu-20:

$ cd inventory
$ cat creds.yaml
---
cisco:
    username: admin1
    password: cisco1

juniper:
    username: admin2
    password: juniper2

$ pwgen 20 -N 1 > vault.passwd
ansible-vault encrypt creds.yaml --vault-password-file vault.passwd  
Encryption successful
$ cat creds.yaml 
$ANSIBLE_VAULT;1.1;AES256
39656463353437333337356361633737383464383231366233386636333965306662323534626131
3964396534396333363939373539393662623164373539620a346565373439646436356438653965
39643266333639356564663961303535353364383163633232366138643132313530346661316533
6236306435613132610a656163653065633866626639613537326233653765353661613337393839
62376662303061353963383330323164633162386336643832376263343634356230613562643533
30363436343465306638653932366166306562393061323636636163373164613630643965636361
34343936323066393763323633336366366566393236613737326530346234393735306261363239
35663430623934323632616161636330353134393435396632663530373932383532316161353963
31393434653165613432326636616636383665316465623036376631313162646435

Kulula kanjalo. Kusele ukufundisa wethu Nornir-script ukuze uthole futhi usebenzise le datha.
Ukuze wenze lokhu, kuskripthi sethu ngemuva komugqa wokuqalisa nr = InitNornir(config_file=... engeza ikhodi elandelayo:

...
nr = InitNornir(config_file="config.yaml", dry_run=True) # set dry_run=False, cross your fingers and run again

# enrich Inventory with the encrypted vault data
from ansible_vault import Vault
vault_password_file="inventory/vault.passwd"
vault_file="inventory/creds.yaml"
with open(vault_password_file, "r") as fp:
    password = fp.readline().strip()   
    vault = Vault(password)
    vaultdata = vault.load(open(vault_file).read())

for a in nr.inventory.hosts.keys():
    item = nr.inventory.hosts[a]
    item.username = vaultdata[item.groups[0]]['username']
    item.password = vaultdata[item.groups[0]]['password']
    #print("hostname={}, username={}, password={}n".format(item.hostname, item.username, item.password))

# run tasks
...

Impela, i-vault.passwd akumele ibekwe eduze kwe-creds.yaml njengakusibonelo sami. Kodwa kulungile ngokudlala.

Yilokho kuphela okwamanje. Kukhona ezinye izindatshana ezimbalwa mayelana nokuza kwe-Cisco + Zabbix, kodwa lokhu akukhona kancane mayelana ne-automation. Futhi esikhathini esizayo esiseduze ngihlela ukubhala nge-RESTCONF e-Cisco.

Source: www.habr.com

Engeza amazwana