Where the ASA sits
In my lab the MikroTik owns the edge: dual-WAN, NAT, the perimeter firewall. The ASA lives one hop behind it, and its job is everything inside. It's the Layer 3 gateway for all six VLANs and the place where inter-VLAN policy is actually enforced.
Physically it's almost boring. One interface faces the MikroTik over a small /30 transit link. One interface faces the Aruba switch as an 802.1Q trunk. That single trunk carries every internal VLAN, and on the ASA side each VLAN gets its own sub-interface with its own gateway address. One physical cable, six logical gateways. Router-on-a-stick, except the stick is a firewall.
That layout took me longer to arrive at than I'd like to admit. I started by trying to give each VLAN its own physical port, because I had the ports and it felt cleaner. It isn't how you do it once you have more VLANs than you want to burn ports on, and the trunk-with-sub-interfaces model is both how real deployments look and a lot less cabling to get wrong.
Lesson 1: a security level is not a policy
The first thing that confused me about the ASA was the security-level model. Every interface gets a number from 0 to 100, where higher means more trusted. By default, traffic flows freely from a higher level to a lower one and is blocked from lower to higher unless you explicitly allow it.
Coming from reading about plain routers, I half-expected the firewall to just block things. It doesn't, not the way you assume. If you leave two internal segments at sensible-looking default levels, the higher one can reach the lower one with no ACL involved at all. I found this out the obvious way. A device on a segment I thought was walled off happily reached a service it had no business touching, and there was no "deny" anywhere to explain it, because I had never needed to write one. The security levels had quietly allowed it for me.
The fix wasn't clever. I decided I would not lean on security levels for policy at all. Every inter-VLAN decision goes through an ACL I wrote on purpose, and the levels became almost incidental. If I can't point at the line that allows a flow, the flow shouldn't be happening.
Lesson 2: the ACL is read top to bottom, and the first match wins
This one bit me more than once. An ASA access-list is evaluated in order, top to bottom, and the first line that matches a packet decides its fate. Nothing below a match is ever looked at.
That sounds simple until you write a broad permit early and a specific deny later, expecting the deny to win. It doesn't. The broad permit above it already let the packet through, and your carefully-worded deny is dead text. I spent an evening convinced a rule was broken when the real problem was that a line three entries higher was matching first.
The discipline I settled on:
- ›No
permit ip any any, anywhere. Every allow is scoped to a source, a destination and ideally a port. - ›Specific denies go above broad permits, never below.
- ›The implicit
denyat the bottom of every ACL is the backstop, not the plan. I let it catch what I forgot, but I don't rely on it to express intent. - ›Log the denies. A deny you can't see is a deny you can't learn from.
Once the order made sense, most of my "the firewall is broken" moments turned out to be the firewall doing precisely what I told it to, in precisely the order I told it.
WATCH IT EVALUATE
Lesson 3: NAT broke my logging before I understood NAT
This is the one I'm least proud of and learned the most from.
The ASA translates internal traffic on its way out toward the MikroTik, which is what you want for general internet access. The trouble started when I pointed the firewall's syslog at my Wazuh box on the server VLAN. The log traffic crossing between the MikroTik transit link and the server subnet was getting translated when it had no reason to be, and Wazuh either didn't see the logs cleanly or saw them coming from the wrong address. I had set up a SIEM and then quietly starved it.
The fix was a NAT exemption: tell the ASA explicitly not to translate traffic between the MikroTik link and the server subnet, so it arrives as itself. The part that took me a while was where that rule has to live. NAT on the ASA is evaluated in a specific order, and a general translation rule will happily eat the traffic before a more specific exemption ever gets a look in if you place them wrong. Same shape of bug as the ACL lesson, in a different costume. Order matters, and the specific case has to come before the general one.
Lesson 4: I locked myself out (once)
Hardening the management plane is the part everyone agrees you should do and nobody enjoys. SSH version 2 only. Telnet and the web management disabled entirely. SSH allowed only from my admin VLANs, not from anywhere internal. A login banner, an actual key, AAA for logins.
I did all of that in roughly the wrong order and tightened the allowed SSH source range from a session that wasn't going to survive the change. The ASA did exactly what I asked and stopped accepting me. The lesson is unglamorous and permanent: get console access before you harden remote access. The ASA has a physical console port for exactly the moment you need it, and the moment you need it is usually one you created yourself.
What it taught me
A few things that have stuck:
The ASA is order-of-operations all the way down. NAT is evaluated in a defined sequence, ACLs match first line to last. Most of my early bugs were me not respecting that order, not the box misbehaving.
Default-deny is only real once you've also removed the accidental allows. The security levels quietly permitting higher-to-lower traffic taught me that "I didn't allow it" and "it's denied" are not the same sentence.
Console access is a seatbelt. Harden remote management from a position where locking yourself out is a five-minute recovery and not a bad night.
And sending the firewall's logs to the SIEM changed how I relate to it. The ASA stopped being a black box the moment its denies started showing up in Wazuh, where I could finally watch what it was actually doing instead of guessing.
This is a home lab, on older hardware running an older image, and I won't pretend it's a data-centre edge. But the model underneath — security levels, NAT order, an ACL you can read top to bottom — is the same one I expect to meet on the job, and configuring it by hand, including every part where I broke it first, is the only reason I understand it at all now. The sanitized running config is on my GitHub.