From e3655b5115c7dd5bf5e9ae0e3ffdca69e5c89135 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:07:00 -0700 Subject: [PATCH 01/12] init: Move upstart file to init directory * No functional changes. --- upstart.init => init/upstart.init | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename upstart.init => init/upstart.init (100%) diff --git a/upstart.init b/init/upstart.init similarity index 100% rename from upstart.init rename to init/upstart.init From 6aca273d89ed4c72ea556a0a7425f4f0c30c8602 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:07:04 -0700 Subject: [PATCH 02/12] getclient: Use openssl to prune comments * The EasyRSA tools create a certificate file with all the metadata readable. This makes the config file larger then it needs to be, so prune it. * Retrieve text files with `openssl x509 -in -noout -text` --- bin/ovpn_getclient | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ovpn_getclient b/bin/ovpn_getclient index e9dc01f..4d57a27 100755 --- a/bin/ovpn_getclient +++ b/bin/ovpn_getclient @@ -45,7 +45,7 @@ remote $OVPN_CN $OVPN_PORT $OVPN_PROTO $(cat $EASYRSA_PKI/private/${cn}.key) -$(cat $EASYRSA_PKI/issued/${cn}.crt) +$(openssl x509 -in $EASYRSA_PKI/issued/${cn}.crt) $(cat $EASYRSA_PKI/ca.crt) From e6f79043448a059ac1fe2f0accf5cd71351ad394 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:07:06 -0700 Subject: [PATCH 03/12] run: Add IPv6 forwarding if default route * Enable IPv6 forwarding if docker daemon provided a default route * For now this requires the --privileged flag, but this could be hacked around using `ip netns` madness. --- bin/ovpn_run | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bin/ovpn_run b/bin/ovpn_run index 5a2c95a..b58e82e 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -43,6 +43,16 @@ if [ -r "$EASYRSA_PKI/crl.pem" ]; then ARGS=("--crl-verify" "$OPENVPN/crl.pem") fi +ip -6 route show default 2>/dev/null +if [ $? = 0 ]; then + echo "Enabling IPv6 Forwarding" + # If this fails, ensure the docker container is run with --privileged + # Could be side stepped with `ip netns` madness to drop privileged flag + + sysctl net.ipv6.conf.default.forwarding=1 + sysctl net.ipv6.conf.all.forwarding=1 +fi + if [ "$#" -gt 0 ]; then exec openvpn "$@" else From 9c8d195880d8fe262c5dbf282590e4257f1ab564 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:07:08 -0700 Subject: [PATCH 04/12] init: Add docker-openvpn systemd service file * Works with IPv6 thanks to ExecStartPost. --- init/docker-openvpn.service | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 init/docker-openvpn.service diff --git a/init/docker-openvpn.service b/init/docker-openvpn.service new file mode 100644 index 0000000..31e9b40 --- /dev/null +++ b/init/docker-openvpn.service @@ -0,0 +1,30 @@ +[Unit] +Description=OpenVPN Docker Container +Documentation=https://github.com/kylemanna/docker-openvpn +After=network.target docker.socket +Requires=docker.socket + +[Service] +# Modify IP6_PREFIX to match network config +Environment="IP6_PREFIX=2001:db8::/64" +Environment="OVPN_NAME=openvpn0" +Environment="OVPN_DATA=ovpn-data" + +# Clean-up previous bad states +ExecStartPre=-/usr/bin/docker rm -f openvpn0 + +# Ensure forwarding is enabled on host's networking stack (hacky) +ExecStartPre=/sbin/sysctl net.ipv6.conf.default.forwarding=1 +ExecStartPre=/sbin/sysctl net.ipv6.conf.all.forwarding=1 + +# Main process +ExecStart=/usr/bin/docker run --rm --privileged --volumes-from $OVPN_DATA --name $OVPN_NAME -p 1194:1194/udp kylemanna/openvpn:dev ovpn_run --config openvpn.conf --server-ipv6 $IP6_PREFIX + +# Add static route for IPv6 after it starts up +ExecStartPost=/bin/sh -c "sleep 1; ip route replace $IP6_PREFIX via $(docker inspect -f '{{ .NetworkSettings.GlobalIPv6Address }}' $OVPN_NAME ) dev docker0" + +# Clean-up +ExecStopPost=-/sbin/ip route del $IP6_PREFIX dev docker0 + +[Install] +WantedBy=multi-user.target From 56a8e735b6fa5e1163365b6ce62f66016ff5521e Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:28:44 -0700 Subject: [PATCH 05/12] docs: ipv6: Add initial development guide * Work in progress. --- docs/ipv6.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/ipv6.md diff --git a/docs/ipv6.md b/docs/ipv6.md new file mode 100644 index 0000000..b015136 --- /dev/null +++ b/docs/ipv6.md @@ -0,0 +1,74 @@ +# IPv6 Support + +This is a work in progress, more polish to follow. Use the `dev` git branch and `dev` docker image tag for testing. + +## Tunnel IPv6 Address To OpenVPN Clients + +This feature is advanced and recommended only for those who already have a functioning IPv4 tunnel and know how IPv6 works. + +Systemd is used to setup a static route and Debian 8.1 or later is recommended as the host distribution. Others probably work, but haven't been tested. + +### Step 1 — Setup IPv6 on the Host Machine + +The tutorial uses a free tunnel from [tunnelbroker.net](https://tunnelbroker.net/) to get a /64 and /48 prefix allocated to me. The tunnel endpoint is less then 3 ms away from Digital Ocean's San Francisco datacenter. + +Place the following in `/etc/network/interfaces`. Relace `PUBLIC_IP` with your host's public IPv4 address and replace 2001:db8::2 and 2001:db8::1 with the corresponding tunnel endpoints: + + auto he-ipv6 + iface he-ipv6 inet6 v4tunnel + address 2001:db8::2 + netmask 64 + endpoint 72.52.104.74 + local PUBLIC_IP + ttl 255 + gateway 2001:db8::1 + +Bring the interface up: + + ifup he-ipv6 + +Test that IPv6 works on the host: + + ping6 google.com + +If this doesn't work, figure it out. It may be necessary to add an firewall rule to allow IP protocol 41 through the firewall. + +### Step 2 — Setup the systemd Unit File + +Copy the systemd init file from the docker-openvpn /init directory of the repository and install into `/etc/systemd/system/docker-openvpn.conf` + +Edit the file, replace `IP6_PREFIX` value with the value of your /64 prefix. + +Finally, reload systemd so the changes take affect: + + systemctl daemon-reload + +### Step 3 — Start OpenVPN + +Ensure that OpenVPN has been initialized and configured as described in the top level `README.md`. + +Start the systemd service file: + + systemctl start docker-openvpn + +Verify logs if needed: + + systemctl status docker-openvpn + docker logs openvpn0 + +### Step 4 — Modify Client Config for IPv6 Default Route + +Append the default route for the public Internet: + + echo "route-ipv6 2000::/3" >> clientname.ovpn + +### Step 5 — Start up Client + +If all went according to plan, then `ping6 2600::` and `ping6 google.com` should work. + +Fire up a web browser and attempt to navigate to [https://ipv6.google.com](https://ipv6.google.com). + + +## Connect to the OpenVPN Server Over IPv6 + +Not implemented, yet. From 155c4d4b904033b23ad45c040e989c7554dbfd8e Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:46:30 -0700 Subject: [PATCH 06/12] docs: docker: Crash course on installation * Nothing less nothing more. --- docs/docker.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 docs/docker.md diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..0538b16 --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,48 @@ +# Install Latest Docker Service + +Docker included with some distributions lags far behind upstream. This guide aims to provide a quick and reliable way to install or update it. + +It is recommended to use platforms that support systemd as future versions of this docker image may require systemd to help with some tasks: + +* Fedora +* Debian 8.1+ + +## Debian / Ubuntu + +### Step 1 — Set Up Docker + +Docker is moving fast and Debian / Ubuntu's long term support (LTS) policy doesn't keep up. To work around this we'll install a PPA that will get us the latest version of Docker. + +Add the upstream Docker repository package signing key. The apt-key command uses elevated privileges via sudo, so a password prompt for the user's password may appear: + + curl https://get.docker.io/gpg | sudo apt-key add - + +Add the upstream Docker repository to the system list: + + echo deb http://get.docker.io/ubuntu docker main | sudo tee /etc/apt/sources.list.d/docker.list + +Update the package list and install the Docker package: + + sudo apt-get update && sudo apt-get install -y lxc-docker + +Add your user to the `docker` group to enable communication with the Docker daemon as a normal user, where `$USER` is your username. Exit and log in again for the new group to take effect: + + sudo usermod -aG docker $USER + +After **re-logging in** verify the group membership using the id command. The expected response should include docker like the following example: + + uid=1001(test0) gid=1001(test0) groups=1001(test0),27(sudo),999(docker) + +### Step 2 — Test Docker + +Run a Debian jessie docker container: + + docker run --rm -it debian:jessie bash -l + +Once inside the container you'll see the `root@:/#` prompt signifying that the current shell is in a Docker container. To confirm that it's different from the host, check the version of Debian running in the container: + + cat /etc/issue.net + +Expected result: + + Debian GNU/Linux jessie/sid From 0edc11b58572a187c327c6b79839dcb51a326f97 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 21:51:20 -0700 Subject: [PATCH 07/12] docs: docker: Install apt dependencies * Otherwise it's annoying without it. --- docs/docker.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/docker.md b/docs/docker.md index 0538b16..2313504 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -13,13 +13,17 @@ It is recommended to use platforms that support systemd as future versions of th Docker is moving fast and Debian / Ubuntu's long term support (LTS) policy doesn't keep up. To work around this we'll install a PPA that will get us the latest version of Docker. +Ensure dependencies are installed: + + sudo apt-get update && sudo apt-get install -y apt-transport-https curl + Add the upstream Docker repository package signing key. The apt-key command uses elevated privileges via sudo, so a password prompt for the user's password may appear: curl https://get.docker.io/gpg | sudo apt-key add - Add the upstream Docker repository to the system list: - echo deb http://get.docker.io/ubuntu docker main | sudo tee /etc/apt/sources.list.d/docker.list + echo deb https://get.docker.io/ubuntu docker main | sudo tee /etc/apt/sources.list.d/docker.list Update the package list and install the Docker package: @@ -45,4 +49,4 @@ Once inside the container you'll see the `root@:/#` prompt signify Expected result: - Debian GNU/Linux jessie/sid + Debian GNU/Linux 8 From 017580fdaa236a6a92a96b3498da8501d80481a0 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sun, 5 Jul 2015 22:11:19 -0700 Subject: [PATCH 08/12] docs: ipv6: Add section enabling Docker IPv6 * Oops, doesn't work without this. --- docs/ipv6.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/ipv6.md b/docs/ipv6.md index b015136..0916d10 100644 --- a/docs/ipv6.md +++ b/docs/ipv6.md @@ -8,6 +8,7 @@ This feature is advanced and recommended only for those who already have a funct Systemd is used to setup a static route and Debian 8.1 or later is recommended as the host distribution. Others probably work, but haven't been tested. + ### Step 1 — Setup IPv6 on the Host Machine The tutorial uses a free tunnel from [tunnelbroker.net](https://tunnelbroker.net/) to get a /64 and /48 prefix allocated to me. The tunnel endpoint is less then 3 ms away from Digital Ocean's San Francisco datacenter. @@ -33,17 +34,33 @@ Test that IPv6 works on the host: If this doesn't work, figure it out. It may be necessary to add an firewall rule to allow IP protocol 41 through the firewall. -### Step 2 — Setup the systemd Unit File -Copy the systemd init file from the docker-openvpn /init directory of the repository and install into `/etc/systemd/system/docker-openvpn.conf` +### Step 2 — Update Docker's Init To Enable IPv6 Support + +Copy the system's existing docker file and append the `--ipv6` argument to the end of the command line: + + sed -e 's:^\(ExecStart.*\):\1 --ipv6:' /lib/systemd/system/docker.service | tee /etc/systemd/system/docker.service + +Reload the daemon and restart docker so that it takes affect: + + systemctl daemon-reload && systemctl restart docker.service + + +### Step 3 — Setup the systemd Unit File + +Copy the systemd init file from the docker-openvpn /init directory of the repository and install into `/etc/systemd/system/docker-openvpn.service` + + curl -o /etc/systemd/system/docker-openvpn.service https://raw.githubusercontent.com/kylemanna/docker-openvpn/dev/init/docker-openvpn.service Edit the file, replace `IP6_PREFIX` value with the value of your /64 prefix. + vi /etc/systemd/system/docker-openvpn.service + Finally, reload systemd so the changes take affect: systemctl daemon-reload -### Step 3 — Start OpenVPN +### Step 4 — Start OpenVPN Ensure that OpenVPN has been initialized and configured as described in the top level `README.md`. From 08d8116e31a97a91466edd24c39a85a0cb33f2c4 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Mon, 6 Jul 2015 08:55:42 -0700 Subject: [PATCH 09/12] docs: faq: How do I edit `openvpn.conf`? * It gets asked too many times. --- docs/faqs.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/faqs.md b/docs/faqs.md index 4805836..7ed633d 100644 --- a/docs/faqs.md +++ b/docs/faqs.md @@ -1,5 +1,12 @@ # Frequently Asked Questions +## How do I edit `openvpn.conf`? + +Use a Docker image with a text editor pre-installed (i.e. Ubuntu) and connect the volume container: + + docker run --volumes-from $OVPN_DATA --rm -it ubuntu vi /etc/openvpn/openvpn.conf + + ## Why not keep everything in one image? The run-time image (`kylemanna/openvpn`) is intended to be an ephemeral image. Nothing should be saved in it so that it can be re-downloaded and re-run when updates are pushed (i.e. newer version of OpenVPN or even Debian). The data container contains all this data and is attached at run time providing a safe home. From 313d1e756c8aea02f2e027ed08e55063fa24d89b Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sat, 11 Jul 2015 08:31:58 -0700 Subject: [PATCH 10/12] init: Update init file to be a template * Useful for systems with several OpenVPN docker containers running. --- init/docker-openvpn.service | 30 ------------------------- init/docker-openvpn@.service | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 30 deletions(-) delete mode 100644 init/docker-openvpn.service create mode 100644 init/docker-openvpn@.service diff --git a/init/docker-openvpn.service b/init/docker-openvpn.service deleted file mode 100644 index 31e9b40..0000000 --- a/init/docker-openvpn.service +++ /dev/null @@ -1,30 +0,0 @@ -[Unit] -Description=OpenVPN Docker Container -Documentation=https://github.com/kylemanna/docker-openvpn -After=network.target docker.socket -Requires=docker.socket - -[Service] -# Modify IP6_PREFIX to match network config -Environment="IP6_PREFIX=2001:db8::/64" -Environment="OVPN_NAME=openvpn0" -Environment="OVPN_DATA=ovpn-data" - -# Clean-up previous bad states -ExecStartPre=-/usr/bin/docker rm -f openvpn0 - -# Ensure forwarding is enabled on host's networking stack (hacky) -ExecStartPre=/sbin/sysctl net.ipv6.conf.default.forwarding=1 -ExecStartPre=/sbin/sysctl net.ipv6.conf.all.forwarding=1 - -# Main process -ExecStart=/usr/bin/docker run --rm --privileged --volumes-from $OVPN_DATA --name $OVPN_NAME -p 1194:1194/udp kylemanna/openvpn:dev ovpn_run --config openvpn.conf --server-ipv6 $IP6_PREFIX - -# Add static route for IPv6 after it starts up -ExecStartPost=/bin/sh -c "sleep 1; ip route replace $IP6_PREFIX via $(docker inspect -f '{{ .NetworkSettings.GlobalIPv6Address }}' $OVPN_NAME ) dev docker0" - -# Clean-up -ExecStopPost=-/sbin/ip route del $IP6_PREFIX dev docker0 - -[Install] -WantedBy=multi-user.target diff --git a/init/docker-openvpn@.service b/init/docker-openvpn@.service new file mode 100644 index 0000000..abd6100 --- /dev/null +++ b/init/docker-openvpn@.service @@ -0,0 +1,43 @@ +[Unit] +Description=OpenVPN Docker Container +Documentation=https://github.com/kylemanna/docker-openvpn +After=network.target docker.socket +Requires=docker.socket + +[Service] +RestartSec=10 +Restart=always + +# Modify IP6_PREFIX to match network config +#Environment="IP6_PREFIX=2001:db8::/64" +#Environment="ARGS=--config openvpn.conf --server-ipv6 2001:db8::/64" +Environment="NAME=ovpn-%i" +Environment="DATA_VOL=ovpn-data-%i" +Environment="IMG=kylemanna/openvpn:dev" +Environment="PORT=1194:1194/udp" + +# Override defaults in env file +EnvironmentFile=-/etc/default/docker-openvpn-%i + +# Clean-up bad state if still hanging around +ExecStartPre=-/usr/bin/docker rm -f $NAME + +# Attempt to pull new image for security updates +ExecStartPre=-/usr/bin/docker pull $IMG + +# IPv6: Ensure forwarding is enabled on host's networking stack (hacky) +# Would be nice to use systemd-network on the host, but this doens't work +# http://lists.freedesktop.org/archives/systemd-devel/2015-June/032762.html +ExecStartPre=/bin/sh -c 'test -z "$IP6_PREFIX" && exit 0; sysctl net.ipv6.conf.all.forwarding=1' + +# Main process +ExecStart=/usr/bin/docker run --rm --privileged --volumes-from ${DATA_VOL}:ro --name ${NAME} -p ${PORT} ${IMG} ovpn_run $ARGS + +# IPv6: Add static route for IPv6 after it starts up +ExecStartPost=/bin/sh -c 'test -z "${IP6_PREFIX}" && exit 0; sleep 1; ip route replace ${IP6_PREFIX} via $(docker inspect -f "{{ .NetworkSettings.GlobalIPv6Address }}" $NAME ) dev docker0' + +# IPv6: Clean-up +ExecStopPost=/bin/sh -c 'test -z "$IP6_PREFIX" && exit 0; ip route del $IP6_PREFIX dev docker0' + +[Install] +WantedBy=multi-user.target From 5a1e64217768b7d29bd725eafa8ec391db6f595e Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Sat, 11 Jul 2015 08:50:24 -0700 Subject: [PATCH 11/12] init: systemd: Use systemd style config overrides * RIP hacky /etc/default/foo style environement sourcing hack --- init/docker-openvpn@.service | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/init/docker-openvpn@.service b/init/docker-openvpn@.service index abd6100..f855e94 100644 --- a/init/docker-openvpn@.service +++ b/init/docker-openvpn@.service @@ -16,8 +16,9 @@ Environment="DATA_VOL=ovpn-data-%i" Environment="IMG=kylemanna/openvpn:dev" Environment="PORT=1194:1194/udp" -# Override defaults in env file -EnvironmentFile=-/etc/default/docker-openvpn-%i +# To override environment variables, use local configuration directory: +# /etc/systemd/system/docker-openvpn@foo.d/local.conf +# http://www.freedesktop.org/software/systemd/man/systemd.unit.html # Clean-up bad state if still hanging around ExecStartPre=-/usr/bin/docker rm -f $NAME From 34d9601e6ebed24aed2ac18840e113b5aac204b9 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Mon, 27 Jul 2015 20:20:46 -0700 Subject: [PATCH 12/12] ovpn_run: Assume /etc/openvpn is read-only * Systemd service currently marks the mount as read-only, and this is regarded as good practice for server/daemon only operation. * Don't create /etc/openvpn/ccd as the mount may be read-only. * Append the client-config-dir command line argument if it is found to avoid mkdir operation. * Mount can easily be modified using a different docker run line with ":ro" on the volume mount. --- bin/ovpn_genconfig | 2 -- bin/ovpn_run | 11 +++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/ovpn_genconfig b/bin/ovpn_genconfig index 894133d..974c344 100755 --- a/bin/ovpn_genconfig +++ b/bin/ovpn_genconfig @@ -171,8 +171,6 @@ port 1194 dev tun0 status /tmp/openvpn-status.log -client-config-dir $OPENVPN/ccd - user nobody group nogroup EOF diff --git a/bin/ovpn_run b/bin/ovpn_run index b58e82e..b91da3a 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -10,6 +10,9 @@ fi set -e +# Build runtime arguments array based on environment +ARGS=("--config" "$OPENVPN/openvpn.conf") + source "$OPENVPN/ovpn_env.sh" mkdir -p /dev/net @@ -17,8 +20,8 @@ if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200 fi -if [ ! -d "$OPENVPN/ccd" ]; then - mkdir -p /etc/openvpn/ccd +if [ -d "$OPENVPN/ccd" ]; then + ARGS+=("--client-config-dir" "$OPENVPN/ccd") fi # Setup NAT forwarding if requested @@ -40,7 +43,7 @@ if [ -r "$EASYRSA_PKI/crl.pem" ]; then ln "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem" chmod 644 "$OPENVPN/crl.pem" fi - ARGS=("--crl-verify" "$OPENVPN/crl.pem") + ARGS+=("--crl-verify" "$OPENVPN/crl.pem") fi ip -6 route show default 2>/dev/null @@ -56,5 +59,5 @@ fi if [ "$#" -gt 0 ]; then exec openvpn "$@" else - exec openvpn ${ARGS[@]} --config "$OPENVPN/openvpn.conf" + exec openvpn ${ARGS[@]} fi