Cisco/Python: Backup der Konfiguration bei write Event auf externen Server

Diverse Cisco Geräte können bei einem write Event die Konfiguration an einen anderen Server z.B. über HTTP pushen.

Cisco Config:

archive
 path http://1.2.3.4/cisco_config/put/$h-$t
 write-memory

Apache /etc/httpd/conf.d/zzz_cisco_backup.conf:

WSGIDaemonProcess cisco_backup user=apache group=apache threads=10
WSGIPythonPath /opt/cisco_backup/web_root
WSGIScriptAlias /cisco_backup /opt/cisco_backup/web_root/cisco_backup.wsgi

<Directory /opt/cisco_backup/web_root>
WSGIProcessGroup cisco_backup
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Order deny,allow
Allow from all

<Files cisco_backup.py>
Require all granted
</Files>
<Files cisco_backup.wsgi>
Require all granted
</Files>

</Directory>

cisco_backup.wsgi File:

import sys

sys.path.append("/opt/cisco_backup/web_root")

from cisco_backup import app as application

cisco_backup.py File:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route("/put/<cfg>", methods=['PUT'])
def get_config(cfg):
   with open('/opt/cisco_config/incoming_configs/%s' % cfg, "wb") as f:
      f.write(request.data)
   return "ok"

if __name__ == "__main__":
    app.run()

Viel Spaß 😉

Python: Snippet: SSH shell on Cisco devices

Mit dem Snippet können Kommandos auf einer Cisco Shell via SSH ausgeführt werden.

#!/usr/bin/env python

import paramiko
import sys


def send_string_and_wait_for_string(command, wait_string, should_print):
    shell.send(command)
  
    receive_buffer = ""

    while not wait_string in receive_buffer:
        receive_buffer += shell.recv(1024)

    if should_print:
        print receive_buffer

    return receive_buffer

client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("10.62.62.10", username="testuser", password="testpasswd", look_for_keys=False, allow_agent=False)

shell = client.invoke_shell()
send_string_and_wait_for_string("", "#", False)
send_string_and_wait_for_string("terminal length 0\n", "#", False)
output=send_string_and_wait_for_string("show logging\n", "#", False)
print output
client.close()

Mehr Infos / Quelle: http://blog.timmattison.com/archives/2014/06/25/automating-cisco-switch-interactions/

Python: Cisco Config grabber – Suchen von Interface Configs & Erzeugen von neuer Config

Das Script Snippet dient dazu in den Backupfoldern z.B. vom 20.09.2016 nach Interfaces mit einer bestimmten Description und einem gesetzten Parameter z.B. service-policy zu suchen und automatisch Konfiguration zu erzeugen die diese Config entfernt.

Configbeispiel Cisco Config  (swt70/20.09.2016/swt70-config.txt):

interface GigabitEthernet1/0/47
 description acp10 
 switchport access vlan 17
 switchport mode access
 switchport nonegotiate
 spanning-tree guard loop
 service-policy input ACCESSPOINT
!
interface GigabitEthernet1/0/48
 description acp43 
 switchport access vlan 17
 switchport mode access
 switchport nonegotiate
 spanning-tree guard loop
 service-policy input ACCESSPOINT
!
Das Script benötigt CiscoConfParse und es kann mit „pip install ciscoconfparse“ installiert werden.
#!/usr/bin/python

import os
from ciscoconfparse import CiscoConfParse
import re

buffer = []
buffer_f = []

# Folderstruktur: <switchname>/<backup_datum>/config.txt
for dir in os.listdir("."):
        buffer.append("./"+dir+"/20.09.2016/")

# Files zusammensammeln
for x in buffer:
        try:
                for f in os.listdir(x):
                        buffer_f.append(x+f)
        except:
                pass


# Alle files abarbeiten
for f in buffer_f:
  # Parser laden
  parse = CiscoConfParse(f)
  
  # Interfaces finden in config
  all_intfs = parse.find_objects(r"^interf")
  intfs = list()
  fault_intfs = list()
  # in den interfaces nach description .+acp.+ suchen
  for obj in all_intfs:
    if obj.re_search_children(r"description.+acp.+|description.+ACP.+"):
      intfs.append(obj)
  
  # fuer alle Suchergebnisse description .+acp.+ suche nach service-policy
  for i in intfs:
    
    if i.re_search_children(r"service-policy.+"):
      sp = i.re_search_children(r"service-policy.+")
      
      fault_intfs.append((i, sp[0].text) )
  
  # wenn eine zeile im fault buffer ist 
  if len(fault_intfs) > 0:
    
    # switchnamen aus dateinamen extrahieren
    n = re.search(r"^.+(swt[0-9][0-9]).+|^.+(SWT[0-9][0-9]).+",f)
    if n.group(1) is None:
      print n.group(2)
    else:
      print n.group(1)
    
    # no statements erzeugen
    for i, no_cmd in fault_intfs:
      print "!"
      print i.text
      print "no "+no_cmd
      
    print "! ---"
  else:
    pass

Das Script erzeugt folgenden Output:

swt70
!
interface GigabitEthernet1/0/47
no  service-policy input ACCESSPOINT
!
interface GigabitEthernet1/0/48
no  service-policy input ACCESSPOINT
! ---

 

Cisco ASA überflüssige Syslog Nachrichten deaktivieren

Das Syslog auf der Cisco ASA ist sehr geschwätzig und viele Nachrichten sind für das nachvollziehen von Verbindungen nicht notwendig.

