In my previous post, I showed you how to accomplish a certain goal using undocumented APIs. However, in critical environments, i totally understand, that you don't have a good feeling with it.
This was the motivation for a second part. In this post i will show you how you can accomplish the same goal as from part one, but with the Identity Services Engine (ISE) ERS API! Transferring microsegmenting to the ISE has a tradeoff. It will deactivate the matrix of the DNA Center and set the SGT page to read-only.
First of all you need to go to Policy -> Group-Based Access Control and hit Configuration on the DNAC.
And check the second option to accomplish the task:
Please note that this will not automatically sync with the ISE. You have to tell this to the ISE as well. Also notice, that TrustSec is still in read-only mode, when you go to the ISE configuration.
To achieve the same as you already did on the DNAC, go to Work Centers -> TrustSec -> Settings and check the box shown below:
Henceforth we can start with the script. As you already guessed i´ll use the sdk, because it will handle the waiting for tasks to finish and/or if we hit a rate-limit (code 429).
You can find the docs here: https://ciscoisesdk.readthedocs.io/en/latest/
I reused the code from Part 1 as far as possible.
But before we dive into the python code i want to mention a structure that really toothpastes my orange juice to find out.
There is a concept of a container which maps a SGT to one or more virtual networks. Every container has exactly one SGT mapped to it. But it it can have none, one or multiple virtual networks.
The mapping is accomplished by specifying container id, sgt id and a list of VNs.
You can use this format for the VN list:
[
{
"id" : f"{vnID}",
"name" : f"{VN}",
"defaultVirtualNetwork" : False,
"vlans" : []
}
]
Let's continue to the process of logging in:
from ciscoisesdk import IdentityServicesEngineAPI
def login():
api = IdentityServicesEngineAPI(username= credentialsise.username,
password=credentialsise.password,
base_url=credentialsise.base_url,
verify=False)
We are using the same Excel File as in Part one and the same order of API calls.
Syncing the SGTs in the Excel with the ones configures on the DNA Center:
def sync_SGTs(api, sheet_sgt):
"""
get all SGTs and create a list of all SGT names
limited to 100 sgts. todo: look for nextPage in the response and
do a further call for the next page.
"""
all_SGTs = api.security_groups.get_security_groups(size=100).
response['SearchResult']['resources'])
currentSGT=[]
for sgt in allSGT:
currentSGT.append(sgt['name'])
"""
convert the rows from the sheet into a list with tuples.
Start with row two and max col three to only
get values and not the topics.
Filter None Fields.
Creating two lists.
todo: atm only one VN is supported. later add the
possibility to have a SGT in multiple VNs simultaneously
"""
inputSGT = []
sgtVNTable = {}
for row in sheet_sgt.iter_rows(min_row=2, max_col=2,
values_only=True):
if not None in row:
inputSGT.append(row[0])
sgtVNTable.update({f"{row[0]}":f"{row[1]}"})
#compare the SGTs of the Excel to the current SGTs on the DNAC
diffSGTs = set(inputSGT).difference(set(currentSGT))
We now have a list called "diffSGTs" which includes all missing SGTs. In the previous part we used a separate API to get a free SGT value. The ISE SDK is doing this for us. It is possible to specify a designated number or set -1 for letting the ISE choose a free value.
#create the missing SGTs and put them into the right Virtual Network
for sgt in diffSGTs:
api.security_groups.create(name=sgt, value=-1)
Now it is time for the tricky part, even though we use the SDK:
I briefly described already the relationship between SGT - Container - VN list. As soon as a SGT is created, a Container is born as well. To update the mapping, we need to know which container is required. Unfortunately if i get all containers, i only get the id, name and description for each. I need to get the container by id to see all mappings. SGT and VN respectively .
Therefor i iterate through all containers by id until i find the container holding the SGT I´m looking for.
I also tried to find a mapping by requesting a SGT and VN by id. But neither have a container referenced.
If somebody is reading this and has found out a better approach, please reach out to me. I will update this post.
def setVNsforSGT(api, sgt, VN):
#get VN Id
vnID = getVNId(api, VN)
#get SGT Id
sgtID = getSGTId(api, sgt)
VNlist =
[
{
"id" : f"{vnID}",
"name" : f"{VN}",
"defaultVirtualNetwork" : False,
"vlans" : []
}
]
#limited to 100 containers. todo: check of nextPage next
#is in response and get next page
all_containers =
api.security_group_to_virtual_network.get_all(size=100)
.response["SearchResult"]["resources"]
#need to get all containers and search for a container which has the
#sgt ID in it. after finding it,update and break out of the loop
for container in all_containers:
csgtid =
api.security_group_to_virtual_network.get_by_id(container["id"])
.response["SgtVNVlanContainer"]["sgtId"]
if csgtid == sgtID:
api.security_group_to_virtual_network
.update_security_groups_to_vn_to_vlan_by_id(id=container["id"],
sgt_id=sgtID, virtualnetworklist=VNlist)
break
return
! This will override the existing mapping. !
After synchronizing the SGT, the script continue with creating the policy rules described in the Excel file.
Again, the same story as in part one. Preemptively delete a possibly rule already in place before moving on setting the rule.
Other than the DNA Center, the ISE does not have a "Permit IP" and "Deny IP" rule. Keep this in mind. But to make sure we can reuse the Excel file, i catch the input of one of the two rules and "translate" this to the parameter the ISE requires for this action.
#set a policy based on Source/Destination SGT and contract. Getting the #IDs for those three objects and set a name
def setPolicy(api, sheet_Policies):
for row in sheet_Policies.iter_rows(min_row=2, max_col=3,
values_only=True):
if not None in row:
srcSGT = row[0]
dstSGT = row[1]
contract = row[2]
#get id for the ACL
aclID = getContractID(api, contract)
#deletion of current Policy in case it is already configure.
#Because ltering with PUT is a lot of code and effort
deletePolicy(api, srcSGT, dstSGT)
"""
make cell rule
unlike the DNAC the ISE does not use Permit
IP or Deny IP. For this case, ISE API uses
default rules. To keep the Excel File the same
no matter you are using the ISE or the DNAC
script we catch these conditions
"""
if contract == "Permit IP":
api.egress_matrix_cell
.create_egress_matrix_cell(
source_sgt_id=getSGTId(api, srcSGT),
destination_sgt_id=getSGTId(api, dstSGT),
matrix_cell_status='ENABLED',
default_rule="PERMIT_IP")
elif contract == "Deny IP":
api.egress_matrix_cell
.create_egress_matrix_cell(
source_sgt_id=getSGTId(api, srcSGT),
destination_sgt_id=getSGTId(api, dstSGT),
matrix_cell_status='ENABLED',
default_rule="DENY_IP")
else:
api.egress_matrix_cell
.create_egress_matrix_cell(
source_sgt_id=getSGTId(api, srcSGT),
destination_sgt_id=getSGTId(api, dstSGT),
matrix_cell_status='ENABLED', sgacls=[aclID])
return
It took a lot of effort to put this together, but I'm happy to know that it could be of help to someone. Thank you for reading
Comments