Openvpn – Access instance behind ELB through OpenVPN server

amazon-elbamazon-web-servicesopenvpn

I want to redirect the traffic through an openvpn server only for some specific domains (dev.mydomain.com, admin.mydomain.com, jira.mydomain.com, etc) which are hosted on some ec2 machines and they are behind some ELBs (each one with 2 AZs – so it has 2 public IPs) and the domains are managed through route53.

In my vpn server config I have

push "route 54.72.xxx.xyz 255.255.255.255 10.8.0.1 1" # dev.mydomain.com
push "route 54.72.xxx.xyz 255.255.255.255 10.8.0.1 1" # 2nd IP for dev.mydomain.com
....

for each domain. Unfortunately also these AWS ELB IPs are changing from time to time and I have to update my server config manually.

Do you know a solution for this?

Best Answer

There are two main ways how to address this:

  1. Keep public access to dev, admin, jira and only optionally route traffic through the VPN. That's what you seem to be doing now. You will have to keep re-resolving the hostnames to IPs as the IPs occasionally change as you know.

    • One way is to update the server config push route lines from time to time, e.g. using cron.

      In your openvpn.conf on the server add a line that will make it read additional config from a separate file:

      dev tun
      server ...
      config /etc/openvpn/elb-routes.inc # <- This file gets updated automatically
      

      Then create a cron job that runs this script every hour:

      #!/bin/bash -e
      
      # Resolve each of the ELB_HOSTNAMES below and update the server config
      
      ELB_HOSTNAMES="dev.mydomain.com admin.mydomain.com jira.mydomain.com"
      for ELB_HOSTNAME in ${ELB_HOSTNAMES}; do
          for ELB_IP in $(host -t A ${ELB_HOSTNAME} | awk '/has address/{print $NF}'); do
          echo "push \"route ${ELB_IP} 255.255.255.255 vpn_gateway 1\""
          done
      done > /etc/openvpn/elb-routes.inc
      
      systemctl reload openvpn.service
      

      It will update the list of push routes in /etc/openvpn/elb-routes.inc with the most recent IPs of the ELBs so you always get the correct routes.

      You can go even fancier and hook up this script on CloudWatch Event that's created every time the ELB IP changes to get it updated immediately :)


    • Another option is to do the ELB hostname to IP resolving on the client. To do that remove the push route command from the server config and instead create the routes dynamically when the client connects.

      To do that create an openvpn up script on the client that will be called every time you connect to the VPN:

      script-security 2
      up /etc/openvpn/up.sh
      

      Then in /etc/openvpn/up.sh you can resolve the current IPs of your ELBs and create the appropriate routes:

      #!/bin/bash
      # Resolve each of the ELB_HOSTNAMES below and insert route through the VPN
      
      ELB_HOSTNAMES="dev.mydomain.com admin.mydomain.com jira.mydomain.com"
      for ELB_HOSTNAME in ${ELB_HOSTNAMES}; do
          for ELB_IP in $(host -t A ${ELB_HOSTNAME} | awk '/has address/{print $NF}'); do
              ip route add $ELB_IP via $route_vpn_gateway dev $dev
          done
      done
      

      Note that you will need the host command from bind9-host (Ubuntu) or bind-utils (Fedora) packages.

      Now every time you bring up your OpenVPN connection it will run this script, resolve the hostnames, and run commands like this:

      # IPs for dev.mydomain.com ...
      ip route add 52.65.12.34 via $route_vpn_gateway dev $dev
      ip route add 13.211.56.78 via $route_vpn_gateway dev $dev
      

      For more info about OpenVPN up/down scripts check the OpenVPN man page, namely sections for --up, --script-security and Environmental variables.


  2. Another and IMO better option is to restrict access to dev, admin, jira to VPN only and don't permit access without VPN at all.

    That's not what you are asking for in the question but it may be a good option for increased security - no one without the VPN will be able to access these restricted hosts.

    To do that simply change the ELBs to Scheme: internal - that will give them only private IP addresses (e.g. from 172.31.0.0/16 range) and assuming your VPN is configured to route all the traffic to 172.31.0.0/16 from your clients you will have the only have access to dev, admin, jira over VPN.

    ELB Scheme: internal


Hope one of these methods will work for you :)