Recently I am experiment on HMA. I currently have a service on AWS ECS, and I want it to observe through VPN so I can see difference result from other area.

Idea

The first thing I have think of is get a VPN and route the traffic through it. HMA is a great VPN provider and their support is really helpful.

Challenge

The two main challenge is how do I connect to VPN programmatically while most of VPN provide client but not for server and how can I connect to the service after it connect to VPN and it will wipe out its original IP.

Solution

solution-diagram

Step by Step

Let's do it step by step. First, connect to HMA.

Prerequisite:

  1. Account of HMA(you can get full return on first month if it is not fit for you).

  2. Docker installed(for local development), AWS account(so you can use ECS).

  3. You will need a docker registry if your will deploy nginx service on AWS ECS.

Connect to HMA

I have these two script in node service container in order to connect to HMA. (My node service run Ubuntu).

The HMA_prepare.sh will download everything that HMA need. (2016-MAY-1, HMA's linux.zip has old cert key and it will not work, I have notify HMA to update the link and will let you guys know when it is ready.)

#HMA_prepare.sh
#!/usr/bin/env bash

apt-get update

apt-get install sudo

#expect is for programmatically enter username
#and password
printf 'y' | apt-get install expect

#install openVPN
printf 'y' | apt-get install openvpn curl unzip dnsmasq-base wget

mkdir /opt/hma/

wget http://vpn.hidemyass.com/linux.zip

#Add execution permission to hma-start
chmod +x /opt/hma/hma-start

#go back to /app
cd /app

#Create node for VPN connection
mkdir /dev/net/

mknod /dev/net/tun c 10 200

#Execute expect script to enter username 
#and password
/usr/bin/expect /app/scripts/HMA_connect.sh $HMA_USERNAME $HMA_PASSWORD $HMA_HOST

The expect script below will enter your HMA host, username and password. It is sad that Docker's env file don't support environment variable with space. So you will need to use environments in docker-compose.yml or -e in docker run command

#HMA_connect.sh
#!/usr/bin/expect

set HMA_USERNAME [lindex $argv 0]
set HMA_PASSWORD [lindex $argv 1]
set HMA_HOST [lindex $argv 2]

set timeout 20

spawn "/opt/hma/hma-start" "$HMA_HOST"

expect "Enter Auth Username:"
send "$HMA_USERNAME\n"

expect "Enter Auth Password:"
send "$HMA_PASSWORD\n"

expect

Nginx configuration

The reason I use nginx here is because after my node service connect to VPN, its ip will be changed. This mean you cannot find node service by http://docker_machine_ip:node_service_port or http://AWS_ECS_node_service_public_IP:node_service_port. Also, in my experiment, linking is not working either.

One of the work around is using nginx to reroute traffic to docker-machine's ip or private ip in AWS. Which will become the architecture image above.

Here is my nginx.conf.

events {
   worker_connections 1024;
 }

 http {
   server {
     listen 8080;
     location / {
       proxy_pass http://docker_machine_ip:your_serivce_port;
#http://AWS_ECS_private_IP:your_service_port
     }
   }
 }

It is sad again nginx.conf don't accept environment variable. But there might have some work around.

If you will run this nginx in AWS container service, there is one thing you need to know. If you manually config nginx after container service start, AWS will consider it as unhealthy and restart the task. Then your hard work will gone. My suggestion will be build your nginx image and push to your registry and use it in container service.

Docker configuration

In order to use VPN, you need to config your docker container. As the docker-compose.yml.

node-service:
  build: .
  ports:
    - "some-port:expose-port"
  env_file:
    #path to vpn.env
    - ./vpn.env
  environments:
    - HMA_HOST: 'A_HMA_Host'
  cap_add:
    #add ability to networking
    - NET_ADMIN
  #add google DNS
  dns: 8.8.8.8
  container_name: node-service

hma-nginx:
  build: ../hma-nginx/
  ports:
    - "8080:8080"
  container_name: hma-nginx

If you want to deploy your service on AWS container service. You need to set the same configuration as above docker-compose.yml. Noted, there is no option in AWS for cap_add: NET_ADMIN, you can only check privileged to give full capability.

Conclusion

Your are all set and ready to use HMA with your service. HMA definitely is a good VPN provider. You can run /opt/hma/hma-start -l for list of hma host. But some of them is not working? It is good if they can fix it.