I have the following scenario:

1 - A bastion (NAT) instance which I use as a gateway to forward ssh access to all my private instances (using iptables) [Private IP: Public IP:]

2 - A public instance under the same vpc (but not and under the same subnet) as my bastion instance (which uses an internet gateway) [Private IP: Public IP:]

I would like to access my public instance (2) through iptables forward in bastion (1), but I'm being able to. It results in timeout. (all other forwards to private instances works).

This is intriguing because: - If I ssh the public instance directly by using its public IP it works fine.

  • If I ssh into bastion and then ssh into the public instance using its private IP it also works fine.

This is the iptables rule I'm using in my bastion:

iptables -t nat -A PREROUTING -d -p tcp --dport 1500 -j DNAT --to-destination

This works: ssh user@

This works (inside bastion (1)): ssh user@

This doesn't work (timeout): ssh -p 1500 user@

  • all ports used are open in the security group.
  • public ips are not real, just for example

Any thoughts are appreciated.

  • Is (1) defined as the gateway for the private network range you are NATing to, in the routing table of (2) ? Where are you SSHing from ? – Xavier Lucas May 5 '15 at 17:01
  • You mean: change the route table of (2) to have (1) as destination? If I do this it will work, but (2) will not be public anymore, since I'm currently using an internet gateway instead. – Josué Lima May 5 '15 at 17:01
  • No I don't mean change the default gateway. Simply the routing table for the private range in case the router's private IP where you DNAT is not on the same LAN. – Xavier Lucas May 5 '15 at 17:03
  • I'm sshing from my local machine. If I ssh from my local machine using (2) public IP address it works. If I ssh from (1) using (2)'s private IP address it also works. If I ssh to (2) from my local machine through (1)'s iptables forward it doesn't work. – Josué Lima May 5 '15 at 17:03
  • Ok, can you put some IP addresses in your post so we get a better idea of your networks ? – Xavier Lucas May 5 '15 at 17:09

You've got an asymmetric routing situation involving NAT, here, and that isn't going to work.

Of course, if your target instance has a public IP anyway, it would seem that there's not much of a bastion effect going on at the bastion host... but assuming you have a logical reason, here's my take on the problem:

Let's call the client machine C, the bastion B, and the target instance T.

Traffic arrives: source IP = C, dest IP = B.

B translates: source IP = C, dest IP = T. Send to T.

T receives: source IP = C, dest IP = T.

T replies: source IP = T, dest IP = C.

Where does the reply traffic go? Not to the bastion -- it goes to the Internet Gateway... a reply packet to a TCP flow the gateway has never heard of. The gateway, by all rights, should drop it or send a TCP RST to the sending instance T to tear down this invalid connection.

The client C should not see this response, but even if it did, the client now sees...

Source IP = T, dest IP = C.

This is not expected by the client, or by any intermediate stateful firewalls, so the traffic is dropped or rejected.

With your private-addressed machines, their default VPC route (I assume) points to the bastion host, so there's no asymmetric situation, here. The bastion can translate the addresses in the opposite direction on the way back to C and everything works.

Now, theoretically, you should be able to make this setup work by adding a second rule to the bastion, so that these ssh connections adopt the bastion host's IP address as their source address.

Leaving the DNAT rule in place, you'd need something like this...

iptables -t nat -A POSTROUTING -d -p tcp --dport 22 -j SNAT 

Of course, I just made that up, since I've never had occasion to do this... but it the logic, at least, is sound.

Now, assuming this (or something really similar) works, you've solved your problem of reachability... and created a new problem: the source IP address (in the logs on the inside server) will always be the bastion host. We didn't have much choice, but to do this, to make the translates connection routable back to the Internet... but you might be better off just accessing the machine with its public address.

Another way to accomplish this is with HAProxy on the bastion. The source address seen by the T server will still be the bastion host's inside address... but now you have nice log files on the bastion host for IP address tracking. On the occasion that I have needed to expose an internal TCP service to the Internet, this is my preferred approach, over DNAT, because of the logs, access control, and connection stats the proxy makes available. (HAProxy is both an http-aware load balancer and a payload-agnostic TCP load balancer. I'm not affiliated with the product, just a fan).

  • Thanks for your detailed explanation. It was really helpful! The reason I want to make the access through bastion, and not through the public IP address, is just to keep consistence once I have many other serves in the private vpc also being accessed through bastion. This way I can create and maintain standardized ssh config files and also manage all the access to the servers through iptables in bastion. Thank you once again. – Josué Lima May 6 '15 at 3:39

I am not sure what is going on but suspect a routing problem/mismatch is a possibility. Have you tried usinga tool like tcpdump to check is the packets make it and the route the take?

  • This is not the case Boris. Michael, right above your comment, gave an answer that addresses the problem. Anyway, thanks for trying to help. – Josué Lima May 6 '15 at 3:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.