I set up a static nat rule, so that I can use my public internet IP address to directly ssh into a dedicated machine on the inside network. As a result I cannot ssh into the dedicated machine anymore, when connected through AnyConnect VPN. Why? How do I fix this?
I have an ASA 5512-X which I use to terminate AnyConnect VPN sessions. This has been working very well. People use AnyConnect to connect to the ASA, the get IP addresses from the specially assigned IP pool and they can access everything I put in the access-lists.
Now, I have this idea to directly forward port 22 to a dedicated machine in my network (I only have inside and outside interfaces), so that I can SSH into my public IP address and end up on the dedicated machine, without the requirement for a VPN connection.
The setup seemed simple enough:
object network MyEndpoint host 10.0.0.1 nat (inside, outside) static interface service tcp ssh ssh access-list from_outside_inside extended permit tcp any object MyEndpoint eq ssh access-group from_outside_inside in interface outside
and it actually works. Now I can
and actually get a ssh session on my dedicated machine. However, this success comes at the cost that
ssh 10.0.0.1 does not work anymore when I am connected to my ASA/network through AnyConnect as it used to, before I set up static NAT.
I can deterministically control the ASA's behaviour:
When I don't have the
nat (inside,outside) line in my configuration,
ssh 10.0.0.1works but
ssh ssh.mydomain.comdoes not work.
When I have the
nat (inside,outside) rule as part of the configuration, it is the other way round:
ssh ssh.mydomain.comworks but
ssh 10.0.0.1does not work.
To investigate I set up a capture on the ASA
capture MyEndpoint type raw-data interface inside capture MyEndpoint type raw-data interface outside capture MyEndpoint match tcp host 10.0.0.1 any
When I first connect via AnyConnect and then try to
ssh 10.0.0.1, the capture doesn't show/capture anything, as long as the
nat (inside,outside) rule is active. Also, my SSH connect attempts never reach the server.
Clearly the ASA is eating the connection requests originating from AnyConnect-connected endpoints, when the
nat rule is active.
At first I thought I require some addition to the access-list, but I couldn't make it work that way. On which interface does VPN traffic enter the ASA anyway? outside or inside? I suppose in this case doesn't matter, because I am using a wildcard (
any) for the source, which, in my oppinion, includes VPN traffic as well.
Then I thought the ASA would always apply the nat, which means the packet carrying the SYN-ACK would be natted to my outside IP which breaks the connection, as I am connecting from a private VPN address, not the Internet. But the SYNs never get to the server, hence there are no SYN-ACKs.
I spent all day warpping my head around the "new"
nat command. When I do a
show nat on my ASA I get
Auto NAT Policies (Section 2) 1 (inside) to (outside) source static MyEndpoint interface service tcp ssh ssh translate_hits = 0, untranslate_hits = 0
As far as I got today this only does a source address translation for leaving traffic. I have no idea, how/why this implies a destination address translation for traffic originating from the Internet arriving at the ASA. Can anybody explain to me why the ASA is behaving this way?
Reading on through the documentations I came accross the ASA command
packet-tracer. When I do
packet-tracer input inside tcp 10.100.0.2 31337 10.0.0.1 22
The ASA tells me a flow would be created and the packet accepted. When I do
packet-tracer input outside tcp 10.100.0.2 31337 10.0.0.1 22
Phase: 6 Type: WEBVPN-SVC Subtype: in Result: DROP Config: Additional Information: Result: input-interface: outside input-status: up input-line-status: up output-interface: inside output-status: up output-line-status: up Action: drop Drop-reason: (acl-drop) Flow is denied by configured rule
So I guess this is some implicitly wanted behaviour, except if you are me.
Edit 2: Searching for hairpins
I found some articles which eventually pointed me to this promissing one which held the information I might need a nat rule along the lines of
nat (outside,outside) \ source static \ client_vpn_pool client_vpn_pool \ destination static \ remote_office_net remote_office_net
but it didn't work. I have a network object for my vpn client subnet and a network object for the subnet of 10.0.0.1. Adapting the template above did not yield the expected result.
nat (inside,outside) rule is in place, SSH does not work, but I can ping 10.0.0.1 just fine. When I add a
nat (outside,ouside) rule as suggested by the article, the ping stops working. I also tried versions of the outside-ouside rule with network objects for the specific host and just the range of the
ip local pool used for vpn clients. They all just make the ping stop.
Edit 3: Never mind
It's working now. I literally didn't change anything. I just went to bed. I guess there was some internal state in the ASA that caused this behaviour and it timed out while I was asleep.
There is still the thing that when I use
packet-tracer input [inside|outside] tcp <my vpn ip> 31337 10.0.0.1 22 packet-tracer always says the packet would be dropped.
When I put
packet-tracer input inside it fails at:
Phase: 6 Type: WEBVPN-SVC Subtype: in Result: DROP Config: Additional Information: [...] Drop-reason: (acl-drop) Flow is denied by configured rule
and when I put
packet-tracer input outside it fails at:
Phase: 6 Type: NAT Subtype: rpf-check Result: DROP Config: object network MyEndpoint nat (inside,outside) static interface service tcp ssh ssh Additional Information: [...] Drop-reason: (acl-drop) Flow is denied by configured rule
Yet, as of today, ping and SSH to/from my VPN-connected Laptop to MyEndpoint (a.k.a. 10.0.0.1) works like a charm. How does this ASA thing work???