37 Commits
v2.1.0 ... dev

Author SHA1 Message Date
Kyle Manna
925b08fec4 Merge pull request #283 from buchdag/genconfig-fix
Fix ovpn_genconfig repeatability issue
2017-07-08 11:06:36 -07:00
Nicolas Duchon
7a29e8e39b Extra client config is now an array 2017-06-21 02:21:52 +02:00
Nicolas Duchon
16fbc4019d Fix ovpn_genconfig for repeatability 2017-06-21 02:21:52 +02:00
Nicolas Duchon
63a2449705 Add test for ovpn_genconfig repeatability 2017-06-21 01:03:49 +02:00
Kyle Manna
1b8374f818 Merge pull request #281 from buchdag/crl-expire
Defaults easy_rsa CRL next update to 3650 days
2017-06-17 09:15:27 -07:00
Nicolas Duchon
8d7bc7e2c5 Set CRL next update to 3650 days 2017-06-17 13:17:20 +02:00
Nicolas Duchon
e30ee8eecf Add CRL next update test 2017-06-17 13:17:08 +02:00
Kyle Manna
e00a72a3f6 Dockerfile: master branch follows alpine:latest
The master branch will follow alpine:latest.  See `openvpn-2.x` branches
for more stability.

Related #267
2017-05-26 12:25:43 -07:00
Kyle Manna
d974c0ac6a README: Mention passphrase prompt and systemd init
* Enhance the documentation to mention that user interaction is
  necessary during the `ovpn_initpki`.
* Re-arrange the next steps part to point people to systemd init as well
  as docs directory.

Closes #266
2017-05-20 08:44:22 -07:00
Kyle Manna
c0ed8d468d Dockerfile: Drop edge/community for google-authenticator
* Use the primary repository now that google-authenticator is available
  from alpine:v3.5.

Related to #262
2017-05-17 09:27:30 -07:00
Kyle Manna
2a9059aa36 tests: Clean-up client + conf_options
Clean-up the mess that was here.  It's less error prone, shorter and
easier to read.
2017-05-13 10:52:47 -07:00
Kyle Manna
074a07e40e genconfig: Fix missing MTU required argument
This must have beeen broken for a long time.  Test case added to prevent
it from breaking again.

