2

I have a number of services running on my server to which I want to restrict access to only those connecting through OpenVPN. I did manage to get routing to work to a second IP I added to the machine, but this is not ideal.

*.*.*.1 is the primary public IP. It is tied to the local IP 172.31.20.102. *.*.*.2 is the secondary IP on the same machine that created for testing. It is tied to the local IP 172.31.20.103. This is done in the Amazon EC2 interface, not on the server.

Note: The *s are just to mask the IP address here. The real configs has the actual public IPs.

Here are the relevant bits of the OpenVPN server config:

dev tun
server 172.16.128.32 255.255.255.240
#push "route *.*.*.1 255.255.255.255 net_gateway"
push "route *.*.*.2 255.255.255.255"

I have tried both with and without the push "route *.*.*.1 255.255.255.255 net_gateway" line, which is why I have it commented in this sample. Note that routing does work to *.*.*.2 in the current configuration.

The server's IP on the VPN is 172.16.128.33.

Here is the relevant line from sysctl.conf:

net.ipv4.ip_forward = 1

Here are the relevant bits from iptables-save:

*nat
-A PREROUTING -p tcp -m state --state NEW -m tcp --dport 22 -j DNAT --to-destination 172.16.128.33
-A POSTROUTING -s 172.16.128.32/28 -o eth0 -j MASQUERADE
COMMIT
*filter
-A FORWARD -i tun0 -s 172.16.128.32/28 -d *.*.*.1 -j ACCEPT
-A FORWARD -i tun0 -s 172.16.128.32/28 -d *.*.*.2 -j ACCEPT
-A FORWARD -i eth0 -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 172.16.128.32/28 -j ACCEPT
-A INPUT -s 172.31.20.100/28 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

-A PREROUTING -p tcp -m state --state NEW -m tcp --dport 22 -j DNAT --to-destination 172.16.128.33 allowed me to SSH into the alternate interface. Adding one of these lines for every port isn't ideal, but would be acceptable if there are no other options.

I want to be able to access port 22, for example, on *.*.*.1. I would prefer that the connection originate from *.*.*.1, rather than my public IP. I realize that I can't route ALL traffic through the tunnel, as the tunnel itself must be maintained, but I want everything else to go through the tunnel.

Let me know if I missed any useful information.

user1936123
  • 133
  • 5
  • I fail to fully understand how you “tie” public and local IPs. Maybe this is Amazon EC2 specific, but can you please explain your network architecture in general? Does NAT occur anywhere? What is the relationship between the local and the public IPs? – Jonas Schäfer May 20 '14 at 15:05
  • @JonasWielicki: Yes, this is specific to EC2 in how they assign their elastic IPs. I have no idea how it is handled under the hood. I don't actually "see" the public IPs from within the server. `ifconfig` returns the local IPs listed in the question. Also, I have to use the local IPs in Apache vhosts. – user1936123 May 20 '14 at 15:12
  • The easiest option might be to drop the public IP and use the OpenVPN network directly. Create a tun/tap device (for multiple clients, if you trust the clients to a certain extent, using tap and bridging might be the easiest option), assign it a random private IP and let the services you want to protect from the outside bind to that IP only. – Jonas Schäfer May 20 '14 at 15:15
  • @JonasWielicki: I'm not sure what you mean by dropping the public IP, but several of the services use SSL and are name-based. Also, the VPN will eventually work with several networks, which, if I understand correctly, requires a routed configuration. – user1936123 May 20 '14 at 15:25
  • Okay, I kind of assumed that it was only for a small amount of services. Without the rule given there, can you check with tcpdump whether the packets are forwarded? Have you enabled IP forwarding in sysctl (``sysctl net.ipv4.ip_forward=1``)? – Jonas Schäfer May 20 '14 at 15:33
  • @JonasWielicki: I have, yes. And verified with `cat /proc/sys/net/ipv4/ip_forward`. – user1936123 May 20 '14 at 15:48
  • If I understand you correctly you would like people accessing `*.*.*.1` when connected to the VPN to have their packets going through the VPN, except packets sent by OpenVPN itself, right? – user2313067 May 20 '14 at 21:29
  • @user2313067: exactly – user1936123 May 20 '14 at 22:11
  • I don't think OpenVPN has support for that included. On a Linux client you should be able to do that by launching the OpenVPN client in a different network namespace. The simplest option though might be to run the OpenVPN server on `*.*.*.2` so that `*.*.*.1` can be routed through the tunnel. – user2313067 May 20 '14 at 22:15

1 Answers1

0

As far as I know, EC2 does not implement nat loopback, which is why connections to yourself fail.

The short solution is either to add the public IP to a dummy interface or DNAT everything which would be forwarded to the public IP to your internal address.

Dummy interface:

ip link add dummy0 type dummy
ip addr add *.*.*.1/32 dev dummy0
ip link set dummy0 up
iptables -A OUTPUT -s *.*.*.1/32 -o eth+ -j REJECT
iptables -A FORWARD -i tun+ -o dummy0 -j ACCEPT
iptables -A FORWARD -i dummy0 -o tun+ -j ACCEPT

or NAT:

iptables -t nat -A PREROUTING -i tun+ -p tcp -d *.*.*.1 -m state --state NEW -j DNAT --to-destination 172.16.128.33

A more common solution is to implement split horizon DNS, which would allow you to run your name-based secure network with internal and external IPs. This will make automatic routing and management significantly easier in the future as your network scales.

Andrew Domaszek
  • 5,163
  • 1
  • 15
  • 27
  • Sorry for the lack of response. It has been a busy day. I'll try to implement your answer tomorrow and get back to you. – user1936123 May 22 '14 at 04:51