-
Notifications
You must be signed in to change notification settings - Fork 0
/
802.1x_Authentication.py
180 lines (162 loc) · 7.68 KB
/
802.1x_Authentication.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
from nornir import InitNornir
from nornir.core.task import Task, Result
from nornir_utils.plugins.functions import print_result
from nornir_napalm.plugins.tasks import napalm_get
from nornir_netmiko import netmiko_send_command, netmiko_send_config
from nornir.core.filter import F
import json
import pprint
import requests
import urllib3
import sys
import os
import socket
import getpass
urllib3.disable_warnings()
nr = InitNornir(config_file="config.yaml")
nr.inventory.groups['a'].username = os.getenv("USER") # Specify the username
nr.inventory.groups['a'].password = os.getenv("PW") # Specify the password
hosts = nr.filter(dot1x="yes") # To ensure proper configuration, only hosts with the "data: dot1x: yes" setting in the Host Inventory File should be used
host_list = [] # This is a list of all the hosts that need to be added to ISE at a later stage.
radius_key = getpass.getpass('Enter Radius Shared Key for location: ')
tacacs_key = getpass.getpass('Enter TACACS Shared Key for location: ')
snmp_community = getpass.getpass('Enter SNMP Community: ')
ise_api_user = input('Enter ISE API User: ')
ise_api_ip = input('Enter ISE API IP: ')
ise_api_pwd = getpass.getpass('Enter ISE API PW: ')
radius_ip_1 = input('Enter first Radius IP: ')
radius_ip_2 = input('Enter second Radius IP: ')
#----------------------------------------------------------------------------------------------------------------------
def global_config(task):
r = task.run(netmiko_send_config, name='Set Global dot1x Settings', config_commands=[
"aaa authentication dot1x default group radius",
"aaa authorization network default group radius",
"aaa accounting dot1x default start-stop group radius",
"aaa server radius dynamic-author",
"client " + radius_ip_1 + "server-key 0 " + radius_key,
"client " + radius_ip_2 + "server-key 0 " + radius_key,
"ip device tracking",
"ip device tracking probe delay 10",
"authentication mac-move permit",
"dot1x system-auth-control",
"radius-server attribute 6 on-for-login-auth",
"radius-server attribute 8 include-in-access-req",
"radius-server attribute 25 access-request include",
"radius-server vsa send accounting",
"radius-server vsa send authentication",
"radius server Radius 1",
"address ipv4 " + radius_ip_1,
"key 0 " + radius_key,
"radius server Radius 2",
"address ipv4 " + radius_ip_2,
"key 0 " + radius_key,
"radius-server dead-criteria time 10 tries 3",
"radius-server deadtime 15"]
)
#----------------------------------------------------------------------------------------------------------------------
def interface_config(task):
r = task.run(task=netmiko_send_command, command_string="sh interfaces switchport", use_genie=True)
intf_dict = r.result
intf_list = []
for intf_id,intf_info in intf_dict.items():
if intf_info['switchport_mode'] == 'static access':
intf_list.append(intf_id)
print('The following Interfaces will be configured:')
print('--------------------------------------------')
print(intf_list)
for intf_id in intf_list:
intf_config = task.run(netmiko_send_config,name="Set Interface command for " + intf_id ,config_commands=[
"interface " + intf_id,
"no switchport port-security mac-address sticky",
"no switchport port-security violation restrict",
"no switchport port-security maximum",
"no switchport port-security",
"spanning-tree bpduguard enable",
"spanning-tree portfast edge",
"authentication control-direction in",
"authentication event fail action next-method",
"authentication event server dead action authorize voice",
"authentication event server alive action reinitialize",
"no authentication host-mode multi-auth",
"authentication host-mode multi-domain",
"no authentication open",
"authentication order mab dot1x",
"authentication priority dot1x mab",
"authentication port-control auto",
"authentication periodic",
"authentication timer reauthenticate server",
"authentication timer restart 14400",
"authentication violation restrict",
"mab",
"dot1x pae authenticator",
"dot1x timeout tx-period 8",
"no switchport port-security maximum"]
)
#----------------------------------------------------------------------------------------------------------------------
def ise_config(hostname,tacacsSharedSecret,location,building,switchtype,ip,radiusSharedSecret,ise_api_ip,ise_api_user,ise_api_pwd):
body = {
"NetworkDevice": {
"name": hostname,
"authenticationSettings": {
"radiusSharedSecret": radiusSharedSecret,
"enableKeyWrap": "false",
"keyEncryptionKey": "Wmc8EgBoZwhsLn",
"keyInputFormat": "ASCII"
},
"snmpsettings": {
"version": "TWO_C",
"roCommunity": snmp_community,
"pollingInterval": "28800",
"linkTrapQuery": "true",
"macTrapQuery": "true",
"originatingPolicyServicesNode": "Auto"
},
"tacacsSettings": {
"sharedSecret": tacacsSharedSecret,
"connectModeOptions": "ON_LEGACY"
},
"profileName": "Cisco",
"coaPort": "1700",
"NetworkDeviceIPList": [
{
"ipaddress": ip,
"mask": "32"
}
],
"NetworkDeviceGroupList": [
"Location#All Locations#{}#{}".format(location,building),
"IPSEC#Is IPSEC Device#No",
"Device Type#All Device Types#Switch#{}".format(switchtype)
]
}
}
update_json = json.dumps(body)
update_device(hostname,ise_api_ip,ise_api_user,ise_api_pwd,update_json)
#------------------------------------------------------------------------------
# Use the previously generated JSON to send data to ISE
def update_device(hostname,ise_api_ip,ise_api_user,ise_api_pwd,json):
url = 'https://{}:9060/ers/config/networkdevice/name/{}'.format(ise_api_ip, hostname.upper())
headers = {'ACCEPT': 'application/json','content-type': 'application/json'}
req = requests.put(url, headers=headers, auth=(ise_api_user, ise_api_pwd), data=json, verify=False)
print(req.text)
return
#==============================================================================
# ---- Main: Execute Commands
#==============================================================================
results_global = hosts.run(task=global_config)
results_intf = hosts.run(task=interface_config)
print_result(results_global)
print_result(results_intf)
write_mem = hosts.run(task=netmiko_send_command, command_string="write mem", use_genie=True)
# Create a list of hosts that were processed by Nornir for future addition to ISE through the API
for dev in hosts.inventory.hosts.items():
host_list.append(dev[0])
# To extract the required information from the hostname string, I separate each value I need using the hyphen (-) delimiter
for host in host_list:
location = host[:3].upper()
building = host[8:10]
swt = host[6:7]
if swt == "a":
switchtype = "Access Switch"
ip = socket.gethostbyname(host) # Perform a DNS lookup to retrieve the IP address of the switch.
ise_config(host,tacacs_key,location,building,switchtype,ip,radius_key,ise_api_ip,ise_api_user,ise_api_pwd)