Closes #259
2017-05-13 09:50:18 -07:00
Kyle Manna
8c9d88b316 tests: client: Add client config test suite
* Test the client configuration to detect breakages
2017-05-13 09:50:18 -07:00
Kyle Manna
78d612d181 Merge pull request #253 from chepurko/patch-1 2017-05-11 11:21:14 -07:00
Kyle Manna
6bff62eb79 Dockerfile: Swtich from dl-4 to dl-cdn.alpinelinux.org
* At the time of this commit dl-4.alpinelinux.org was unreachable.
* Switch to the CDN instead of some hardcoded server.
2017-05-11 11:20:40 -07:00
Alexander Chepurko
8f2f27486c Add quoting into test.sh push options. 2017-05-11 10:55:46 -07:00
Alexander Chepurko
3ee5479d78 Push options need to be quoted.
Move the implementation to process_push_config.
2017-05-11 10:55:46 -07:00
Kyle Manna
909744dd78 Merge pull request #251 from buchdag/buchdag-revoke1
Fix certificate revocation
2017-05-10 09:37:03 -07:00
Nicolas Duchon
5aea8b914c Update documentation
Add ovpn_revokeclient usage to client.md and docker-compose.md
2017-05-10 18:08:11 +02:00
Nicolas Duchon
a091bef13b Create a script to handle client revocation
This script revoke the certificate corresponding to the commonName passed as first parameter, generate a new CRL, copies it to /etc/openvpn, make it readable by OpenVPN and optionally remove the crt, key and req file corresponding to the revoked certificate using "remove" as second parameter (removal of those files are required to generate a new client certificate using the revoked certificate's CN).
2017-05-10 18:08:11 +02:00
Nicolas Duchon
59644d953d Replace hardlinking of crl.pem with a copy
easyrsa gen-crl does not modify the crl.pem in place but rather remove the old file and create a new one, which means any hardlink to it will get broken again at each invocation of easyrsa gen-crl.

If hardlink to this file is not going to work anyway and we still need it to be readable by OpenVPN, we're better off copying it and chmod-ing it every time a new one is detected on container start, using the conditional expression file1 -nt file2.
2017-05-10 18:08:11 +02:00
Nicolas Duchon
dcf3791d54 Generate a CRL during PKI initialization 2017-05-10 18:08:11 +02:00
Nicolas Duchon
76546e1823 Add client revocation test 2017-05-10 18:08:11 +02:00
Kyle Manna
f996bbaa8e README: Clarify volume naming convention
* Use a better default that works with systemd service out of the box.
* Update upstart init script to follow convention.
2017-05-10 08:14:51 -07:00
Kyle Manna
861ed05c48 Merge pull request #254 from buchdag/buchdag-systemd.md
Clarify and complete systemd.md
2017-05-06 07:04:18 -07:00
Kyle Manna
ce690e5ab1 ovpn_run: Explicitly enable ipv6
On a recent build I ran in to the following error messages:

    Wed May  3 14:31:43 2017 /sbin/ip -6 addr add 2001:db8:0:4::1/64 dev tun0
    Wed May  3 14:31:43 2017 Linux ip -6 addr add failed: external program exited with error status: 2

This appears to be do to the fact that somewhere something defaulted the
kernel in the container to disable IPv6.  Not sure if this is my host or
the docker daemon.  Re-enable it explicitly for now until Docker gets
it's IPv6 act together.
2017-05-03 07:48:15 -07:00
Nicolas Duchon
e4821ec709 Clarify and complete systemd.md 2017-05-02 22:24:37 +02:00
Kyle Manna
808e2448b1 Merge pull request #244 from DerEnderKeks/patch-1
Removed double entry
2017-05-02 10:48:14 -07:00
DerEnderKeks
fe2cdebea2 Removed double entry
the removed line contained the same option as line 63
2017-03-25 19:41:31 +01:00
Kyle Manna
892a3c9a1c Merge pull request #234 from slamont/master
Add an option for setting different values for keepalive
2017-03-09 20:30:49 -08:00
Sylvain Lamontagne
a3c96bc881 Add test for keepalive 2017-03-09 20:58:46 -05:00
Sylvain Lamontagne
22fcaf9477 Add configuration for keepalive
* Add parameter to disable the push of block-outside-dns
* -d should really do what it was supposed to do
* Fix problem where comp-lzo would always be set regardless of the parameter
2017-03-09 20:35:52 -05:00
Kyle Manna
d454a20e80 Merge pull request #231 from mediatemple/only_block_when_road_warrior
Only block external dns when default route is pushed
2017-03-07 16:24:34 -08:00
Nate Jones
c8ba567333 only block external dns when default route is pushed 2017-03-07 23:21:17 +00:00
Nate Jones
21ae2fcef4 fix block-external-dns tests 2017-03-07 23:20:50 +00:00
Kyle Manna
24944b0a11 Merge pull request #226 from vielmetti/patch-1
Create Dockerfile.aarch64
2017-02-24 09:06:58 -08:00
Edward Vielmetti
b74cbd5c74 Create Dockerfile.aarch64
New Dockerfile to support aarch64 (ARMv8, arm64).
2017-02-23 13:59:43 -05:00
17 changed files with 530 additions and 251 deletions

View File

@@ -1,12 +1,12 @@
# Original credit: https://github.com/jpetazzo/dockvpn # Original credit: https://github.com/jpetazzo/dockvpn
# Smallest base image # Smallest base image
FROM alpine:3.5 FROM alpine:latest
MAINTAINER Kyle Manna <kyle@kylemanna.com> MAINTAINER Kyle Manna <kyle@kylemanna.com>
RUN echo "http://dl-4.alpinelinux.org/alpine/edge/community/" >> /etc/apk/repositories && \ # Testing: pamtester
echo "http://dl-4.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories && \ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories && \
apk add --update openvpn iptables bash easy-rsa openvpn-auth-pam google-authenticator pamtester && \ apk add --update openvpn iptables bash easy-rsa openvpn-auth-pam google-authenticator pamtester && \
ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \
rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/*
@@ -17,6 +17,9 @@ ENV EASYRSA /usr/share/easy-rsa
ENV EASYRSA_PKI $OPENVPN/pki ENV EASYRSA_PKI $OPENVPN/pki
ENV EASYRSA_VARS_FILE $OPENVPN/vars ENV EASYRSA_VARS_FILE $OPENVPN/vars
# Prevents refused client connection because of an expired CRL
ENV EASYRSA_CRL_DAYS 3650
VOLUME ["/etc/openvpn"] VOLUME ["/etc/openvpn"]
# Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp` # Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp`

34
Dockerfile.aarch64 Normal file
View File

@@ -0,0 +1,34 @@
# Original credit: https://github.com/jpetazzo/dockvpn
# Smallest base image
FROM aarch64/alpine:3.5
MAINTAINER Kyle Manna <kyle@kylemanna.com>
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/* /var/cache/distfiles/*
# Needed by scripts
ENV OPENVPN /etc/openvpn
ENV EASYRSA /usr/share/easy-rsa
ENV EASYRSA_PKI $OPENVPN/pki
ENV EASYRSA_VARS_FILE $OPENVPN/vars
# Prevents refused client connection because of an expired CRL
ENV EASYRSA_CRL_DAYS 3650
VOLUME ["/etc/openvpn"]
# Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp`
EXPOSE 1194/udp
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/

View File

@@ -18,11 +18,16 @@ a corresponding [Digital Ocean Community Tutorial](http://bit.ly/1AGUZkq).
## Quick Start ## Quick Start
* Pick a name for the `$OVPN_DATA` data volume container, it will be created automatically. * Pick a name for the `$OVPN_DATA` data volume container. It's recommended to
use the `ovpn-data-` prefix to operate seamlessly with the reference systemd
service. Users are encourage to replace `example` with a descriptive name of
their choosing.
OVPN_DATA="ovpn-data" OVPN_DATA="ovpn-data-example"
* Initialize the `$OVPN_DATA` container that will hold the configuration files and certificates * Initialize the `$OVPN_DATA` container that will hold the configuration files
and certificates. The container will prompt for a passphrase to protect the
private key used by the newly generated certificate authority.
docker volume create --name $OVPN_DATA docker volume create --name $OVPN_DATA
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM
@@ -40,7 +45,22 @@ a corresponding [Digital Ocean Community Tutorial](http://bit.ly/1AGUZkq).
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn
## Docker Compose ## Next Steps
### More Reading
Miscellaneous write-ups for advanced configurations are available in the
[docs](docs) folder.
### Systemd Init Scripts
A `systemd` init script is available to manage the OpenVPN container. It will
start the container on system boot, restart the container if it exits
unexpectedly, and pull updates from Docker Hub to keep itself up to date.
Please refer to the [systemd documentation](docs/systemd.md) to learn more.
### Docker Compose
If you prefer to use `docker-compose` please refer to the [documentation](docs/docker-compose.md). If you prefer to use `docker-compose` please refer to the [documentation](docs/docker-compose.md).

View File

@@ -7,7 +7,6 @@
TMP_PUSH_CONFIGFILE=$(mktemp -t vpn_push.XXXXXXX) TMP_PUSH_CONFIGFILE=$(mktemp -t vpn_push.XXXXXXX)
TMP_ROUTE_CONFIGFILE=$(mktemp -t vpn_route.XXXXXXX) TMP_ROUTE_CONFIGFILE=$(mktemp -t vpn_route.XXXXXXX)
TMP_EXTRA_CONFIGFILE=$(mktemp -t vpn_extra.XXXXXXX) TMP_EXTRA_CONFIGFILE=$(mktemp -t vpn_extra.XXXXXXX)
TMP_EXTRA_CLIENT_CONFIGFILE=$(mktemp -t vpn_extra_client.XXXXXXX)
#Traceback on Error and Exit come from https://docwhat.org/tracebacks-in-bash/ #Traceback on Error and Exit come from https://docwhat.org/tracebacks-in-bash/
set -eu set -eu
@@ -46,7 +45,6 @@ on_exit() {
rm -f $TMP_PUSH_CONFIGFILE rm -f $TMP_PUSH_CONFIGFILE
rm -f $TMP_ROUTE_CONFIGFILE rm -f $TMP_ROUTE_CONFIGFILE
rm -f $TMP_EXTRA_CONFIGFILE rm -f $TMP_EXTRA_CONFIGFILE
rm -f $TMP_EXTRA_CLIENT_CONFIGFILE
local _ec="$?" local _ec="$?"
if [[ $_ec != 0 && "${_showed_traceback}" != t ]]; then if [[ $_ec != 0 && "${_showed_traceback}" != t ]]; then
traceback 1 traceback 1
@@ -95,10 +93,12 @@ usage() {
echo "optional arguments:" echo "optional arguments:"
echo " -2 Enable two factor authentication using Google Authenticator." echo " -2 Enable two factor authentication using Google Authenticator."
echo " -a Authenticate packets with HMAC using the given message digest algorithm (auth)." echo " -a Authenticate packets with HMAC using the given message digest algorithm (auth)."
echo " -b Disable 'push block-outside-dns'"
echo " -c Enable client-to-client option" echo " -c Enable client-to-client option"
echo " -C A list of allowable TLS ciphers delimited by a colon (cipher)." echo " -C A list of allowable TLS ciphers delimited by a colon (cipher)."
echo " -d Disable NAT routing and default route" echo " -d Disable default route"
echo " -D Do not push dns servers" echo " -D Do not push dns servers"
echo " -k Set keepalive. Default: '10 60'"
echo " -m Set client MTU" echo " -m Set client MTU"
echo " -N Configure NAT to access external server network" echo " -N Configure NAT to access external server network"
echo " -t Use TAP device (instead of TUN device)" echo " -t Use TAP device (instead of TUN device)"
@@ -119,7 +119,7 @@ process_push_config() {
local ovpn_push_config='' local ovpn_push_config=''
ovpn_push_config="$1" ovpn_push_config="$1"
echo "Processing PUSH Config: '${ovpn_push_config}'" echo "Processing PUSH Config: '${ovpn_push_config}'"
[[ -n "$ovpn_push_config" ]] && echo "push $ovpn_push_config" >> "$TMP_PUSH_CONFIGFILE" [[ -n "$ovpn_push_config" ]] && echo "push \"$ovpn_push_config\"" >> "$TMP_PUSH_CONFIGFILE"
} }
process_extra_config() { process_extra_config() {
@@ -127,14 +127,6 @@ process_extra_config() {
ovpn_extra_config="$1" ovpn_extra_config="$1"
echo "Processing Extra Config: '${ovpn_extra_config}'" echo "Processing Extra Config: '${ovpn_extra_config}'"
[[ -n "$ovpn_extra_config" ]] && echo "$ovpn_extra_config" >> "$TMP_EXTRA_CONFIGFILE" [[ -n "$ovpn_extra_config" ]] && echo "$ovpn_extra_config" >> "$TMP_EXTRA_CONFIGFILE"
}
process_extra_client_config() {
local ovpn_extra_config=''
ovpn_extra_config="$1"
echo "Processing Extra Client Config: '${ovpn_extra_config}'"
[[ -n "$ovpn_extra_config" ]] && echo "$ovpn_extra_config" >> "$TMP_EXTRA_CLIENT_CONFIGFILE"
} }
if [ "${DEBUG:-}" == "1" ]; then if [ "${DEBUG:-}" == "1" ]; then
@@ -150,35 +142,52 @@ if [ -z "${EASYRSA_PKI:-}" ]; then
export EASYRSA_PKI="$OPENVPN/pki" export EASYRSA_PKI="$OPENVPN/pki"
fi fi
OVPN_ENV=${OPENVPN}/ovpn_env.sh OVPN_AUTH=''
OVPN_SERVER=192.168.255.0/24 OVPN_CIPHER=''
OVPN_CLIENT_TO_CLIENT=''
OVPN_CN=''
OVPN_COMP_LZO=0
OVPN_DEFROUTE=1 OVPN_DEFROUTE=1
OVPN_NAT=0
OVPN_DNS=1
OVPN_DEVICE="tun" OVPN_DEVICE="tun"
OVPN_DEVICEN=0 OVPN_DEVICEN=0
OVPN_DNS_SERVERS=("8.8.8.8" "8.8.4.4") OVPN_DISABLE_PUSH_BLOCK_DNS=0
TMP_DNS_SERVERS=() OVPN_DNS=1
OVPN_DNS_SERVERS=()
OVPN_ENV=${OPENVPN}/ovpn_env.sh
OVPN_EXTRA_CLIENT_CONFIG=()
OVPN_EXTRA_SERVER_CONFIG=()
OVPN_FRAGMENT=''
OVPN_KEEPALIVE="10 60"
OVPN_MTU=''
OVPN_NAT=0
OVPN_PORT=''
OVPN_PROTO=''
OVPN_PUSH=()
OVPN_ROUTES=()
OVPN_SERVER=192.168.255.0/24
OVPN_SERVER_URL=''
OVPN_TLS_CIPHER='' OVPN_TLS_CIPHER=''
OVPN_CIPHER=''
OVPN_AUTH=''
OVPN_EXTRA_CONFIG=''
CUSTOM_ROUTE_CONFIG=''
# Import defaults if present # Import existing configuration if present
[ -r "$OVPN_ENV" ] && source "$OVPN_ENV" [ -r "$OVPN_ENV" ] && source "$OVPN_ENV"
# Parse arguments # Parse arguments
while getopts ":a:e:E:C:T:r:s:du:cp:n:DNmf:tz2" opt; do while getopts ":a:e:E:C:T:r:s:du:bcp:n:k:DNm:f:tz2" opt; do
case $opt in case $opt in
a) a)
OVPN_AUTH="$OPTARG" OVPN_AUTH="$OPTARG"
;; ;;
e) e)
process_extra_config "$OPTARG" mapfile -t TMP_EXTRA_SERVER_CONFIG < <(echo "$OPTARG")
for i in "${TMP_EXTRA_SERVER_CONFIG[@]}"; do
OVPN_EXTRA_SERVER_CONFIG+=("$i")
done
;; ;;
E) E)
process_extra_client_config "$OPTARG" mapfile -t TMP_EXTRA_CLIENT_CONFIG < <(echo "$OPTARG")
for i in "${TMP_EXTRA_CLIENT_CONFIG[@]}"; do
OVPN_EXTRA_CLIENT_CONFIG+=("$i")
done
;; ;;
C) C)
OVPN_CIPHER="$OPTARG" OVPN_CIPHER="$OPTARG"
@@ -187,26 +196,38 @@ while getopts ":a:e:E:C:T:r:s:du:cp:n:DNmf:tz2" opt; do
OVPN_TLS_CIPHER="$OPTARG" OVPN_TLS_CIPHER="$OPTARG"
;; ;;
r) r)
CUSTOM_ROUTE_CONFIG=1 mapfile -t TMP_ROUTES < <(echo "$OPTARG")
process_route_config "$OPTARG" for i in "${TMP_ROUTES[@]}"; do
OVPN_ROUTES+=("$i")
done
;; ;;
s) s)
OVPN_SERVER=$OPTARG OVPN_SERVER="$OPTARG"
;; ;;
d) d)
OVPN_DEFROUTE=0 OVPN_DEFROUTE=0
OVPN_DISABLE_PUSH_BLOCK_DNS=1
;; ;;
u) u)
OVPN_SERVER_URL=$OPTARG OVPN_SERVER_URL="$OPTARG"
;;
b)
OVPN_DISABLE_PUSH_BLOCK_DNS=1
;; ;;
c) c)
OVPN_CLIENT_TO_CLIENT=1 OVPN_CLIENT_TO_CLIENT=1
;; ;;
p) p)
process_push_config "$OPTARG" mapfile -t TMP_PUSH < <(echo "$OPTARG")
for i in "${TMP_PUSH[@]}"; do
OVPN_PUSH+=("$i")
done
;; ;;
n) n)
TMP_DNS_SERVERS+=("$OPTARG") mapfile -t TMP_DNS_SERVERS < <(echo "$OPTARG")
for i in "${TMP_DNS_SERVERS[@]}"; do
OVPN_DNS_SERVERS+=("$i")
done
;; ;;
D) D)
OVPN_DNS=0 OVPN_DNS=0
@@ -214,8 +235,11 @@ while getopts ":a:e:E:C:T:r:s:du:cp:n:DNmf:tz2" opt; do
N) N)
OVPN_NAT=1 OVPN_NAT=1
;; ;;
k)
OVPN_KEEPALIVE="$OPTARG"
;;
m) m)
OVPN_MTU=$OPTARG OVPN_MTU="$OPTARG"
;; ;;
t) t)
OVPN_DEVICE="tap" OVPN_DEVICE="tap"
@@ -227,7 +251,7 @@ while getopts ":a:e:E:C:T:r:s:du:cp:n:DNmf:tz2" opt; do
OVPN_OTP_AUTH=1 OVPN_OTP_AUTH=1
;; ;;
f) f)
OVPN_FRAGMENT=$OPTARG OVPN_FRAGMENT="$OPTARG"
;; ;;
\?) \?)
set +x set +x
@@ -247,9 +271,6 @@ done
# Create ccd directory for static routes # Create ccd directory for static routes
[ ! -d "${OPENVPN:-}/ccd" ] && mkdir -p ${OPENVPN:-}/ccd [ ! -d "${OPENVPN:-}/ccd" ] && mkdir -p ${OPENVPN:-}/ccd
# 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" # Server name is in the form "udp://vpn.example.com:1194"
if [[ "${OVPN_SERVER_URL:-}" =~ ^((udp|tcp|udp6|tcp6)://)?([0-9a-zA-Z\.\-]+)(:([0-9]+))?$ ]]; then if [[ "${OVPN_SERVER_URL:-}" =~ ^((udp|tcp|udp6|tcp6)://)?([0-9a-zA-Z\.\-]+)(:([0-9]+))?$ ]]; then
OVPN_PROTO=${BASH_REMATCH[2]}; OVPN_PROTO=${BASH_REMATCH[2]};
@@ -262,24 +283,13 @@ else
exit 1 exit 1
fi fi
# Apply defaults # Apply defaults. If dns servers were not defined with -n, use google nameservers
set +u
[ -z "$OVPN_DNS_SERVERS" ] && OVPN_DNS_SERVERS=("8.8.8.8" "8.8.4.4")
[ -z "$OVPN_PROTO" ] && OVPN_PROTO=udp [ -z "$OVPN_PROTO" ] && OVPN_PROTO=udp
[ -z "$OVPN_PORT" ] && OVPN_PORT=1194 [ -z "$OVPN_PORT" ] && OVPN_PORT=1194
[ -z "$CUSTOM_ROUTE_CONFIG" ] && process_route_config "192.168.254.0/24" set -u
[ "${#OVPN_ROUTES[@]}" == "0" ] && [ "$OVPN_DEFROUTE" == "1" ] && OVPN_ROUTES+=("192.168.254.0/24")
# Save extra client config from temp file only if temp file is not empty
if [ -s "$TMP_EXTRA_CLIENT_CONFIGFILE" ]; then
OVPN_ADDITIONAL_CLIENT_CONFIG=$(cat $TMP_EXTRA_CLIENT_CONFIGFILE)
fi
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
export OVPN_ADDITIONAL_CLIENT_CONFIG
# Preserve config # Preserve config
if [ -f "$OVPN_ENV" ]; then if [ -f "$OVPN_ENV" ]; then
@@ -288,17 +298,10 @@ if [ -f "$OVPN_ENV" ]; then
mv "$OVPN_ENV" "$bak_env" mv "$OVPN_ENV" "$bak_env"
fi fi
# Like `export | grep OVPN_ > "$OVPN_ENV"` but handles multiline variables # Save the current OVPN_ vars to the ovpn_env.sh file
set +u while read -r var; do
while read var ; do echo "declare -x $var" >> "$OVPN_ENV"
eval value=\$$var done < <(set | grep '^OVPN_')
if [ -n "$value" ]; then
echo "declare -x $var=\"$value\"" >> "$OVPN_ENV"
else
echo "declare -x $var" >> "$OVPN_ENV"
fi
done < <(export | egrep -o '(OVPN_[^=]+)')
set -u
conf=${OPENVPN:-}/openvpn.conf conf=${OPENVPN:-}/openvpn.conf
if [ -f "$conf" ]; then if [ -f "$conf" ]; then
@@ -307,6 +310,13 @@ if [ -f "$conf" ]; then
mv "$conf" "$bak" mv "$conf" "$bak"
fi fi
# Echo extra client configurations
if [ ${#OVPN_EXTRA_CLIENT_CONFIG[@]} -gt 0 ]; then
for i in "${OVPN_EXTRA_CLIENT_CONFIG[@]}"; do
echo "Processing Extra Client Config: $i"
done
fi
cat > "$conf" <<EOF cat > "$conf" <<EOF
server $(getroute $OVPN_SERVER) server $(getroute $OVPN_SERVER)
verb 3 verb 3
@@ -316,7 +326,7 @@ cert $EASYRSA_PKI/issued/${OVPN_CN}.crt
dh $EASYRSA_PKI/dh.pem dh $EASYRSA_PKI/dh.pem
tls-auth $EASYRSA_PKI/ta.key tls-auth $EASYRSA_PKI/ta.key
key-direction 0 key-direction 0
keepalive 10 60 keepalive $OVPN_KEEPALIVE
persist-key persist-key
persist-tun persist-tun
@@ -330,39 +340,57 @@ user nobody
group nogroup group nogroup
EOF EOF
#This was in the heredoc, we use the new function instead if [ "${OVPN_DISABLE_PUSH_BLOCK_DNS}" == "1" ]; then
process_push_config "block-outside-dns" echo "Disable default push of 'block-outside-dns'"
else
process_push_config "block-outside-dns"
fi
[ -n "$OVPN_TLS_CIPHER" ] && echo "tls-cipher $OVPN_TLS_CIPHER" >> "$conf" [ -n "$OVPN_TLS_CIPHER" ] && echo "tls-cipher $OVPN_TLS_CIPHER" >> "$conf"
[ -n "$OVPN_CIPHER" ] && echo "cipher $OVPN_CIPHER" >> "$conf" [ -n "$OVPN_CIPHER" ] && echo "cipher $OVPN_CIPHER" >> "$conf"
[ -n "$OVPN_AUTH" ] && echo "auth $OVPN_AUTH" >> "$conf" [ -n "$OVPN_AUTH" ] && echo "auth $OVPN_AUTH" >> "$conf"
[ -n "${OVPN_CLIENT_TO_CLIENT:-}" ] && echo "client-to-client" >> "$conf" [ -n "${OVPN_CLIENT_TO_CLIENT:-}" ] && echo "client-to-client" >> "$conf"
[ -n "${OVPN_COMP_LZO:-}" ] && echo "comp-lzo" >> "$conf" [ "$OVPN_COMP_LZO" == "1" ] && echo "comp-lzo" >> "$conf"
[ -n "${OVPN_FRAGMENT:-}" ] && echo "fragment $OVPN_FRAGMENT" >> "$conf" [ -n "${OVPN_FRAGMENT:-}" ] && echo "fragment $OVPN_FRAGMENT" >> "$conf"
# Append route commands
if [ ${#OVPN_ROUTES[@]} -gt 0 ]; then
for i in "${OVPN_ROUTES[@]}"; do
process_route_config "$i"
done
echo -e "\n### Route Configurations Below" >> "$conf"
cat $TMP_ROUTE_CONFIGFILE >> "$conf"
fi
# Append push commands
[ "$OVPN_DNS" == "1" ] && for i in "${OVPN_DNS_SERVERS[@]}"; do [ "$OVPN_DNS" == "1" ] && for i in "${OVPN_DNS_SERVERS[@]}"; do
process_push_config "dhcp-option DNS $i" process_push_config "dhcp-option DNS $i"
done done
# Append route commands [ ${#OVPN_PUSH[@]} -gt 0 ] && for i in "${OVPN_PUSH[@]}"; do
echo -e "\n### Route Configurations Below" >> "$conf" process_push_config "$i"
cat $TMP_ROUTE_CONFIGFILE >> "$conf" done
# Append push commands
echo -e "\n### Push Configurations Below" >> "$conf" echo -e "\n### Push Configurations Below" >> "$conf"
cat $TMP_PUSH_CONFIGFILE >> "$conf" cat $TMP_PUSH_CONFIGFILE >> "$conf"
# Optional OTP authentication support # Append optional OTP authentication support
if [ -n "${OVPN_OTP_AUTH:-}" ]; then if [ -n "${OVPN_OTP_AUTH:-}" ]; then
echo -e "\n\n# Enable OTP+PAM for user authentication" >> "$conf" echo -e "\n\n# Enable OTP+PAM for user authentication" >> "$conf"
echo "plugin /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn" >> "$conf" echo "plugin /usr/lib/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn" >> "$conf"
echo "reneg-sec 0" >> "$conf" echo "reneg-sec 0" >> "$conf"
fi fi
echo -e "\n### Extra Configurations Below" >> "$conf" # Append extra server configurations
cat $TMP_EXTRA_CONFIGFILE >> "$conf" if [ ${#OVPN_EXTRA_SERVER_CONFIG[@]} -gt 0 ]; then
for i in "${OVPN_EXTRA_SERVER_CONFIG[@]}"; do
process_extra_config "$i"
done
echo -e "\n### Extra Configurations Below" >> "$conf"
cat $TMP_EXTRA_CONFIGFILE >> "$conf"
fi
set +e set +e

View File

@@ -35,7 +35,6 @@ get_client_config() {
client client
nobind nobind
dev $OVPN_DEVICE dev $OVPN_DEVICE
key-direction 1
remote-cert-tls server remote-cert-tls server
remote $OVPN_CN $OVPN_PORT $OVPN_PROTO" remote $OVPN_CN $OVPN_PORT $OVPN_PROTO"
@@ -45,8 +44,9 @@ remote $OVPN_CN $OVPN_PORT $OVPN_PROTO"
if [ "$OVPN_PROTO" == "tcp6" ]; then if [ "$OVPN_PROTO" == "tcp6" ]; then
echo "remote $OVPN_CN $OVPN_PORT tcp" echo "remote $OVPN_CN $OVPN_PORT tcp"
fi fi
echo "$OVPN_ADDITIONAL_CLIENT_CONFIG for i in "${OVPN_EXTRA_CLIENT_CONFIG[@]}"; do
" echo "$i"
done
if [ "$mode" == "combined" ]; then if [ "$mode" == "combined" ]; then
echo " echo "
<key> <key>
@@ -97,12 +97,12 @@ tls-auth ta.key 1
echo "auth-nocache" echo "auth-nocache"
fi fi
if [ -n "$OVPN_COMP_LZO" ]; then if [ "$OVPN_COMP_LZO" == "1" ]; then
echo "comp-lzo" echo "comp-lzo"
fi fi
if [ -n "$OVPN_OTP_AUTH" ]; then if [ -n "$OVPN_OTP_AUTH" ]; then
echo reneg-sec 0 echo reneg-sec 0
fi fi
} }
@@ -124,9 +124,9 @@ case "$parm" in
get_client_config "combined" > "$dir/${cn}-combined.ovpn" get_client_config "combined" > "$dir/${cn}-combined.ovpn"
;; ;;
*) *)
echo "This script can produce the client configuration in to formats:" >&2 echo "This script can produce the client configuration in two formats:" >&2
echo " 1. combined (default): All needed configuration and cryptographic material is in one file (Use \"combined-save\" to write the configuration file in the same path as the separated parameter does)." >&2 echo " 1. combined (default): All needed configuration and cryptographic material is in one file (Use \"combined-save\" to write the configuration file in the same path as the separated parameter does)." >&2
echo " 2. separated: Separated files." >&2 echo " 2. separated: Separated files." >&2
echo "Please specific one of those options as second parameter." >&2 echo "Please specify one of those options as second parameter." >&2
;; ;;
esac esac

View File

@@ -38,3 +38,6 @@ openvpn --genkey --secret $EASYRSA_PKI/ta.key
# For a server key with a password, manually init; this is autopilot # For a server key with a password, manually init; this is autopilot
easyrsa build-server-full "$OVPN_CN" nopass easyrsa build-server-full "$OVPN_CN" nopass
# Generate the CRL for client/server certificates revocation.
easyrsa gen-crl

61
bin/ovpn_revokeclient Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
#
# Revoke a client certificate
#
if [ "$DEBUG" == "1" ]; then
set -x
fi
set -e
if [ -z "$OPENVPN" ]; then
export OPENVPN="$PWD"
fi
if ! source "$OPENVPN/ovpn_env.sh"; then
echo "Could not source $OPENVPN/ovpn_env.sh."
exit 1
fi
if [ -z "$EASYRSA_PKI" ]; then
export EASYRSA_PKI="$OPENVPN/pki"
fi
cn="$1"
parm="$2"
if [ ! -f "$EASYRSA_PKI/private/${cn}.key" ]; then
echo "Unable to find \"${cn}\", please try again or generate the key first" >&2
exit 1
fi
revoke_client_certificate(){
easyrsa revoke "$1"
echo "Generating the Certificate Revocation List :"
easyrsa gen-crl
cp -f "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem"
chmod 644 "$OPENVPN/crl.pem"
}
remove_files(){
rm -v "$EASYRSA_PKI/issued/${1}.crt"
rm -v "$EASYRSA_PKI/private/${1}.key"
rm -v "$EASYRSA_PKI/reqs/${1}.req"
}
case "$parm" in
"remove")
revoke_client_certificate "$cn"
remove_files "$cn"
;;
"" | "keep")
revoke_client_certificate "$cn"
;;
*)
echo "When revoking a client certificate, this script let you choose if you want to remove the corresponding crt, key and req files." >&2
echo "Pease note that the removal of those files is required if you want to generate a new client certificate using the revoked certificate's CN." >&2
echo " 1. keep (default): Keep the files." >&2
echo " 2. remove: Remove the files." >&2
echo "Please specify one of those options as second parameter." >&2
;;
esac

View File

@@ -74,13 +74,14 @@ if [ "$OVPN_DEFROUTE" != "0" ] || [ "$OVPN_NAT" == "1" ] ; then
setupIptablesAndRouting setupIptablesAndRouting
fi fi
# Use a hacky hardlink as the CRL Needs to be readable by the user/group # Use a copy of crl.pem as the CRL Needs to be readable by the user/group
# OpenVPN is running as. Only pass arguments to OpenVPN if it's found. # OpenVPN is running as. Only pass arguments to OpenVPN if it's found.
if [ -r "$EASYRSA_PKI/crl.pem" ]; then if [ "$EASYRSA_PKI/crl.pem" -nt "$OPENVPN/crl.pem" ]; then
if [ ! -r "$OPENVPN/crl.pem" ]; then cp -f "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem"
ln "$EASYRSA_PKI/crl.pem" "$OPENVPN/crl.pem" chmod 644 "$OPENVPN/crl.pem"
chmod 644 "$OPENVPN/crl.pem" fi
fi
if [ -r "$OPENVPN/crl.pem" ]; then
addArg "--crl-verify" "$OPENVPN/crl.pem" addArg "--crl-verify" "$OPENVPN/crl.pem"
fi fi
@@ -90,6 +91,7 @@ if [ $? = 0 ]; then
# If this fails, ensure the docker container is run with --privileged # If this fails, ensure the docker container is run with --privileged
# Could be side stepped with `ip netns` madness to drop privileged flag # Could be side stepped with `ip netns` madness to drop privileged flag
sysctl -w net.ipv6.conf.all.disable_ipv6=0 || echo "Failed to enable IPv6 support"
sysctl -w net.ipv6.conf.default.forwarding=1 || echo "Failed to enable IPv6 Forwarding default" 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" sysctl -w net.ipv6.conf.all.forwarding=1 || echo "Failed to enable IPv6 Forwarding"
fi fi

View File

@@ -34,9 +34,12 @@ After doing so, you will find the following files in each of the `$cn` directori
## Revoking Client Certificates ## Revoking Client Certificates
Revoke `client1`'s certificate and generate the certificate revocation list (CRL): Revoke `client1`'s certificate and generate the certificate revocation list (CRL) using [`ovpn_revokeclient`](/bin/ovpn_revokeclient) script :
docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn easyrsa revoke client1 docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn ovpn_revokeclient client1
docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn easyrsa gen-crl
The OpenVPN server will read this change every time a client connects (no need to restart server) and deny clients access using revoked certificates. The OpenVPN server will read this change every time a client connects (no need to restart server) and deny clients access using revoked certificates.
You can optionally pass `remove` as second parameter to ovpn_revokeclient to remove the corresponding crt, key and req files :
docker run --rm -it -v $OVPN_DATA:/etc/openvpn kylemanna/openvpn ovpn_revokeclient client1 remove

View File

@@ -59,6 +59,15 @@ docker-compose run --rm openvpn easyrsa build-client-full $CLIENTNAME nopass
docker-compose run --rm openvpn ovpn_getclient $CLIENTNAME > $CLIENTNAME.ovpn docker-compose run --rm openvpn ovpn_getclient $CLIENTNAME > $CLIENTNAME.ovpn
``` ```
* Revoke a client certificate
```bash
# Keep the corresponding crt, key and req files.
docker-compose run --rm openvpn ovpn_revokeclient $CLIENTNAME
# Remove the corresponding crt, key and req files.
docker-compose run --rm openvpn ovpn_revokeclient $CLIENTNAME remove
```
## Debugging Tips ## Debugging Tips
* Create an environment variable with the name DEBUG and value of 1 to enable debug output (using "docker -e"). * Create an environment variable with the name DEBUG and value of 1 to enable debug output (using "docker -e").

View File

@@ -15,11 +15,17 @@ are harmless for those not using IPv6.
To use and enable automatic start by systemd: To use and enable automatic start by systemd:
1. Create a Docker volume container named `ovpn-data-NAME` where `NAME` is the 1. Create a Docker volume container named `ovpn-data-NAME` where `NAME` is the
user's choice to describe the use of the container. In the example user's choice to describe the use of the container. In this example
configuration given in the [README](/README.md) `NAME=data`. configuration, `NAME=example`.
2. Initialize the data container according to the [docker-openvpn
README](/README.md), but don't start the container. Stop the Docker OVPN_DATA="ovpn-data-example"
container if started. docker volume create --name $OVPN_DATA
2. Initialize the data container, but don't start the container :
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki
3. Download the [docker-openvpn@.service](https://raw.githubusercontent.com/kylemanna/docker-openvpn/master/init/docker-openvpn%40.service) 3. Download the [docker-openvpn@.service](https://raw.githubusercontent.com/kylemanna/docker-openvpn/master/init/docker-openvpn%40.service)
file to `/etc/systemd/system`: file to `/etc/systemd/system`:
@@ -27,11 +33,11 @@ To use and enable automatic start by systemd:
4. Enable and start the service with: 4. Enable and start the service with:
systemctl enable --now docker-openvpn@NAME.service systemctl enable --now docker-openvpn@example.service
5. Verify service start-up with: 5. Verify service start-up with:
systemctl status docker-openvpn@NAME.service systemctl status docker-openvpn@example.service
journalctl --unit docker-openvpn@NAME.service journalctl --unit docker-openvpn@example.service
For more information, see the [systemd manual pages](https://www.freedesktop.org/software/systemd/man/index.html). For more information, see the [systemd manual pages](https://www.freedesktop.org/software/systemd/man/index.html).

View File

@@ -4,5 +4,5 @@ start on filesystem and started docker
stop on runlevel [!2345] stop on runlevel [!2345]
respawn respawn
script script
exec docker run -v ovpn-data:/etc/openvpn --rm -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn exec docker run -v ovpn-data-example:/etc/openvpn --rm -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn
end script end script

View File

@@ -7,11 +7,13 @@ testAlias+=(
imageTests+=( imageTests+=(
[openvpn]=' [openvpn]='
paranoid paranoid
conf_options conf_options
client
basic basic
dual-proto dual-proto
otp otp
iptables iptables
revocation
' '
) )

View File

@@ -0,0 +1,84 @@
#!/bin/bash
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
SERVER_CONF="/etc/openvpn/openvpn.conf"
TEST1_OVPN="/etc/openvpn/test1.ovpn"
# Function to fail
abort() { cat <<< "$@" 1>&2; exit 1; }
# Check a config (haystack) for a given line (needle) exit with error if not
# found.
test_config() {
local needle="${2}"
local file="${1}"
busybox grep -q "${needle}" "${file}"
if [ $? -ne 0 ]; then
abort "==> Config match not found: ${needle}"
fi
}
# Check a config (haystack) for absence of given line (needle) exit with error
# if found.
test_not_config() {
local needle="${2}"
local file="${1}"
busybox grep -vq "${needle}" "${file}"
if [ $? -ne 0 ]; then
abort "==> Config match found: ${needle}"
fi
}
#
# Generate openvpn.config file
#
ovpn_genconfig \
-u udp://$SERV_IP \
-m 1337 \
EASYRSA_BATCH=1 EASYRSA_REQ_CN="Travis-CI Test CA" ovpn_initpki nopass
easyrsa build-client-full test1 nopass 2>/dev/null
ovpn_getclient test1 > "${TEST1_OVPN}"
#
# Simple test cases
#
# 1. client MTU
test_config "${TEST1_OVPN}" "^tun-mtu\s\+1337"
#
# Test udp client with tcp fallback
#
ovpn_genconfig -u udp://$SERV_IP -E "remote $SERV_IP 443 tcp" -E "remote vpn.example.com 443 tcp"
# nopass is insecure
EASYRSA_BATCH=1 EASYRSA_REQ_CN="Travis-CI Test CA" ovpn_initpki nopass
easyrsa build-client-full client-fallback nopass
ovpn_getclient client-fallback > "${TEST1_OVPN}"
test_config "${TEST1_OVPN}" "^remote\s\+$SERV_IP\s\+443\s\+tcp"
test_config "${TEST1_OVPN}" "^remote\s\+vpn.example.com\s\+443\s\+tcp"
#
# Test non-defroute config
#
ovpn_genconfig -d -u udp://$SERV_IP -r "172.33.33.0/24" -r "172.34.34.0/24"
# nopass is insecure
EASYRSA_BATCH=1 EASYRSA_REQ_CN="Travis-CI Test CA" ovpn_initpki nopass
easyrsa build-client-full non-defroute nopass
ovpn_getclient non-defroute > "${TEST1_OVPN}"
# The '!' inverts the match to test that the string isn't present
test_not_config "${TEST1_OVPN}" "^redirect-gateway\s\+def1"

1
test/tests/client/run.sh Symbolic link
View File

@@ -0,0 +1 @@
../run-bash-in-container.sh

View File

@@ -1,8 +1,37 @@
#!/bin/bash #!/bin/bash
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
SERVER_CONF="/etc/openvpn/openvpn.conf"
TEST1_OVPN="/etc/openvpn/test1.ovpn"
# Function to fail # Function to fail
abort() { cat <<< "$@" 1>&2; exit 1; } abort() { cat <<< "$@" 1>&2; exit 1; }
# Check a config (haystack) for a given line (needle) exit with error if not found.
test_config() {
local needle="${2}"
local file="${1}"
busybox grep -q "${needle}" "${file}"
if [ $? -ne 0 ]; then
abort "==> Config match not found: ${needle}"
fi
}
# Check a config (haystack) for absence of given line (needle) exit with error
# if found.
test_not_config() {
local needle="${2}"
local file="${1}"
busybox grep -vq "${needle}" "${file}"
if [ $? -ne 0 ]; then
abort "==> Config match found: ${needle}"
fi
}
# #
# Generate openvpn.config file # Generate openvpn.config file
@@ -12,183 +41,76 @@ management localhost 7505
max-clients 10 max-clients 10
EOF EOF
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1) ovpn_genconfig \
ovpn_genconfig -u udp://$SERV_IP -f 1400 -e "$MULTILINE_EXTRA_SERVER_CONF" -e 'duplicate-cn' -e 'topology subnet' -p 'route 172.22.22.0 255.255.255.0' -u udp://$SERV_IP \
-f 1400 \
-k '60 300' \
-e "$MULTILINE_EXTRA_SERVER_CONF" \
-e 'duplicate-cn' \
-e 'topology subnet' \
-p 'route 172.22.22.0 255.255.255.0' \
# Run ovpn_genconfig a second time with no arguments to test its repeatability.
ovpn_genconfig
# #
# grep for config lines from openvpn.conf # Simple test cases
# add more tests for more configs as required
# #
# 1. verb config # 1. verb config
CONFIG_REQUIRED_VERB="verb 3" test_config "${SERVER_CONF}" "^verb\s\+3"
CONFIG_MATCH_VERB=$(busybox grep verb /etc/openvpn/openvpn.conf)
# 2. fragment config # 2. fragment config
CONFIG_REQUIRED_FRAGMENT="fragment 1400" test_config "${SERVER_CONF}" "^fragment\s\+1400"
CONFIG_MATCH_FRAGMENT=$(busybox grep fragment /etc/openvpn/openvpn.conf)
## Tests for extra configs ## Tests for extra configs
# 3. management config # 3. management config
CONFIG_REQUIRED_MANAGEMENT="^management localhost 7505" test_config "${SERVER_CONF}" "^management\s\+localhost\s\+7505"
CONFIG_MATCH_MANAGEMENT=$(busybox grep management /etc/openvpn/openvpn.conf)
# 4. max-clients config # 4. max-clients config
CONFIG_REQUIRED_MAX_CLIENTS="^max-clients 10" test_config "${SERVER_CONF}" "^max-clients\s\+10"
CONFIG_MATCH_MAX_CLIENTS=$(busybox grep max-clients /etc/openvpn/openvpn.conf)
# 5. duplicate-cn config # 5. duplicate-cn config
CONFIG_REQUIRED_DUPCN="^duplicate-cn" test_config "${SERVER_CONF}" "^duplicate-cn"
CONFIG_MATCH_DUPCN=$(busybox grep duplicate-cn /etc/openvpn/openvpn.conf)
# 6. topology config # 6. topology config
CONFIG_REQUIRED_TOPOLOGY="^topology subnet" test_config "${SERVER_CONF}" "^topology\s\+subnet"
CONFIG_MATCH_TOPOLOGY=$(busybox grep 'topology subnet' /etc/openvpn/openvpn.conf)
## Tests for push config ## Tests for push config
# 7. push route # 7. push route
CONFIG_REQUIRED_PUSH_ROUTE="^push route 172.22.22.0 255.255.255.0" test_config "${SERVER_CONF}" '^push\s\+"route\s\+172.22.22.0\s\+255.255.255.0"'
CONFIG_MATCH_PUSH_ROUTE=$(busybox grep 'push route 172.22.22.0 255.255.255.0' /etc/openvpn/openvpn.conf)
## Test for default ## Test for default
# 8. Should see default route if none provided # 8. Should see default route if none provided
CONFIG_REQUIRED_DEFAULT_ROUTE="^route 192.168.254.0 255.255.255.0" test_config "${SERVER_CONF}" "^route\s\+192.168.254.0\s\+255.255.255.0"
CONFIG_MATCH_DEFAULT_ROUTE=$(busybox grep 'route 192.168.254.0 255.255.255.0' /etc/openvpn/openvpn.conf)
# 9. Should see a push of 'block-outside-dns' by default # 9. Should see a push of 'block-outside-dns' by default
CONFIG_REQUIRED_DEFAULT_ROUTE="^push block-outside-dns" test_config "${SERVER_CONF}" '^push\s\+"block-outside-dns"'
CONFIG_MATCH_DEFAULT_ROUTE=$(busybox grep 'push block-outside-dns' /etc/openvpn/openvpn.conf)
# 10. Should see a push of 'dhcp-option DNS' by default # 10. Should see a push of 'dhcp-option DNS' by default
CONFIG_REQUIRED_DEFAULT_DNS_1="^push dhcp-option DNS 8.8.8.8" test_config "${SERVER_CONF}" '^push\s\+"dhcp-option\s\+DNS\s\+8.8.8.8"'
CONFIG_MATCH_DEFAULT_DNS_1=$(busybox grep 'push dhcp-option DNS 8.8.8.8' /etc/openvpn/openvpn.conf) test_config "${SERVER_CONF}" '^push\s\+"dhcp-option\s\+DNS\s\+8.8.4.4"'
CONFIG_REQUIRED_DEFAULT_DNS_2="^push dhcp-option DNS 8.8.4.4"
CONFIG_MATCH_DEFAULT_DNS_2=$(busybox grep 'push dhcp-option DNS 8.8.4.4' /etc/openvpn/openvpn.conf) ## Test for keepalive
# 11. keepalive config
test_config "${SERVER_CONF}" '^keepalive\s\+60\s\+300'
# #
# Tests # More elaborate route 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
if [[ $CONFIG_MATCH_MANAGEMENT =~ $CONFIG_REQUIRED_MANAGEMENT ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_MANAGEMENT == $CONFIG_MATCH_MANAGEMENT"
else
abort "==> Config match not found: $CONFIG_REQUIRED_MANAGEMENT != $CONFIG_MATCH_MANAGEMENT"
fi
if [[ $CONFIG_MATCH_MAX_CLIENTS =~ $CONFIG_REQUIRED_MAX_CLIENTS ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_MAX_CLIENTS == $CONFIG_MATCH_MAX_CLIENTS"
else
abort "==> Config match not found: $CONFIG_REQUIRED_MAX_CLIENTS != $CONFIG_MATCH_MAX_CLIENTS"
fi
if [[ $CONFIG_MATCH_DUPCN =~ $CONFIG_REQUIRED_DUPCN ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_DUPCN == $CONFIG_MATCH_DUPCN"
else
abort "==> Config match not found: $CONFIG_REQUIRED_DUPCN != $CONFIG_MATCH_DUPCN"
fi
if [[ $CONFIG_MATCH_TOPOLOGY =~ $CONFIG_REQUIRED_TOPOLOGY ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_TOPOLOGY == $CONFIG_MATCH_TOPOLOGY"
else
abort "==> Config match not found: $CONFIG_REQUIRED_TOPOLOGY != $CONFIG_MATCH_TOPOLOGY"
fi
if [[ $CONFIG_MATCH_PUSH_ROUTE =~ $CONFIG_REQUIRED_PUSH_ROUTE ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_PUSH_ROUTE == $CONFIG_MATCH_PUSH_ROUTE"
else
abort "==> Config match not found: $CONFIG_REQUIRED_PUSH_ROUTE != $CONFIG_MATCH_PUSH_ROUTE"
fi
if [[ $CONFIG_MATCH_DEFAULT_ROUTE =~ $CONFIG_REQUIRED_DEFAULT_ROUTE ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_DEFAULT_ROUTE == $CONFIG_MATCH_DEFAULT_ROUTE"
else
abort "==> Config match not found: $CONFIG_REQUIRED_DEFAULT_ROUTE != $CONFIG_MATCH_DEFAULT_ROUTE"
fi
if [[ $CONFIG_MATCH_DEFAULT_DNS_1 =~ $CONFIG_REQUIRED_DEFAULT_DNS_1 ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_DEFAULT_DNS_1 == $CONFIG_MATCH_DEFAULT_DNS_1"
else
abort "==> Config match not found: $CONFIG_REQUIRED_DEFAULT_DNS_1 != $CONFIG_MATCH_DEFAULT_DNS_1"
fi
if [[ $CONFIG_MATCH_DEFAULT_DNS_2 =~ $CONFIG_REQUIRED_DEFAULT_DNS_2 ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_DEFAULT_DNS_2 == $CONFIG_MATCH_DEFAULT_DNS_2"
else
abort "==> Config match not found: $CONFIG_REQUIRED_DEFAULT_DNS_2 != $CONFIG_MATCH_DEFAULT_DNS_2"
fi
SERV_IP=$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)
ovpn_genconfig -u udp://$SERV_IP -r "172.33.33.0/24" -r "172.34.34.0/24" ovpn_genconfig -u udp://$SERV_IP -r "172.33.33.0/24" -r "172.34.34.0/24"
CONFIG_REQUIRED_ROUTE_1="^route 172.33.33.0 255.255.255.0" test_config "${SERVER_CONF}" "^route\s\+172.33.33.0\s\+255.255.255.0"
CONFIG_MATCH_ROUTE_1=$(busybox grep 'route 172.33.33.0 255.255.255.0' /etc/openvpn/openvpn.conf) test_config "${SERVER_CONF}" "^route\s\+172.34.34.0\s\+255.255.255.0"
CONFIG_REQUIRED_ROUTE_2="^route 172.34.34.0 255.255.255.0"
CONFIG_MATCH_ROUTE_2=$(busybox grep 'route 172.34.34.0 255.255.255.0' /etc/openvpn/openvpn.conf)
if [[ $CONFIG_MATCH_ROUTE_1 =~ $CONFIG_REQUIRED_ROUTE_1 ]] #
then # Block outside DNS test
echo "==> Config match found: $CONFIG_REQUIRED_ROUTE_1 == $CONFIG_MATCH_ROUTE_1" #
else
abort "==> Config match not found: $CONFIG_REQUIRED_ROUTE_1 != $CONFIG_MATCH_ROUTE_1"
fi
if [[ $CONFIG_MATCH_ROUTE_2 =~ $CONFIG_REQUIRED_ROUTE_2 ]] ovpn_genconfig -u udp://$SERV_IP -b
then
echo "==> Config match found: $CONFIG_REQUIRED_ROUTE_2 == $CONFIG_MATCH_ROUTE_2"
else
abort "==> Config match not found: $CONFIG_REQUIRED_ROUTE_2 != $CONFIG_MATCH_ROUTE_2"
fi
# Test generated client config test_not_config "${SERVER_CONF}" '^push "block-outside-dns"'
cat ${SERVER_CONF} >&1
# gen udp client with tcp fallback
ovpn_genconfig -u udp://$SERV_IP -E "remote $SERV_IP 443 tcp" -E "remote vpn.example.com 443 tcp"
# nopass is insecure
EASYRSA_BATCH=1 EASYRSA_REQ_CN="Travis-CI Test CA" ovpn_initpki nopass
easyrsa build-client-full client-fallback nopass
ovpn_getclient client-fallback | tee /etc/openvpn/config-fallback.ovpn
CONFIG_REQUIRED_TCP_REMOTE="^remote $SERV_IP 443 tcp"
CONFIG_MATCH_TCP_REMOTE=$(busybox grep "remote $SERV_IP 443 tcp" /etc/openvpn/config-fallback.ovpn)
CONFIG_REQUIRED_TCP_REMOTE_2="^remote vpn.example.com 443 tcp"
CONFIG_MATCH_TCP_REMOTE_2=$(busybox grep "remote vpn.example.com 443 tcp" /etc/openvpn/config-fallback.ovpn)
if [[ $CONFIG_MATCH_TCP_REMOTE =~ $CONFIG_REQUIRED_TCP_REMOTE ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_TCP_REMOTE == $CONFIG_MATCH_TCP_REMOTE"
else
abort "==> Config match not found: $CONFIG_REQUIRED_TCP_REMOTE != $CONFIG_MATCH_TCP_REMOTE"
fi
if [[ $CONFIG_MATCH_TCP_REMOTE_2 =~ $CONFIG_REQUIRED_TCP_REMOTE_2 ]]
then
echo "==> Config match found: $CONFIG_REQUIRED_TCP_REMOTE_2 == $CONFIG_MATCH_TCP_REMOTE_2"
else
abort "==> Config match not found: $CONFIG_REQUIRED_TCP_REMOTE_2 != $CONFIG_MATCH_TCP_REMOTE_2"
fi

101
test/tests/revocation/run.sh Executable file
View File

@@ -0,0 +1,101 @@
#!/bin/bash
set -e
[ -n "${DEBUG+x}" ] && set -x
OVPN_DATA="basic-data"
CLIENT1="travis-client1"
CLIENT2="travis-client2"
IMG="kylemanna/openvpn"
NAME="ovpn-test"
CLIENT_DIR="$(readlink -f "$(dirname "$BASH_SOURCE")/../../client")"
SERV_IP="$(ip -4 -o addr show scope global | awk '{print $4}' | sed -e 's:/.*::' | head -n1)"
#
# Initialize openvpn configuration and pki.
#
docker volume create --name $OVPN_DATA
docker run --rm -v $OVPN_DATA:/etc/openvpn $IMG ovpn_genconfig -u udp://$SERV_IP
docker run --rm -v $OVPN_DATA:/etc/openvpn -it -e "EASYRSA_BATCH=1" -e "EASYRSA_REQ_CN=Travis-CI Test CA" $IMG ovpn_initpki nopass
#
# Fire up the server.
#
sudo iptables -N DOCKER || echo 'Firewall already configured'
sudo iptables -I FORWARD 1 -j DOCKER
docker run -d -v $OVPN_DATA:/etc/openvpn --cap-add=NET_ADMIN --privileged -p 1194:1194/udp --name $NAME $IMG
#
# Test that easy_rsa generate CRLs with 'next publish' set to 3650 days.
#
crl_next_update="$(docker exec $NAME openssl crl -nextupdate -noout -in /etc/openvpn/crl.pem | cut -d'=' -f2 | tr -d 'GMT')"
crl_next_update="$(date -u -d "$crl_next_update" "+%s")"
now="$(docker exec $NAME date "+%s")"
crl_remain="$(( $crl_next_update - $now ))"
crl_remain="$(( $crl_remain / 86400 ))"
if (( $crl_remain < 3649 )); then
echo "easy_rsa CRL next publish set to less than 3650 days." >&2
exit 2
fi
#
# Generate a first client certificate and configuration using $CLIENT1 as CN then revoke it.
#
docker exec -it $NAME easyrsa build-client-full $CLIENT1 nopass
docker exec -it $NAME ovpn_getclient $CLIENT1 > $CLIENT_DIR/config.ovpn
docker exec -it $NAME bash -c "echo 'yes' | ovpn_revokeclient $CLIENT1 remove"
#
# Test that openvpn client can't connect using $CLIENT1 config.
#
if docker run --rm -v $CLIENT_DIR:/client --cap-add=NET_ADMIN --privileged --net=host $IMG /client/wait-for-connect.sh; then
echo "Client was able to connect after revocation test #1." >&2
exit 2
fi
#
# Generate and revoke a second client certificate using $CLIENT2 as CN, then test for failed client connection.
#
docker exec -it $NAME easyrsa build-client-full $CLIENT2 nopass
docker exec -it $NAME ovpn_getclient $CLIENT2 > $CLIENT_DIR/config.ovpn
docker exec -it $NAME bash -c "echo 'yes' | ovpn_revokeclient $CLIENT2 remove"
if docker run --rm -v $CLIENT_DIR:/client --cap-add=NET_ADMIN --privileged --net=host $IMG /client/wait-for-connect.sh; then
echo "Client was able to connect after revocation test #2." >&2
exit 2
fi
#
# Restart the server
#
docker stop $NAME && docker start $NAME
#
# Test for failed connection using $CLIENT2 config again.
#
if docker run --rm -v $CLIENT_DIR:/client --cap-add=NET_ADMIN --privileged --net=host $IMG /client/wait-for-connect.sh; then
echo "Client was able to connect after revocation test #3." >&2
exit 2
fi
#
# Stop the server and clean up
#
docker kill $NAME && docker rm $NAME
docker volume rm $OVPN_DATA
sudo iptables -D FORWARD 1
#
# Celebrate
#
cat <<EOF
___________
< it worked >
-----------
\ ^__^
\ (oo)\_______
(__)\ )\/\\
||----w |
|| ||
EOF