Secondary gateway IP
The secondary gateway IP is intended to create an egress IP that is different from the gateway IP.
Why must the egress ip be different than the gw address? The reason the egress ip (ip_address) must be different than gateway address (openvpn.gateway_address) is that, by necessity, all traffic routed to the gateway IP by clients is not encrypted by the VPN. it must be this way so that the VPN doesn't try to encrypt its own traffic, leading to an endless loop. the problem is, if gateway and egress are the same, then any p2p app run by users on the same gateway will bypass the VPN.
What needs to be done to make it work?
-
Determine the right way to configure the gateway address Right now in group_vars/all/gateway_locations.yml we have the location, country_code, hemisphere, and timezone, and the gateway_address is the one that needs to be added to the machine.
-
Determine the interface to use
-
Firewall needs to be setup properly Ports should be opened for gw address for obsf4/openvpn, and not ip_address, currently config/roles/openvpn/tasks/openvpn.yml installs openvpn firewall, sets ip_forward, installs vpnweb nat config
-
Services bind to the gateway_address openvpn daemon binds to gateway_address, and vpn clients connect to it obsf4 binds to gateway_address
-
Configure eip-service.json the gateway_address is the one that should be put into the eip-service.json
this is generated in config/roles/vpnweb/tasks/main.yml by calling the simplevpn 'module' (config/roles/vpnweb/tasks/main.yml):
- name: "Generate eip-service.json and provider.json"
local_action:
module: simplevpn
obfs4_state_dir: "{{ credentials_dir }}/shapeshifter"
locations: "{{ locations }}"
domain: "{{ domain_public[0] }}"
gateways: "{{ groups['openvpn'] | map('extract', hostvars) | list }}"
openvpn: "{{ openvpn_config }}"
provider_api_uri: "https://{{ api_uri }}:4430"
ca_cert_uri: "https://{{ ca_cert_uri }}"
ca_public_crt: "{{ credentials_dir }}/common/api_ca.crt"
run_once: true
register: simplevpn_result
notify:
- "restart docker-vpnweb-vpnweb"
The gateways are pulled from the hosts file for every host that is in the openvpn group.
There is a template in config/roles/vpnweb/templates/eip-config.json.j2 which simply does:
{{ simplevpn_result.eip_config | tojson }}
The simplevpn module is located in plugins/action/simplevpn.py:
def produceEipConfig(config, obfs4_state_dir, public_domain, transports):
if obfs4_state_dir:
obfs4_cert = open(
obfs4_state_dir + '/obfs4_cert.txt').read().rstrip()
transports = patchObfs4Cert(transports, obfs4_cert)
# Build the JSON data structure that needs to end up in eip-service.json.
eip_config = {
"serial": 3,
"version": 3,
"locations": config.locations,
"gateways": [{
"host": "%s.%s" % (v["inventory_hostname"], public_domain),
"ip_address": v["ip"],
"location": v.get("location", "Unknown"),
"capabilities": {
"adblock": False,
"filter_dns": False,
"limited": False,
"transport": transports,
},
} for v in config.gateways],
"openvpn_configuration": config.openvpn,
}
# Instead of calling the template here, we just return the
# 'config' object so that Ansible can use it with its own template
# module.
return eip_config
This gateways block pulls things from float/hosts.yml:
hosts:
floatapp1:
ansible_host: 37.218.241.85
groups: [backend]
ip: 37.218.241.85
ip_vpn0: 172.16.1.1
floatrp1:
ansible_host: 37.218.241.84
groups: [frontend]
ip: 37.218.241.84
ip_vpn0: 172.16.1.2
location: Seattle
group_vars:
all:
ansible_user: root
ansible_become: false
testing: false
So the ip_address is just added to hosts.yml as 'gateway_address', and we change simplevpn.py to use that instead.
- Documentation detailing why this is needed, and how it works