Cisco Syslog Messages ASA: http://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog.html

Folgende Syslog Typen lassen sich problemlos deaktivieren:

no logging message 302012Error Message %ASA-6-302012: Pre-allocate H225 Call Signalling Connection for faddr IP_address /port to laddr IP_address
no logging message 302013Error Message%ASA-6-302013: Built {inbound|outbound} TCP connection_id for interface :real-address /real-port (mapped-address/mapped-port ) [(idfw_user )] to interface :real-address /real-port (mapped-address/mapped-port ) [(idfw_user )] [(user )]
no logging message 302014Error Message %ASA-6-302014: Teardown TCP connection id for interface :real-address /real-port [(idfw_user )] to interface :real-address /real-port [(idfw_user )] duration hh:mm:ss bytes bytes [reason ] [(user )]
no logging message 302015Error Message %ASA-6-302015: Built {inbound|outbound} UDP connection number for interface_name :real_address /real_port (mapped_address /mapped_port ) [(idfw_user )] to interface_name :real_address /real_port (mapped_address /mapped_port )[(idfw_user )] [(user )]
no logging message 302016Error Message %ASA-6-302016: Teardown UDP connection number for interface :real-address /real-port [(idfw_user )] to interface :real-address /real-port [(idfw_user )] duration hh :mm :ss bytes bytes [(user )]
no logging message 302020Error Message %ASA-6-302020: Built {in | out} bound ICMP connection for faddr {faddr | icmp_seq_num } [(idfw_user )] gaddr {gaddr | cmp_type } laddr laddr [(idfw_user )] type {type } code {code }
no logging message 302021Error Message %ASA-6-302021: Teardown ICMP connection for faddr {faddr | icmp_seq_num } [(idfw_user )] gaddr {gaddr | cmp_type } laddr laddr [(idfw_user )] (981) type {type } code {code }
no logging message 305011Error Message %ASA-6-305011: Built {dynamic|static} {TCP|UDP|ICMP} translation from interface_name :real_address/real_port [(idfw_user )] to interface_name :mapped_address/mapped_port
no logging message 305012Error Message %ASA-6-305012: Teardown {dynamic|static} {TCP|UDP|ICMP} translation from interface_name [(acl-name )]:real_address /{real_port |real_ICMP_ID } [(idfw_user )] to interface_name :mapped_address /{mapped_port |mapped_ICMP_ID } duration time
Optional:
no logging message 302017Error Message %ASA-6-302017: Built {inbound|outbound} GRE connection id from interface :real_address (translated_address ) [(idfw_user )] to interface :real_address /real_cid (translated_address /translated_cid ) [(idfw_user )] [(user )
no logging message 302018Error Message %ASA-6-302018: Teardown GRE connection id from interface :real_address (translated_address ) [(idfw_user )] to interface :real_address /real_cid (translated_address /translated_cid ) [(idfw_user )] duration hh :mm :ss bytes bytes [(user )]

Config:

no logging message 302012
no logging message 302013
no logging message 302014
no logging message 302015
no logging message 302016
no logging message 302020
no logging message 302021
no logging message 305011
no logging message 305012
! Optional
no logging message 302017
no logging message 302018

 

Einrichten einer NPS Policy für Cisco Geräte

  • Im Baum auf „Netzwerkrichtlinien“ einen Rechtsklick und „Neu“ auswählen

  • Einen Policy Namen festlegen z.B. „Cisco Device Access“

  • Folgende Bedinungen werden benötigt
    • Windows-Gruppe: radius_nw_equipment_access
    • Clientanzeigename: CISCO-R?
    • NAS-Porttyp: Virtuell (VPN)

  • Zugriff gewähren

  • Haken von MS-CHAPv2 und MS-CHAP entfernen und nur PAP auswählen

  • Hier wird nichts verändert, Weiter…

  • Framed-Protocol und Service-Type entfernen

  • Unter „Herstellerspezifisch“ den Typ „Cisco-AV-Pair“ mit dem Attributwert „shell:priv-lvl=15“ hinzufügen

  • Fertigstellen

  • Die Policy mit Rechtsklick „Nach oben“ in die oberste Position befördern

Fertig.

Radius Konfiguration für Cisco Geräte

Konfiguration mit Rescue User falls Radius ausfällt. In dem Fall wird mit Username/Passwort und enable-Secret gearbeitet. Im Fall einer Radiusanmeldung arbeitet der User direkt im Privilege Mode 15.

!
aaa new-model
aaa group server radius RADIUS_AUTH
server 192.168.10.1 auth-port 1812 acct-port 1813
!
aaa authentication login networkaccess group RADIUS_AUTH local
aaa authorization exec default group RADIUS_AUTH if-authenticated
aaa authorization exec networkaccess group RADIUS_AUTH local if-authenticated
enable secret 5 $1$UaiX$0ivA6uWDl0eNoZWv4ciLW.
!
username admin privilege 15 secret 5 $1$dArb$Q2sC1uPNaL0QUMlc/V7sF1
ip subnet-zero
!
ip radius source-interface FastEthernet0/1
!
radius-server host 192.168.10.1 auth-port 1812 acct-port 1813 key geheim
radius-server retransmit 3
!
line con 0
 login authentication networkaccess
line vty 0 4
 exec-timeout 0 0
 login authentication networkaccess
line vty 5 15
 exec-timeout 0 0
 login authentication networkaccess
!