DNAC - 18.104.22.168
ISE - 2.4 patch 11
The task is simple - Host2, an ODC user, should not be able to talk to Host4, a corporate user. Since they are in the same VN (Corp_VN), the goal is to achieve this segmentation via SGTs. An added requirement is that we must log this as well.
Configuration and verification
As part of the authorization policies for these hosts, a VLAN and SGT is returned. Let's confirm the policies again.
For Corporate users, we hit the authorization policy called 'aninchat_corp_users', which returns a result called 'aninchat_corp_users' and an SGT called 'Corp_Emp'. The result is the following:
For ODC users, we hit the authorization policy called 'aninchat_ODC_users', which returns a result called 'aninchat_test_authz' and an SGT called 'ODC_Users'. The result is the following:
Yes, the authorization policies are very crude and rudimentary, but that's not the goal here. The goal is to simply understand what they are doing - which is returning a VLAN and an SGT in both cases.
Let's now confirm both hosts have been authenticated and assigned the correct VLAN and SGT.
Perfect - Host4 was assigned a VLAN of 1029 and an SGT of 18 (and it successfully pulled an IP address of 22.214.171.124 from the DHCP server) while Host2 was given a VLAN of 1030 and an SGT of 20 (and it successfully pulled an IP address of 126.96.36.199 from the DHCP server as well).
Let's complete our topology with this new information.
As a last step, let's go and deploy a SGACL rule that denies conversation between SGT 20 to SGT 18. I've gone through the steps of configuring the policy (notice that I've chosen a contract of Deny IP Log since the intention was to log hits against the policy as well):
Save it and then deploy it.
At this point, a ping from Host2 to Host4 should fail.
Well. That's surprising! So, how do we troubleshoot this?
Since the intention was to block this conversation using SGTs, that is what we should focus on to troubleshoot this. Now, what we know so far is that the SGTs were indeed pushed correctly for each host (we verified that during the previous section).
What about the actual SGACL though? Let's go to Edge1 to make sure that the SGACL was pushed and is applied. Remember, the SGACLs gets pushed to the NAD that has the destination SGT only which is why this will not get pushed to Edge2.
Good - the SGACL is present. How about the contents of the ACL?
Okay, that's definitely odd. The ACL exists but it is empty - there are no ACEs inside it. Let's deploy the policy again and capture the packet exchange between the NAD (Edge1, in this case) and the ISE to understand whats happening.
To re-deploy, I simply revert the change and re-configure the policy, and deploy again. A packet capture was already setup prior to this. Now, this is the flow I see (this is also the generic flow you would typically see when a SGACL is pushed/deployed):
The important things to notice here - ISE informs ALL NADs when a policy needs to be deployed by sending a CoA with an AV-pair that includes the destination SGT that was in the policy.
Any NAD that has downloaded this SGT will then send an Access-Request to ISE to download the actual policy. ISE then returns the SGACL name, following which the NAD again sends another Access-Request requesting for the contents of this ACL. ISE then replies with an Access-Accept which includes the ACEs inside this ACL.
Look at the last Access-Accept in the above flow (where ISE should have sent the ACEs) - it is empty! ISE returned nothing for some reason. Our packet capture also confirms this entire flow.
ISE sending a CoA to the NAD:
Edge1 sending an Access-Request for this SGT:
ISE sending the SGACL name back:
Edge1 sending another Access-Request with the ACL name to get its contents from ISE:
ISE responding back with an empty ACE list:
This is why the ACL is empty - its because ISE never sent anything back! Why would ISE do this?
Remember, by default, on 2.4 patch 11, there are 4 contracts available:
Permit IP Log
Deny IP Log
The "Log" contracts allow for logging of SGACL hits - that's the only difference between them and the regular contracts. These ACLs are maintained on ISE itself - the logical next step would be to check the validity of these ACLs on ISE.
Small hiccup here though - the default contracts CANNOT be viewed in the GUI. Well, good thing we have ERS enabled already! I can use some simple GET calls and leverage some ISE APIs to try and pull these contracts.
As you can see, each of these contracts are referenced via an ID. To look at the actual contents of the ACL, you can reference this ID in your GET call.
The first call pulls the content of the Deny IP contract - focus on the "aclcontent" part. It correctly contains a "deny ip" ACE.
The next call pulls the content of the Deny IP Log contract - again, focus on the "aclcontent" part. It is empty!
And finally, we've come to the source of our problem - the log contracts are empty on ISE. Because of this, when you reference these contracts, ISE does not return any ACE at all.
Naturally, from a troubleshooting perspective, there is where we stop - this was obviously a bug in ISE which is fixed in later patches.