Everybody knows me to be a huge dedicated Cisco fanboy. So when I first attempted to upgrade to the latest and greatest Adaptive Security Appliance operating system (8.3) over a year ago, I was scared away when the "upgrade" broke my long worked on and cleverly optimized configuration.
Now, I don't back down from things too easily, but being lazy, it took me about a year to look back at it and attempt a conquering. How did the conquering go? Poorly. Well, not poorly. I figured out what was causing my issues after researching and finding a very nice breakdown on the cisco support forums.
After spending a couple days waiting for a newly purchased ASA5505 with an unlimited users license (I had a 10 user, and user for Cisco means IPs. I have significantly more than 10 IPs on my network...), I spend the time trying to build a new configuration based on the walkthrough for NAT. All of the configuration differences were documented and then put into a text configuration file properly broken down. So, Ready to go!
I fire up my new ASA5505, upgrade the OS to 8.2 (including the ASDM to 6.2), and then a final upgrade to 8.4.1 (ASDM 6.4.1). Off the get-go, most of my default configurations work flawlessly. A few new features and alterations to configurations, but nothing significant, and quickly changed in my text file. Then, came the heartache and disappointment.
First, a bit of background to why I considered my configurations "clever" and "optimized". The ASA has a nifty feature called "object-group", that in my opinion, is just brilliant for making a clean structured configuration for rules and policies. With these object-groups, you can essentially create groupings of networks, ports, port ranges, services, etc... If you're asking yourself why this is important? I answer you: Memory.
If you haven't been following technology over the last decade, let alone the last two decades, you would have noticed all technology is moving towards doing as much as possible in memory. This is due to memory systems being thousands of times faster than conventional storage and processing. Think about it, remember everything you need to do during the day, or simply put it in a calendar you can pull from. Of course the calendar is useful, you just grab the information as the time comes needed to use it, and that frees up your mind to simply process things as it comes by.
Coming back to the object-groups, you can essentially load up a broad range of information into memory, by applying them with access lists. In the networking world, access-lists are used to allow/deny things, but also, to define interesting traffic. A best example for this scenario, will be VPN. VPN relies on handshaking, mirrored access-lists, and pretty much duplication of configurations on both sides, but in reverse. What triggers a VPN, is the ACL (access list) being processed when a packet flows through (yes, PROCESSED). If the packet source IP, port and destination IP, port match the ACL, it then encapsulates the packet and sends to it's destination all bundled like a pig in a blanket.
Where the "optimized" configurations in networking come from, are when you can manage to optimize your routing/processing to the littlest amount possible. This involves refining ACLs to a minimum to stop the router engine from stopping, sending an IRQ to the processor, and then looking at EACH ACL in priority until it hits a match. If no match, it simply forwards out the "default route". In a small office, it's not that heavy, but it's great to stick to best practice and scalability. Who knows, you could be working for the next Microsoft, and you get to help in TAKING OVER THE WORLD! Narf. In this scenario, the firewall will process all packets and you want to keep as much processing for the firewall to do what the firewall does. It encrypts/decrypts packets for secure delivery, it filters packets, intrusion prevention, etc... By adding object groups, you can condense the ACLs based on traffic flows instead of each flow.
Ok, enough shovel following the horse... Why is this all important and why Cisco (in my opinion) screwed up. They took the object groups, and applied it to everything now. Their new NAT is simpler for the newbie admin, and easier to follow, but it's convoluted and a waste of text space. Let's compare the amount of lines of "code" it takes to do a simple Port forward in 8.2, and then 8.3.
object-group service SERVER_Services tcp port-object eq ident port-object range 6100 6199 object-group service NETWORK_SERVICES tcp group-object SERVER_Services group-object SERVER_Services group-object SERVER3_Services access-list outside_access_in extended permit tcp any host OUTSIDE_IP object-group NETWORK_SERVICES ! Removed Code static (inside,outside) tcp interface ident SERVER ident netmask 255.255.255.255 static (inside,outside) tcp interface 6101 SERVER 6101 netmask 255.255.255.255 static (inside,outside) tcp interface 6150 SERVER 6150 netmask 255.255.255.255 |
object-group service SERVER_Services tcp port-object range 6100 6199 port-object eq ident object network SERVER-ident host 172.32.100.5 nat (inside,outside) static interface service tcp ident ident object network SERVER-6101 host 172.32.100.5 nat (inside,outside) static interface service tcp 6101 6101 object network SERVER-6150 host 172.32.100.5 nat (inside,outside) static interface service tcp 6150 6150 access-list outside_access_in extended permit tcp any host SERVER object-group SERVER_Services |
I'm sure you're asking "so what? it's two extra lines..." Well, you're right, but, scale that. The first configuration has 10 lines of code, but 3 of those lines are ADDED to simply combine everything into a single Access list. One access list, for one external IP, which in turn then port redirects to whatever port is triggered. The new method is definitely object orientated, but the old method was a packet derivative. It followed the flow, now, it follows the device. This is where the issue comes up with me when scaling and optimizing.
I now have to create two extra lines for every port forward I need to make, and an access list for every server that will be port forwarded to. The new method uses the internal IP in the access list, while the old method used the global external IP that I used to mask my internal devices with. In essence, you no longer have a hirarchical flow from L4 and down. Your configuration is triggered by the Port and Nat process, and THEN verifies the access list. Instead of simply checking one global ACL, and then converting with a single line of code.
Confusing? Yeah, that was why I was shy'd away from the get-go.