Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
98f9681d3e | |||
74ba753f70 | |||
cd8fd6afaa | |||
9ea4815a74 | |||
74bfad0aac | |||
ed51116fb6 | |||
eb22992a2f | |||
286676879d | |||
42bf842202 | |||
bd51bb273e | |||
70b70e298d | |||
95c260a97a | |||
35c9103454 | |||
d481313311 | |||
9b824fb35a | |||
7a9abf4c14 | |||
44055aa687 | |||
8356a664d8 | |||
ba7b925a9f | |||
517ad6aeb2 | |||
9c6f3311a1 | |||
dc4656ef48 | |||
e8d93ea4fa | |||
10dd404159 | |||
607063b358 | |||
bb3d1add3c | |||
c24a22deea | |||
6084261943 | |||
5ca92a2c5e | |||
dd719c1f11 | |||
6fcebf9adb | |||
86d2a52f85 | |||
1623afe651 | |||
e7d0d4ea0e | |||
e50f4dcc23 | |||
96d17bb5a7 | |||
f2111006ad | |||
d520a58ec4 | |||
1c290e60db | |||
2fa3abe064 | |||
2650d4a286 | |||
2abbcf1999 | |||
818e8682d1 | |||
3edc12a6b7 | |||
ded4414ef4 | |||
f277449569 | |||
edfbffb85f | |||
98cf2128c7 | |||
c3d526fd67 | |||
ba7860cced | |||
23f66094ff | |||
3da0efa5bc |
35
CONTRIBUTING.md
Normal file
35
CONTRIBUTING.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Contributing to docker-openvpn
|
||||
|
||||
Community contributions are welcome and help move the project along. Please review this document before sending any pull requests.
|
||||
|
||||
Thanks!
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
All bug fixes are welcome. Please try to add a test if the bug is something that should have been fixed already. Oops.
|
||||
|
||||
## Feature Additions
|
||||
|
||||
New features are welcome provided that the feature has a general audience and is reasonably simple. The goal of the repository is to support a wide audience and be simple enough.
|
||||
|
||||
Please add new documentation in the `docs` folder for any new features. Pull requests for missing documentation is welcome as well. Keep the `README.md` focused on the most popular use case, details belong in the docs directory.
|
||||
|
||||
If you have a special feature, you're likely to try but it will likely be rejected if not too many people seem interested.
|
||||
|
||||
## Tests
|
||||
|
||||
In an effort to not repeat bugs (and break less popular features), unit tests are run on [Travis CI](https://travis-ci.org/kylemanna/docker-openvpn). The goal of the tests are to be simple and to be placed in the `tests` directory where it will be automatically run. Review existing tests for an example.
|
||||
|
||||
## Style
|
||||
|
||||
The style of the repo follows that of the Linux kernel, in particular:
|
||||
|
||||
* Pull requests should be rebased to small atomic commits so that the merged history is more coherent
|
||||
* The subject of the commit should be in the form "<subsystem>: <subject>"
|
||||
* More details in the body
|
||||
* Match surrounding coding style (line wrapping, spaces, etc)
|
||||
|
||||
More details in the [SubmittingPatches](https://www.kernel.org/doc/Documentation/SubmittingPatches) document included with the Linux kernel. In particular the following sections:
|
||||
|
||||
* `2) Describe your changes`
|
||||
* `3) Separate your changes`
|
21
Dockerfile
21
Dockerfile
@ -1,21 +1,19 @@
|
||||
# Original credit: https://github.com/jpetazzo/dockvpn
|
||||
|
||||
# Leaner build then Ubunutu
|
||||
FROM debian:jessie
|
||||
# Smallest base image
|
||||
FROM alpine:3.2
|
||||
|
||||
MAINTAINER Kyle Manna <kyle@kylemanna.com>
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y openvpn iptables curl && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN mkdir -p /usr/local/share/easy-rsa && \
|
||||
curl -L https://github.com/OpenVPN/easy-rsa/archive/v3.0.0.tar.gz | tar xzf - --strip=1 -C /usr/local/share/easy-rsa easy-rsa-3.0.0/easyrsa3 && \
|
||||
ln -s /usr/local/share/easy-rsa/easyrsa3/easyrsa /usr/local/bin
|
||||
RUN echo "http://dl-4.alpinelinux.org/alpine/edge/community/" >> /etc/apk/repositories && \
|
||||
echo "http://dl-4.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories && \
|
||||
apk add --update openvpn iptables bash easy-rsa openvpn-auth-pam google-authenticator pamtester && \
|
||||
ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \
|
||||
rm -rf /tmp/* /var/tmp/* /var/cache/apk/*
|
||||
|
||||
# Needed by scripts
|
||||
ENV OPENVPN /etc/openvpn
|
||||
ENV EASYRSA /usr/local/share/easy-rsa/easyrsa3
|
||||
ENV EASYRSA /usr/share/easy-rsa
|
||||
ENV EASYRSA_PKI $OPENVPN/pki
|
||||
ENV EASYRSA_VARS_FILE $OPENVPN/vars
|
||||
|
||||
@ -29,3 +27,6 @@ CMD ["ovpn_run"]
|
||||
|
||||
ADD ./bin /usr/local/bin
|
||||
RUN chmod a+x /usr/local/bin/*
|
||||
|
||||
# Add support for OTP authentication using a PAM module
|
||||
ADD ./otp/openvpn /etc/pam.d/
|
||||
|
26
README.md
26
README.md
@ -1,6 +1,10 @@
|
||||
# OpenVPN for Docker
|
||||
|
||||
[](https://travis-ci.org/kylemanna/docker-openvpn)
|
||||
[](https://hub.docker.com/r/kylemanna/openvpn/)
|
||||
[](https://hub.docker.com/r/kylemanna/openvpn/)
|
||||
[](https://hub.docker.com/r/kylemanna/openvpn/)
|
||||
[](https://hub.docker.com/r/kylemanna/openvpn/)
|
||||
|
||||
OpenVPN server in a Docker container complete with an EasyRSA PKI CA.
|
||||
|
||||
@ -9,7 +13,7 @@ a corresponding [Digital Ocean Community Tutorial](http://bit.ly/1AGUZkq).
|
||||
|
||||
#### Upstream Links
|
||||
|
||||
* Docker Registry @ [kylemanna/openvpn](https://registry.hub.docker.com/u/kylemanna/openvpn)
|
||||
* Docker Registry @ [kylemanna/openvpn](https://hub.docker.com/r/kylemanna/openvpn/)
|
||||
* GitHub @ [kylemanna/docker-openvpn](https://github.com/kylemanna/docker-openvpn)
|
||||
|
||||
#### Example Service
|
||||
@ -45,9 +49,21 @@ a corresponding [Digital Ocean Community Tutorial](http://bit.ly/1AGUZkq).
|
||||
|
||||
docker run --volumes-from $OVPN_DATA --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
* Create an environment variable with the name DEBUG and value of 1 to enable debug output (using "docker -e").
|
||||
|
||||
docker run --volumes-from $OVPN_DATA -d -p 1194:1194/udp --privileged -e DEBUG=1 kylemanna/openvpn
|
||||
docker run --volumes-from $OVPN_DATA -p 1194:1194/udp --privileged -e DEBUG=1 kylemanna/openvpn
|
||||
|
||||
* Test using a client that has openvpn installed correctly
|
||||
|
||||
$ openvpn --config CLIENTNAME.ovpn
|
||||
|
||||
* Run through a barrage of debugging checks on the client if things don't just work
|
||||
|
||||
$ ping 8.8.8.8 # checks connectivity without touching name resolution
|
||||
$ dig google.com # won't use the search directives in resolv.conf
|
||||
$ nslookup google.com # will use search
|
||||
|
||||
## How Does It Work?
|
||||
|
||||
@ -75,6 +91,7 @@ Conveniently, `kylemanna/openvpn` comes with a script called `ovpn_getclient`,
|
||||
which dumps an inline OpenVPN client configuration file. This single file can
|
||||
then be given to a client for access to the VPN.
|
||||
|
||||
To enable Two Factor Authentication for clients (a.k.a. OTP) see [this document](/docs/otp.md).
|
||||
|
||||
## OpenVPN Details
|
||||
|
||||
@ -167,3 +184,8 @@ of a guarantee in the future.
|
||||
* OpenVPN core 3.0 android armv7a thumb2 32-bit
|
||||
* OS X Mavericks with Tunnelblick 3.4beta26 (build 3828) using openvpn-2.3.4
|
||||
* ArchLinux OpenVPN pkg 2.3.4-1
|
||||
*
|
||||
|
||||
## Having permissions issues with Selinux enabled?
|
||||
|
||||
See [this](docs/selinux.md)
|
||||
|
@ -37,17 +37,21 @@ usage() {
|
||||
echo " [-s SERVER_SUBNET]"
|
||||
echo " [-r ROUTE ...]"
|
||||
echo " [-p PUSH ...]"
|
||||
echo " [-n DNS_SERVER ...]"
|
||||
echo
|
||||
echo "optional arguments:"
|
||||
echo " -d Disable NAT routing and default route"
|
||||
echo " -c Enable client-to-client option"
|
||||
echo " -D Disable built in external dns (google dns)"
|
||||
echo " -D Do not push dns servers"
|
||||
echo " -N Configure NAT to access external server network"
|
||||
echo " -m Set client MTU"
|
||||
echo " -t Use TAP device (instead of TUN device)"
|
||||
echo " -T Encrypt packets with the given cipher algorithm instead of the default one (tls-cipher)."
|
||||
echo " -C A list of allowable TLS ciphers delimited by a colon (cipher)."
|
||||
echo " -a Authenticate packets with HMAC using the given message digest algorithm (auth)."
|
||||
echo " -z Enable comp-lzo compression."
|
||||
echo " -2 Enable two factor authentication using Google Authenticator."
|
||||
echo " -f Set the fragment directive."
|
||||
}
|
||||
|
||||
if [ "$DEBUG" == "1" ]; then
|
||||
@ -67,6 +71,8 @@ OVPN_ROUTES=()
|
||||
TMP_ROUTES=()
|
||||
OVPN_PUSH=()
|
||||
TMP_PUSH=()
|
||||
OVPN_DNS_SERVERS=("8.8.8.8" "8.8.4.4")
|
||||
TMP_DNS_SERVERS=()
|
||||
OVPN_TLS_CIPHER=''
|
||||
OVPN_CIPHER=''
|
||||
OVPN_AUTH=''
|
||||
@ -75,7 +81,7 @@ OVPN_AUTH=''
|
||||
[ -r "$OVPN_ENV" ] && source "$OVPN_ENV"
|
||||
|
||||
# Parse arguments
|
||||
while getopts ":a:C:T:r:s:du:cp:DNm:t" opt; do
|
||||
while getopts ":a:C:T:r:s:du:cp:n:DNmf:tz2" opt; do
|
||||
case $opt in
|
||||
a)
|
||||
OVPN_AUTH="$OPTARG"
|
||||
@ -104,6 +110,9 @@ while getopts ":a:C:T:r:s:du:cp:DNm:t" opt; do
|
||||
p)
|
||||
TMP_PUSH+=("$OPTARG")
|
||||
;;
|
||||
n)
|
||||
TMP_DNS_SERVERS+=("$OPTARG")
|
||||
;;
|
||||
D)
|
||||
OVPN_DNS=0
|
||||
;;
|
||||
@ -116,6 +125,15 @@ while getopts ":a:C:T:r:s:du:cp:DNm:t" opt; do
|
||||
t)
|
||||
OVPN_DEVICE="tap"
|
||||
;;
|
||||
z)
|
||||
OVPN_COMP_LZO=1
|
||||
;;
|
||||
2)
|
||||
OVPN_OTP_AUTH=1
|
||||
;;
|
||||
f)
|
||||
OVPN_FRAGMENT=$OPTARG
|
||||
;;
|
||||
\?)
|
||||
set +x
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
@ -137,6 +155,9 @@ done
|
||||
# if new push directives were not defined with -p, use default
|
||||
[ ${#TMP_PUSH[@]} -gt 0 ] && OVPN_PUSH=("${TMP_PUSH[@]}")
|
||||
|
||||
# if dns servers were not defined with -n, use google nameservers
|
||||
[ ${#TMP_DNS_SERVERS[@]} -gt 0 ] && OVPN_DNS_SERVERS=("${TMP_DNS_SERVERS[@]}")
|
||||
|
||||
# Server name is in the form "udp://vpn.example.com:1194"
|
||||
if [[ "$OVPN_SERVER_URL" =~ ^((udp|tcp)://)?([0-9a-zA-Z\.\-]+)(:([0-9]+))?$ ]]; then
|
||||
OVPN_PROTO=${BASH_REMATCH[2]};
|
||||
@ -158,6 +179,9 @@ export OVPN_SERVER OVPN_ROUTES OVPN_DEFROUTE
|
||||
export OVPN_SERVER_URL OVPN_ENV OVPN_PROTO OVPN_CN OVPN_PORT
|
||||
export OVPN_CLIENT_TO_CLIENT OVPN_PUSH OVPN_NAT OVPN_DNS OVPN_MTU OVPN_DEVICE
|
||||
export OVPN_TLS_CIPHER OVPN_CIPHER OVPN_AUTH
|
||||
export OVPN_COMP_LZO
|
||||
export OVPN_OTP_AUTH
|
||||
export OVPN_FRAGMENT
|
||||
|
||||
# Preserve config
|
||||
if [ -f "$OVPN_ENV" ]; then
|
||||
@ -202,8 +226,13 @@ EOF
|
||||
[ -n "$OVPN_AUTH" ] && echo "auth $OVPN_AUTH" >> "$conf"
|
||||
|
||||
[ -n "$OVPN_CLIENT_TO_CLIENT" ] && echo "client-to-client" >> "$conf"
|
||||
[ "$OVPN_DNS" == "1" ] && echo push "dhcp-option DNS 8.8.4.4" >> "$conf"
|
||||
[ "$OVPN_DNS" == "1" ] && echo push "dhcp-option DNS 8.8.8.8" >> "$conf"
|
||||
[ -n "$OVPN_COMP_LZO" ] && echo "comp-lzo" >> "$conf"
|
||||
|
||||
[ -n "$OVPN_FRAGMENT" ] && echo "fragment $OVPN_FRAGMENT" >> "$conf"
|
||||
|
||||
[ "$OVPN_DNS" == "1" ] && for i in "${OVPN_DNS_SERVERS[@]}"; do
|
||||
echo "push dhcp-option DNS $i" >> "$conf"
|
||||
done
|
||||
# Append Routes
|
||||
for i in "${OVPN_ROUTES[@]}"; do
|
||||
# If user passed "0" skip this, assume no extra routes
|
||||
@ -216,6 +245,12 @@ for i in "${OVPN_PUSH[@]}"; do
|
||||
echo push \"$i\" >> "$conf"
|
||||
done
|
||||
|
||||
# Optional OTP authentication support
|
||||
if [ -n "$OVPN_OTP_AUTH" ]; then
|
||||
echo -e "\n\n# Enable OTP+PAM for user authentication" >> "$conf"
|
||||
echo "plugin /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn" >> "$conf"
|
||||
fi
|
||||
|
||||
set +e
|
||||
|
||||
# Clean-up duplicate configs
|
||||
|
@ -84,6 +84,15 @@ $OVPN_ADDITIONAL_CLIENT_CONFIG
|
||||
if [ -n "$OVPN_AUTH" ]; then
|
||||
echo "auth $OVPN_AUTH"
|
||||
fi
|
||||
|
||||
if [ -n "$OVPN_OTP_AUTH" ]; then
|
||||
echo "auth-user-pass"
|
||||
echo "auth-nocache"
|
||||
fi
|
||||
|
||||
if [ -n "$OVPN_COMP_LZO" ]; then
|
||||
echo "comp-lzo"
|
||||
fi
|
||||
}
|
||||
|
||||
dir="$OPENVPN/clients/$cn"
|
||||
|
33
bin/ovpn_otp_user
Executable file
33
bin/ovpn_otp_user
Executable file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Generate OpenVPN users via google authenticator
|
||||
#
|
||||
|
||||
if ! source "$OPENVPN/ovpn_env.sh"; then
|
||||
echo "Could not source $OPENVPN/ovpn_env.sh."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "x$OVPN_OTP_AUTH" != "x1" ]; then
|
||||
echo "OTP authentication not enabled, please regenerate configuration using -2 flag"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $1 ]; then
|
||||
echo "Usage: ovpn_otp_user USERNAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure the otp folder is present
|
||||
[ -d /etc/openvpn/otp ] || mkdir -p /etc/openvpn/otp
|
||||
|
||||
# Binary is present in image, save an $user.google_authenticator file in /etc/openvpn/otp
|
||||
if [ "$2" == "interactive" ]; then
|
||||
# Authenticator will ask for other parameters. User can choose rate limit, token reuse policy and time window policy
|
||||
# Always use time base OTP otherwise storage for counters must be configured somewhere in volume
|
||||
google-authenticator --time-based --force -l "${1}@${OVPN_CN}" -s /etc/openvpn/otp/${1}.google_authenticator
|
||||
else
|
||||
google-authenticator --time-based --disallow-reuse --force --rate-limit=3 --rate-time=30 --window-size=3 \
|
||||
-l "${1}@${OVPN_CN}" -s /etc/openvpn/otp/${1}.google_authenticator
|
||||
fi
|
@ -55,8 +55,8 @@ if [ $? = 0 ]; then
|
||||
# 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 || echo "Failed to enable IPv6 Forwarding default"
|
||||
sysctl net.ipv6.conf.all.forwarding=1 || echo "Failed to enable IPv6 Forwarding"
|
||||
sysctl -w net.ipv6.conf.default.forwarding=1 || echo "Failed to enable IPv6 Forwarding default"
|
||||
sysctl -w net.ipv6.conf.all.forwarding=1 || echo "Failed to enable IPv6 Forwarding"
|
||||
fi
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
|
10
docs/docker-openvpn.te
Normal file
10
docs/docker-openvpn.te
Normal file
@ -0,0 +1,10 @@
|
||||
module docker-openvpn 1.0;
|
||||
|
||||
require {
|
||||
type svirt_lxc_net_t;
|
||||
class tun_socket create;
|
||||
}
|
||||
|
||||
#============= svirt_lxc_net_t ==============
|
||||
allow svirt_lxc_net_t self:tun_socket create;
|
||||
|
@ -12,3 +12,9 @@ Use a Docker image with a text editor pre-installed (i.e. Ubuntu) and connect th
|
||||
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.
|
||||
|
||||
If it was all in one container, an upgrade would require a few steps to extract all the data, perform some upgrade import, and re-run. This technique is also prone to people losing their EasyRSA PKI when they forget where it was. With everything in the data container upgrading is as simple as re-running `docker pull kylemanna/openvpn` and then `docker run ... kylemanna/openvpn`.
|
||||
|
||||
## How do I set up a split tunnel?
|
||||
|
||||
Split tunnels are configurations where only some of the traffic from a client goes to the VPN, with the remainder routed through the normal non-VPN interfaces. You'll want to disable a default route (-d) when you generate the configuration, but still use NAT (-N) to keep network address translation enabled.
|
||||
|
||||
ovpn_genconfig -N -d ...
|
||||
|
72
docs/otp.md
Normal file
72
docs/otp.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Using two factor authentication for users
|
||||
|
||||
Instead of relying on complex passwords for client certificates (that usually get written somewhere) this image
|
||||
provides support for two factor authentication with OTP devices.
|
||||
|
||||
The most common app that provides OTP generation is Google Authenticator ([iOS](https://itunes.apple.com/it/app/google-authenticator/id388497605?mt=8) and
|
||||
[Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=it)) you can download it
|
||||
and use this image to generate user configuration.
|
||||
|
||||
## Usage
|
||||
|
||||
In order to enable two factor authentication the following steps are required.
|
||||
|
||||
* Generate server configuration with `-2` option
|
||||
|
||||
docker run --volumes-from $OVPN_DATA --rm fabn/openvpn ovpn_genconfig -u udp://vpn.example.com -2
|
||||
|
||||
* Generate your client certificate (possibly without a password since you're using OTP)
|
||||
|
||||
docker run --volumes-from $OVPN_DATA --rm -it fabn/openvpn easyrsa build-client-full <user> nopass
|
||||
|
||||
* Generate authentication configuration for your client. -t is needed to show QR code, -i is optional for interactive usage
|
||||
|
||||
docker run --volumes-from $OVPN_DATA --rm -t fabn/openvpn ovpn_otp_user <user>
|
||||
|
||||
The last step will generate OTP configuration for the provided user with the following options
|
||||
|
||||
```
|
||||
google-authenticator --time-based --disallow-reuse --force --rate-limit=3 --rate-time=30 --window-size=3 \
|
||||
-l "${1}@${OVPN_CN}" -s /etc/openvpn/otp/${1}.google_authenticator
|
||||
```
|
||||
|
||||
It will also show a shell QR code in terminal you can scan with the Google Authenticator application. It also provides
|
||||
a link to a google chart url that will display a QR code for the authentication.
|
||||
|
||||
**Do not share QR code (or generated url) with anyone but final user, that is your second factor for authentication
|
||||
that is used to generate OTP codes**
|
||||
|
||||
Here's an example QR code generated for an hypotetical user@example.com user.
|
||||
|
||||

|
||||
|
||||
Generate client configuration for `<user>` and import it in OpenVPN client. On connection it will prompt for user and password.
|
||||
Enter your username and a 6 digit code generated by Authenticator app and you're logged in.
|
||||
|
||||
## TL;DR
|
||||
|
||||
Under the hood this configuration will setup an `openvpn` PAM service configuration (`/etc/pam.d/openvpn`)
|
||||
that relies on the awesome [Google Authenticator PAM module](https://github.com/google/google-authenticator).
|
||||
In this configuration the `auth` part of PAM flow is managed by OTP codes and the `account` part is not enforced
|
||||
because you're likely dealing with virtual users and you do not want to create a system account for every VPN user.
|
||||
|
||||
`ovpn_otp_user` script will store OTP credentials under `/etc/openvpn/otp/<user>.google_authentication`. In this
|
||||
way when you take a backup OTP users are included as well.
|
||||
|
||||
Finally it will enable the openvpn plugin `openvpn-plugin-auth-pam.so` in server configuration and append the
|
||||
`auth-user-pass` directive in client configuration.
|
||||
|
||||
## Debug
|
||||
|
||||
If something is not working you can verify your PAM setup with these commands
|
||||
|
||||
```
|
||||
# Start a shell in container
|
||||
docker run --volumes-from $OVPN_DATA --rm -it fabn/openvpn bash
|
||||
# Then in container install pamtester utility
|
||||
apt-get update && apt-get install -y pamtester
|
||||
# To check authentication use this command that will prompt for a valid code from Authenticator APP
|
||||
pamtester -v openvpn <user> authenticate
|
||||
```
|
||||
|
||||
If you configured everything correctly you should get authenticated by entering a OTP code from the app.
|
25
docs/selinux.md
Normal file
25
docs/selinux.md
Normal file
@ -0,0 +1,25 @@
|
||||
# For hosts that use SELinux
|
||||
|
||||
Try this [policy file](docker-openvpn.te)
|
||||
|
||||
Run these commands to compile and load it:
|
||||
|
||||
```
|
||||
checkmodule -M -m -o docker-openvpn.mod docker-openvpn.te
|
||||
semodule_package -o docker-openvpn.pp -m docker-openvpn.mod
|
||||
sudo semodule -i docker-openvpn.pp
|
||||
```
|
||||
|
||||
Also, some configurations don't allow containers to load kernel modules, so on the host run this:
|
||||
|
||||
```
|
||||
sudo modprobe tun
|
||||
```
|
||||
|
||||
So the container doesn't have to load the `tun` module.
|
||||
|
||||
|
||||
# Still having issues?
|
||||
|
||||
In January 2016, Fedora based systems got an update that fixed an issue for labeling namespaced net objects under /proc
|
||||
to fix, make sure that you have run `sudo dnf update` and you need to reboot to load the new policies
|
18
docs/tcp.md
Normal file
18
docs/tcp.md
Normal file
@ -0,0 +1,18 @@
|
||||
# TCP Protocol
|
||||
|
||||
## TCP vs. UDP - Pros & Cons
|
||||
By default, OpenVPN is configured to use the UDP protocol. Because UDP incurs minimal protocol overhead (for example, no acknowledgment is required upon successful packet receipt), it can sometimes result in slightly faster throughput. However, in situations where VPN service is needed over an unreliable connection, the user experience can benefit from the extra diagnostic features of the TCP protocol.
|
||||
|
||||
As an example, users connecting from an airplane wifi network may experience high packet drop rates, where the error detection and sliding window control of TCP can more readily adjust to the inconsistent connection.
|
||||
|
||||
## Using TCP
|
||||
Those requiring TCP connections should initialize the data container by specifying the TCP protocol and port number:
|
||||
|
||||
docker run --volumes-from $OVPN_DATA --rm kylemanna/openvpn ovpn_genconfig -u tcp://VPN.SERVERNAME.COM:443
|
||||
docker run --volumes-from $OVPN_DATA --rm -it kylemanna/openvpn ovpn_initpki
|
||||
|
||||
Because the server container always exposes port 1194, regardless of the
|
||||
specified protocol, adjust the mapping appropriately:
|
||||
|
||||
docker run --volumes-from $OVPN_DATA -d -p 443:1194/tcp --cap-add=NET_ADMIN kylemanna/openvpn
|
||||
|
7
otp/openvpn
Normal file
7
otp/openvpn
Normal file
@ -0,0 +1,7 @@
|
||||
# Uses google authenticator library as PAM module using a single folder for all users tokens
|
||||
# User root is required to stick with an hardcoded user when trying to determine user id and allow unexisting system users
|
||||
# See https://github.com/google/google-authenticator/tree/master/libpam#secretpathtosecretfile--usersome-user
|
||||
auth required pam_google_authenticator.so secret=/etc/openvpn/otp/${USER}.google_authenticator user=root
|
||||
|
||||
# Accept any user since we're dealing with virtual users there's no need to have a system account (pam_unix.so)
|
||||
account sufficient pam_permit.so
|
55
tests/openvpn_conf_options.test.sh
Executable file
55
tests/openvpn_conf_options.test.sh
Executable file
@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
OVPN_DATA=opvn-data
|
||||
|
||||
IMG=kylemanna/openvpn
|
||||
|
||||
# Function to fail
|
||||
abort() { cat <<< "$@" 1>&2; exit 1; }
|
||||
|
||||
#
|
||||
# Create a docker container with the config data
|
||||
#
|
||||
sudo docker run --name $OVPN_DATA -v /etc/openvpn busybox
|
||||
|
||||
#
|
||||
# Generate openvpn.config file
|
||||
#
|
||||
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
|
||||
sudo docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_genconfig -u udp://$SERV_IP -f 1400
|
||||
|
||||
#
|
||||
# grep for config lines from openvpn.conf
|
||||
# add more tests for more configs as required
|
||||
#
|
||||
|
||||
# 1. verb config
|
||||
CONFIG_REQUIRED_VERB="verb 3"
|
||||
CONFIG_MATCH_VERB=$(sudo docker run --rm -it --volumes-from $OVPN_DATA busybox grep verb /etc/openvpn/openvpn.conf)
|
||||
|
||||
# 2. fragment config
|
||||
CONFIG_REQUIRED_FRAGMENT="fragment 1400"
|
||||
CONFIG_MATCH_FRAGMENT=$(sudo docker run --rm -it --volumes-from $OVPN_DATA busybox grep fragment /etc/openvpn/openvpn.conf)
|
||||
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
# sudo docker rm -f $OVPN_DATA
|
||||
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
|
||||
if [[ $CONFIG_MATCH_VERB =~ $CONFIG_REQUIRED_VERB ]]
|
||||
then
|
||||
echo "==> Config match found: $CONFIG_REQUIRED_VERB == $CONFIG_MATCH_VERB"
|
||||
else
|
||||
abort "==> Config match not found: $CONFIG_REQUIRED_VERB != $CONFIG_MATCH_VERB"
|
||||
fi
|
||||
|
||||
if [[ $CONFIG_MATCH_FRAGMENT =~ $CONFIG_REQUIRED_FRAGMENT ]]
|
||||
then
|
||||
echo "==> Config match found: $CONFIG_REQUIRED_FRAGMENT == $CONFIG_MATCH_FRAGMENT"
|
||||
else
|
||||
abort "==> Config match not found: $CONFIG_REQUIRED_FRAGMENT != $CONFIG_MATCH_FRAGMENT"
|
||||
fi
|
81
tests/otp.sh
Executable file
81
tests/otp.sh
Executable file
@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
set -ex
|
||||
OVPN_DATA=basic-data-otp
|
||||
CLIENT=travis-client
|
||||
IMG=kylemanna/openvpn
|
||||
OTP_USER=otp
|
||||
# Function to fail
|
||||
abort() { cat <<< "$@" 1>&2; exit 1; }
|
||||
|
||||
#
|
||||
# Create a docker container with the config data
|
||||
#
|
||||
docker run --name $OVPN_DATA -v /etc/openvpn busybox
|
||||
|
||||
ip addr ls
|
||||
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
|
||||
# Configure server with two factor authentication
|
||||
docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_genconfig -u udp://$SERV_IP -2
|
||||
|
||||
# nopass is insecure
|
||||
docker run --volumes-from $OVPN_DATA --rm -it -e "EASYRSA_BATCH=1" -e "EASYRSA_REQ_CN=Travis-CI Test CA" $IMG ovpn_initpki nopass
|
||||
|
||||
docker run --volumes-from $OVPN_DATA --rm -it $IMG easyrsa build-client-full $CLIENT nopass
|
||||
|
||||
# Generate OTP credentials for user named test, should return QR code for test user
|
||||
docker run --volumes-from $OVPN_DATA --rm -it $IMG ovpn_otp_user $OTP_USER | tee client/qrcode.txt
|
||||
# Ensure a chart link is printed in client OTP configuration
|
||||
grep 'https://www.google.com/chart' client/qrcode.txt || abort 'Link to chart not generated'
|
||||
grep 'Your new secret key is:' client/qrcode.txt || abort 'Secret key is missing'
|
||||
# Extract an emergency code from textual output, grepping for line and trimming spaces
|
||||
OTP_TOKEN=$(grep -A1 'Your emergency scratch codes are' client/qrcode.txt | tail -1 | tr -d '[[:space:]]')
|
||||
# Token should be present
|
||||
if [ -z $OTP_TOKEN ]; then
|
||||
abort "QR Emergency Code not detected"
|
||||
fi
|
||||
|
||||
# Store authentication credentials in config file and tell openvpn to use them
|
||||
echo -e "$OTP_USER\n$OTP_TOKEN" > client/credentials.txt
|
||||
|
||||
# Override the auth-user-pass directive to use a credentials file
|
||||
docker run --volumes-from $OVPN_DATA --rm $IMG ovpn_getclient $CLIENT | sed 's/auth-user-pass/auth-user-pass \/client\/credentials.txt/' | tee client/config.ovpn
|
||||
|
||||
#
|
||||
# Fire up the server
|
||||
#
|
||||
sudo iptables -N DOCKER || echo 'Firewall already configured'
|
||||
sudo iptables -I FORWARD -j DOCKER || echo 'Forward already configured'
|
||||
# run in shell bg to get logs
|
||||
docker run --name "ovpn-test" --volumes-from $OVPN_DATA --rm -p 1194:1194/udp --privileged $IMG &
|
||||
|
||||
#for i in $(seq 10); do
|
||||
# SERV_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}')
|
||||
# test -n "$SERV_IP" && break
|
||||
#done
|
||||
#sed -ie s:SERV_IP:$SERV_IP:g client/config.ovpn
|
||||
|
||||
#
|
||||
# Fire up a client in a container since openvpn is disallowed by Travis-CI, don't NAT
|
||||
# the host as it confuses itself:
|
||||
# "Incoming packet rejected from [AF_INET]172.17.42.1:1194[2], expected peer address: [AF_INET]10.240.118.86:1194"
|
||||
#
|
||||
docker run --rm --net=host --privileged --volume $PWD/client:/client $IMG /client/wait-for-connect.sh
|
||||
|
||||
#
|
||||
# Client either connected or timed out, kill server
|
||||
#
|
||||
kill %1
|
||||
|
||||
#
|
||||
# Celebrate
|
||||
#
|
||||
cat <<EOF
|
||||
___________
|
||||
< it worked >
|
||||
-----------
|
||||
\ ^__^
|
||||
\ (oo)\_______
|
||||
(__)\ )\/\\
|
||||
||----w |
|
||||
|| ||
|
||||
EOF
|
Reference in New Issue
Block a user