From ed50537bddb0f3a9d032829b8a8e9e44d0c475ff Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 23 Mar 2021 14:15:25 +0800 Subject: [PATCH 01/21] simple htpasswd generator using openssl --- Dockerfile | 2 +- bin/openssl-htpasswd | 70 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100755 bin/openssl-htpasswd diff --git a/Dockerfile b/Dockerfile index 4ece3147..e949b632 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ LABEL maintainer="Kyle Manna " # Testing: pamtester 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 libqrencode && \ + apk add --update openvpn iptables bash easy-rsa openvpn-auth-pam google-authenticator pamtester libqrencode lighttpd && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* diff --git a/bin/openssl-htpasswd b/bin/openssl-htpasswd new file mode 100755 index 00000000..0c73a9a3 --- /dev/null +++ b/bin/openssl-htpasswd @@ -0,0 +1,70 @@ +#!/bin/bash +# + +print_help() +{ + echo "$(basename \"$0\") [-Dci] passwdfile username [password]" + echo -e "\t-D delete given user" + echo -e "\t-c truncate file (will contain only new user" + echo -e "\t-i read password from stdin" + echo -e "\t-h print this help" +} + +ensure_pwd() +{ + [ "$STDIN" = 1 ] && read -s PWD + [ -z "$PWD" ] && echo "missing or empty password" >&2 && print_help >&2 && exit 1 + PWD=$(openssl passwd -crypt "$PWD") +} + +action="modify" +while getopts "Dcid" arg; do + case $arg in + D) + action="delete" + ;; + c) + action="create" + ;; + i) + STDIN=1 + ;; + *) + echo "invalid usage" >&2 + print_help >&2 + exit 1 + ;; + esac +done +shift $(($OPTIND - 1)) + +FILE="$1" +USER="$2" +PWD="$3" + +[ -z "$USER" ] && echo "missing username" >&2 && print_help >&2 && exit 1 +[ -z "$FILE" ] && echo "missing filename" >&2 && print_help >&2 + +case "$action" in + delete) + [ ! -f "$FILE" ] && exit 0 + tmp=$(mktemp) + grep -v "^$USER:" "$FILE" > "$tmp" + cat "$tmp" > "$FILE" && rm "$tmp" && exit 0 + ;; + + create) + ensure_pwd + echo "$USER:$PWD" > "$FILE" && exit 0 + ;; + + modify) + ensure_pwd + tmp=$(mktemp) + (grep -v "^$USER:" "$FILE" 2>/dev/null; echo "$USER:$PWD") > "$tmp" && cat "$tmp" > "$FILE" && rm "$tmp" && exit 0 + ;; +esac + +# should not reach here +exit 1 + From 0d9567f5fcaf0698315c5656fe03354c167f3f30 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 23 Mar 2021 14:57:02 +0800 Subject: [PATCH 02/21] maintainer change --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e949b632..cedfb800 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -# Original credit: https://github.com/jpetazzo/dockvpn +# Original credit: https://github.com/kylemanna/docker-openvpn # Smallest base image FROM alpine:latest -LABEL maintainer="Kyle Manna " +LABEL maintainer="Nanda Bhikkhu " # Testing: pamtester RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories && \ From 67980d46d47129fbc8074cac7a89b57eb3564d41 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 23 Mar 2021 15:04:49 +0800 Subject: [PATCH 03/21] basics for lighttpd --- Dockerfile | 4 + lighttpd/config/lighttpd.conf | 285 ++++++++++++++++++++++++++++++++++ lighttpd/htdocs/defs | 9 ++ lighttpd/htdocs/index.cgi | 29 ++++ 4 files changed, 327 insertions(+) create mode 100644 lighttpd/config/lighttpd.conf create mode 100644 lighttpd/htdocs/defs create mode 100755 lighttpd/htdocs/index.cgi diff --git a/Dockerfile b/Dockerfile index cedfb800..5fdc0ce7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,9 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/reposi ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* +ADD ./lighttpd/htdocs/ /var/www/localhost/ +ADD ./lighttpd/config/* /etc/lighttpd/ + # Needed by scripts ENV OPENVPN=/etc/openvpn ENV EASYRSA=/usr/share/easy-rsa \ @@ -21,6 +24,7 @@ VOLUME ["/etc/openvpn"] # Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp` EXPOSE 1194/udp +EXPOSE 80/tcp CMD ["ovpn_run"] diff --git a/lighttpd/config/lighttpd.conf b/lighttpd/config/lighttpd.conf new file mode 100644 index 00000000..5f3fa800 --- /dev/null +++ b/lighttpd/config/lighttpd.conf @@ -0,0 +1,285 @@ +############################################################################### +# Default lighttpd.conf for Gentoo. +# $Header: /var/cvsroot/gentoo-x86/www-servers/lighttpd/files/conf/lighttpd.conf,v 1.3 2005/09/01 14:22:35 ka0ttic Exp $ +############################################################################### + +# {{{ variables +var.basedir = "/var/www/localhost" +var.logdir = "/var/log/lighttpd" +var.statedir = "/var/lib/lighttpd" +# }}} + +# {{{ modules +# At the very least, mod_access and mod_accesslog should be enabled. +# All other modules should only be loaded if necessary. +# NOTE: the order of modules is important. +server.modules = ( +# "mod_rewrite", +# "mod_redirect", +# "mod_alias", +# "mod_access", +# "mod_cml", +# "mod_trigger_b4_dl", + "mod_auth", + "mod_authn_file", +# "mod_status", +# "mod_setenv", +# "mod_proxy", +# "mod_simple_vhost", +# "mod_evhost", +# "mod_userdir", +# "mod_compress", +# "mod_ssi", +# "mod_usertrack", +# "mod_expire", +# "mod_secdownload", +# "mod_rrdtool", +# "mod_webdav", + "mod_accesslog" +) +# }}} + +# {{{ includes +include "mime-types.conf" +# uncomment for cgi support +include "mod_cgi.conf" +# uncomment for php/fastcgi support +# include "mod_fastcgi.conf" +# uncomment for php/fastcgi fpm support +# include "mod_fastcgi_fpm.conf" +# }}} + +# {{{ server settings +server.username = "root" +server.groupname = "root" + +server.document-root = var.basedir + "/htdocs" +server.pid-file = "/run/lighttpd.pid" + +server.errorlog = var.logdir + "/error.log" +# log errors to syslog instead +# server.errorlog-use-syslog = "enable" + +server.indexfiles = ("index.cgi", "index.html", + "index.htm", "default.htm") + +# server.tag = "lighttpd" + +server.follow-symlink = "enable" + +# event handler (defaults to "poll") +# see performance.txt +# +# for >= linux-2.4 +# server.event-handler = "linux-rtsig" +# for >= linux-2.6 +# server.event-handler = "linux-sysepoll" +# for FreeBSD +# server.event-handler = "freebsd-kqueue" + +# chroot to directory (defaults to no chroot) +# server.chroot = "/" + +# bind to port (defaults to 80) +# server.port = 81 + +# bind to name (defaults to all interfaces) +# server.bind = "grisu.home.kneschke.de" + +# error-handler for status 404 +# server.error-handler-404 = "/error-handler.html" +# server.error-handler-404 = "/error-handler.php" + +# Format: .html +# -> ..../status-404.html for 'File not found' +# server.errorfile-prefix = var.basedir + "/error/status-" + +# FAM support for caching stat() calls +# requires that lighttpd be built with USE=fam +# server.stat-cache-engine = "fam" +# }}} + +# {{{ mod_staticfile + +# which extensions should not be handled via static-file transfer +# (extensions that are usually handled by mod_cgi, mod_fastcgi, etc). +static-file.exclude-extensions = (".php", ".pl", ".cgi", ".fcgi") +# }}} + +# {{{ mod_accesslog +accesslog.filename = /dev/console +# }}} + +# {{{ mod_dirlisting +# enable directory listings +# dir-listing.activate = "enable" +# +# don't list hidden files/directories +# dir-listing.hide-dotfiles = "enable" +# +# use a different css for directory listings +# dir-listing.external-css = "/path/to/dir-listing.css" +# +# list of regular expressions. files that match any of the +# specified regular expressions will be excluded from directory +# listings. +# dir-listing.exclude = ("^\.", "~$") +# }}} + +# {{{ mod_access +# see access.txt + +url.access-deny = ("~", ".inc") +# }}} + +# {{{ mod_userdir +# see userdir.txt +# +# userdir.path = "public_html" +# userdir.exclude-user = ("root") +# }}} + +# {{{ mod_ssi +# see ssi.txt +# +# ssi.extension = (".shtml") +# }}} + +# {{{ mod_ssl +# see ssl.txt +# + ssl.engine = "enable" + ssl.pemfile = "/etc/openvpn/http/server.pem" + ssl.privkey = "/etc/openvpn/http/server.key" +# }}} + +# {{{ mod_status +# see status.txt +# +# status.status-url = "/server-status" +# status.config-url = "/server-config" +# }}} + +# {{{ mod_simple_vhost +# see simple-vhost.txt +# +# If you want name-based virtual hosting add the next three settings and load +# mod_simple_vhost +# +# document-root = +# virtual-server-root + virtual-server-default-host + virtual-server-docroot +# or +# virtual-server-root + http-host + virtual-server-docroot +# +# simple-vhost.server-root = "/home/weigon/wwwroot/servers/" +# simple-vhost.default-host = "grisu.home.kneschke.de" +# simple-vhost.document-root = "/pages/" +# }}} + +# {{{ mod_auth +# see authentication.txt +# + auth.backend = "plain" + auth.backend.htpasswd.file = "/etc/openvpn/http/htpasswd" + auth.backend.htpasswd.method = "basic" + +# auth.require = ( "/server-status" => +# ( +# "method" => "digest", +# "realm" => "download archiv", +# "require" => "user=jan" +# ), +# "/server-info" => +# ( +# "method" => "digest", +# "realm" => "download archiv", +# "require" => "valid-user" +# ) +# ) +# }}} + +# {{{ mod_evhost +# define a pattern for the host url finding +# %% => % sign +# %0 => domain name + tld +# %1 => tld +# %2 => domain name without tld +# %3 => subdomain 1 name +# %4 => subdomain 2 name +# +# evhost.path-pattern = "/home/storage/dev/www/%3/htdocs/" +# }}} + +# {{{ mod_expire +# expire.url = ( +# "/buggy/" => "access 2 hours", +# "/asdhas/" => "access plus 1 seconds 2 minutes" +# ) +# }}} + +# {{{ mod_rrdtool +# see rrdtool.txt +# +# rrdtool.binary = "/usr/bin/rrdtool" +# rrdtool.db-name = var.statedir + "/lighttpd.rrd" +# }}} + +# {{{ mod_setenv +# see setenv.txt +# +# setenv.add-request-header = ( "TRAV_ENV" => "mysql://user@host/db" ) +# setenv.add-response-header = ( "X-Secret-Message" => "42" ) +# }}} + +# {{{ mod_trigger_b4_dl +# see trigger_b4_dl.txt +# +# trigger-before-download.gdbm-filename = "/home/weigon/testbase/trigger.db" +# trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" ) +# trigger-before-download.trigger-url = "^/trigger/" +# trigger-before-download.download-url = "^/download/" +# trigger-before-download.deny-url = "http://127.0.0.1/index.html" +# trigger-before-download.trigger-timeout = 10 +# }}} + +# {{{ mod_cml +# see cml.txt +# +# don't forget to add index.cml to server.indexfiles +# cml.extension = ".cml" +# cml.memcache-hosts = ( "127.0.0.1:11211" ) +# }}} + +# {{{ mod_webdav +# see webdav.txt +# +# $HTTP["url"] =~ "^/dav($|/)" { +# webdav.activate = "enable" +# webdav.is-readonly = "enable" +# } +# }}} + +# {{{ extra rules +# +# set Content-Encoding and reset Content-Type for browsers that +# support decompressing on-thy-fly (requires mod_setenv) +# $HTTP["url"] =~ "\.gz$" { +# setenv.add-response-header = ("Content-Encoding" => "x-gzip") +# mimetype.assign = (".gz" => "text/plain") +# } + +# $HTTP["url"] =~ "\.bz2$" { +# setenv.add-response-header = ("Content-Encoding" => "x-bzip2") +# mimetype.assign = (".bz2" => "text/plain") +# } +# +# }}} + +# {{{ debug +# debug.log-request-header = "enable" +# debug.log-response-header = "enable" +# debug.log-request-handling = "enable" +# debug.log-file-not-found = "enable" +# }}} + +# vim: set ft=conf foldmethod=marker et : diff --git a/lighttpd/htdocs/defs b/lighttpd/htdocs/defs new file mode 100644 index 00000000..d01e8114 --- /dev/null +++ b/lighttpd/htdocs/defs @@ -0,0 +1,9 @@ +HEAD=' + + + + Openvpn client management + +' + +END='' diff --git a/lighttpd/htdocs/index.cgi b/lighttpd/htdocs/index.cgi new file mode 100755 index 00000000..33e53409 --- /dev/null +++ b/lighttpd/htdocs/index.cgi @@ -0,0 +1,29 @@ +#!/bin/bash + + + +print_user_table() +{ +# name,begin,end,status +# ariya,Jul 21 11:15:44 2020 GMT,Jul 6 11:15:44 2023 GMT,VALID + + echo '' + echo '' + + ovpn_listclients | tail -n +2 | while IFS=, read -r name valid_from valid_to status; do + echo "" + done + + echo '
namevalid fromvalid tostatusactions
$name$valid_from$valid_to$statusDELETE RENEW DOWNLOAD_CONFIG
' +} + + +MY_PATH=$(readlink -f "$BASH_SOURCE") +MYDIR=$(dirname "$MY_PATH") +. "$MYDIR/defs" + +echo "$HEAD" + +print_user_table + +echo "$END" From a5065e835e0aee7c631f805d389356d7d0ee182b Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 23 Mar 2021 16:17:57 +0800 Subject: [PATCH 04/21] some lighttpd fixes --- Dockerfile | 9 ++++++--- lighttpd/config/lighttpd.conf | 16 ++++++++-------- lighttpd/config/mod_cgi.conf | 31 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 lighttpd/config/mod_cgi.conf diff --git a/Dockerfile b/Dockerfile index 5fdc0ce7..48696ff1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,12 +7,13 @@ LABEL maintainer="Nanda Bhikkhu " # Testing: pamtester 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 libqrencode lighttpd && \ + apk add --update openvpn iptables bash easy-rsa openvpn-auth-pam google-authenticator pamtester libqrencode lighttpd lighttpd-mod_auth && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* -ADD ./lighttpd/htdocs/ /var/www/localhost/ +ADD ./lighttpd/htdocs/ /var/www/localhost/htdocs/ ADD ./lighttpd/config/* /etc/lighttpd/ +RUN chown -R openvpn:openvpn /var/www/localhost/htdocs /etc/lighttpd /var/log/lighttpd # Needed by scripts ENV OPENVPN=/etc/openvpn @@ -24,7 +25,7 @@ VOLUME ["/etc/openvpn"] # Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp` EXPOSE 1194/udp -EXPOSE 80/tcp +EXPOSE 443/tcp CMD ["ovpn_run"] @@ -33,3 +34,5 @@ RUN chmod a+x /usr/local/bin/* # Add support for OTP authentication using a PAM module ADD ./otp/openvpn /etc/pam.d/ + +# TODO: make sure here & in scripts that everything is done as "openvpn" user diff --git a/lighttpd/config/lighttpd.conf b/lighttpd/config/lighttpd.conf index 5f3fa800..fa51dc55 100644 --- a/lighttpd/config/lighttpd.conf +++ b/lighttpd/config/lighttpd.conf @@ -17,13 +17,14 @@ server.modules = ( # "mod_rewrite", # "mod_redirect", # "mod_alias", -# "mod_access", + "mod_access", # "mod_cml", # "mod_trigger_b4_dl", "mod_auth", "mod_authn_file", + "mod_openssl", # "mod_status", -# "mod_setenv", + "mod_setenv", # "mod_proxy", # "mod_simple_vhost", # "mod_evhost", @@ -50,8 +51,8 @@ include "mod_cgi.conf" # }}} # {{{ server settings -server.username = "root" -server.groupname = "root" +server.username = "openvpn" +server.groupname = "openvpn" server.document-root = var.basedir + "/htdocs" server.pid-file = "/run/lighttpd.pid" @@ -107,7 +108,7 @@ static-file.exclude-extensions = (".php", ".pl", ".cgi", ".fcgi") # }}} # {{{ mod_accesslog -accesslog.filename = /dev/console +accesslog.filename = var.logdir + "/access.log" # }}} # {{{ mod_dirlisting @@ -179,9 +180,8 @@ url.access-deny = ("~", ".inc") # {{{ mod_auth # see authentication.txt # - auth.backend = "plain" - auth.backend.htpasswd.file = "/etc/openvpn/http/htpasswd" - auth.backend.htpasswd.method = "basic" + auth.backend = "htpasswd" + auth.backend.htpasswd.userfile = "/etc/openvpn/http/htpasswd" # auth.require = ( "/server-status" => # ( diff --git a/lighttpd/config/mod_cgi.conf b/lighttpd/config/mod_cgi.conf new file mode 100644 index 00000000..7a8ad9fc --- /dev/null +++ b/lighttpd/config/mod_cgi.conf @@ -0,0 +1,31 @@ +############################################################################### +# mod_cgi.conf +# include'd by lighttpd.conf. +# $Header: /var/cvsroot/gentoo-x86/www-servers/lighttpd/files/conf/mod_cgi.conf,v 1.1 2005/08/27 12:36:13 ka0ttic Exp $ +############################################################################### + +# +# see cgi.txt for more information on using mod_cgi +# + +server.modules += ("mod_cgi") + +# +# Note that you'll also want to enable the +# cgi-bin alias via mod_alias (above). +# + +# disable directory listings +dir-listing.activate = "disable" +cgi.assign = ( + ".cgi" => "/bin/bash" + ) + +# TODO: send directly not to leave stuff around +cgi.x-sendfile = "enable" # default "disable" +cgi.x-sendfile-docroot = ( var.basedir + "/vpn_configs" ) + +setenv.set-environment = ( "PATH" => "/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin", + "OPENVPN" => "/etc/openvpn/") + +# vim: set ft=conf foldmethod=marker et : From 9fe28a167005a88c3e9c5924ed6baad617386cf8 Mon Sep 17 00:00:00 2001 From: nanda Date: Fri, 26 Mar 2021 15:37:06 +0800 Subject: [PATCH 05/21] web nearly done, init done as well --- Dockerfile | 3 ++- README.md | 1 + bin/ovpn_genconfig | 16 ++++++++++- bin/ovpn_run | 13 +++++++++ lighttpd/config/lighttpd.conf | 1 + lighttpd/htdocs/defs | 16 +++++++++++ lighttpd/htdocs/index.cgi | 50 ++++++++++++++++++++++++++++++----- 7 files changed, 92 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 48696ff1..e26a23ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,7 @@ ENV EASYRSA=/usr/share/easy-rsa \ EASYRSA_PKI=$OPENVPN/pki VOLUME ["/etc/openvpn"] +VOLUME ["/var/log"] # Internally uses port 1194/udp, remap using `docker run -p 443:1194/tcp` EXPOSE 1194/udp @@ -30,7 +31,7 @@ EXPOSE 443/tcp CMD ["ovpn_run"] ADD ./bin /usr/local/bin -RUN chmod a+x /usr/local/bin/* +RUN chmod a+x /usr/local/bin/* && chown -RH root:openvpn /usr/local/bin/ # Add support for OTP authentication using a PAM module ADD ./otp/openvpn /etc/pam.d/ diff --git a/README.md b/README.md index a9106737..c578bac9 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ 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). +NOTE: requires easy-rsa 3.0.8 or higher ## OpenVPN Details diff --git a/bin/ovpn_genconfig b/bin/ovpn_genconfig index c2ebca6c..c49d3fcc 100755 --- a/bin/ovpn_genconfig +++ b/bin/ovpn_genconfig @@ -89,6 +89,7 @@ usage() { echo " [-p PUSH ...]" echo " [-r ROUTE ...]" echo " [-s SERVER_SUBNET]" + echo " [-H]" echo echo "optional arguments:" echo " -2 Enable two factor authentication using Google Authenticator." @@ -104,6 +105,7 @@ usage() { 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 " -z Enable comp-lzo compression." + echo " -H Enable admin https server" } process_route_config() { @@ -129,6 +131,12 @@ process_extra_config() { [[ -n "$ovpn_extra_config" ]] && echo "$ovpn_extra_config" >> "$TMP_EXTRA_CONFIGFILE" } +gen_lighttpd_config() { + read -p "https username:" http_user || return 1 + read -sp "$http_user password:" http_password || return 1 + openssl-htpasswd /etc/openvpn/http/htpasswd "$http_user" "$http_password" +} + if [ "${DEBUG:-}" == "1" ]; then set -x fi @@ -167,12 +175,13 @@ OVPN_ROUTES=() OVPN_SERVER=192.168.255.0/24 OVPN_SERVER_URL='' OVPN_TLS_CIPHER='' +OVPN_HTTPS_ADMIN=0 # Import existing configuration if present [ -r "$OVPN_ENV" ] && source "$OVPN_ENV" # Parse arguments -while getopts ":a:e:E:C:T:r:s:du:bcp:n:k:DNm:f:tz2" opt; do +while getopts ":a:e:E:C:T:r:s:du:bcp:n:k:DNm:f:tz2H" opt; do case $opt in a) OVPN_AUTH="$OPTARG" @@ -253,6 +262,9 @@ while getopts ":a:e:E:C:T:r:s:du:bcp:n:k:DNm:f:tz2" opt; do f) OVPN_FRAGMENT="$OPTARG" ;; + H) + OVPN_HTTPS_ADMIN=1 + ;; \?) set +x echo "Invalid option: -$OPTARG" >&2 @@ -409,4 +421,6 @@ if diff -q "${bak:-}" "$conf" 2>/dev/null; then rm -fv "$bak" fi + [ "$OVPN_HTTPS_ADMIN" = 1 ] && gen_lighttpd_config + echo "Successfully generated config" diff --git a/bin/ovpn_run b/bin/ovpn_run index e93201bc..10c71b0a 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -101,5 +101,18 @@ if [ $? = 0 ]; then fi fi +chown -R openvpn:openvpn "$OPENVPN" + +echo "running https admin iface" +if [ "$OVPN_HTTPS_ADMIN" = 1 ]; then + env | grep EASYRSA | while read line; do echo "export $line"; done > $OPENVPN/http/easyrsa.env && chown openvpn $OPENVPN/http/easyrsa.env + lighttpd -f /etc/lighttpd/lighttpd.conf +fi + +# TODO: ovpn user echo "Running 'openvpn ${ARGS[@]} ${USER_ARGS[@]}'" exec openvpn ${ARGS[@]} ${USER_ARGS[@]} + +echo "shutting down https admin iface" +[ "$OVPN_HTTPS_ADMIN" = 1 ] && [ -f /var/run/lighttpd.pid ] && kill -TERM $(cat /var/run/lighttpd.pid) + diff --git a/lighttpd/config/lighttpd.conf b/lighttpd/config/lighttpd.conf index fa51dc55..d07e8ac5 100644 --- a/lighttpd/config/lighttpd.conf +++ b/lighttpd/config/lighttpd.conf @@ -58,6 +58,7 @@ server.document-root = var.basedir + "/htdocs" server.pid-file = "/run/lighttpd.pid" server.errorlog = var.logdir + "/error.log" +server.breakagelog = var.logdir + "/stderr.log" # log errors to syslog instead # server.errorlog-use-syslog = "enable" diff --git a/lighttpd/htdocs/defs b/lighttpd/htdocs/defs index d01e8114..85ece883 100644 --- a/lighttpd/htdocs/defs +++ b/lighttpd/htdocs/defs @@ -2,8 +2,24 @@ HEAD=' + Openvpn client management ' END='' + +function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; } + +parse_arg() +{ + while IFS='=' read -r -d '&' var val; do + var=$(urldecode "$var") + [ "$var" = "$1" ] && echo $(urldecode "$val") && return 0 + done <<<"${QUERY_STRING}&" + + return 1 +} +export -f parse_arg + +. /etc/openvpn/http/easyrsa.env diff --git a/lighttpd/htdocs/index.cgi b/lighttpd/htdocs/index.cgi index 33e53409..bea05014 100755 --- a/lighttpd/htdocs/index.cgi +++ b/lighttpd/htdocs/index.cgi @@ -1,20 +1,46 @@ #!/bin/bash - - print_user_table() { # name,begin,end,status # ariya,Jul 21 11:15:44 2020 GMT,Jul 6 11:15:44 2023 GMT,VALID - echo '' - echo '' + echo '
namevalid fromvalid tostatusactions
' + + echo ' + ' ovpn_listclients | tail -n +2 | while IFS=, read -r name valid_from valid_to status; do - echo "" + + echo " + + " done + + echo '
Existing users
namevalid fromvalid tostatusconfig
$name$valid_from$valid_to$statusDELETE RENEW DOWNLOAD_CONFIG
$name$valid_from$valid_to$statusDOWNLOAD_CONFIG
+

+ +
* Passphrase can be found in keepassxc pwd db
+ + ' } @@ -22,8 +48,20 @@ MY_PATH=$(readlink -f "$BASH_SOURCE") MYDIR=$(dirname "$MY_PATH") . "$MYDIR/defs" +action=$(parse_arg "action") +username=$(parse_arg "username") +capassphrase=$(parse_arg "capassphrase") +export EASYRSA_PASSIN="pass:$capassphrase" +export EASYRSA_BATCH=1 +case "$action" in + del) echo "$capassphrase" | ovpn_revokeclient "$username" remove 1>&2 && message="

User $username removed

";; + add) echo "$capassphrase" | easyrsa build-client-full "$username" nopass 1>&2 && message="

Succesfully created user $username

";; + renew) echo "$capassphrase" | easyrsa renew "$username" 1>&2 && message="

Certificate of user $username renewed

";; +esac + echo "$HEAD" print_user_table +echo "$message" echo "$END" From 3b1518d492c69930f69eeb905752a50f25a94fa5 Mon Sep 17 00:00:00 2001 From: nanda Date: Fri, 26 Mar 2021 18:01:10 +0800 Subject: [PATCH 06/21] some clarifications to index.cgi --- lighttpd/htdocs/index.cgi | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lighttpd/htdocs/index.cgi b/lighttpd/htdocs/index.cgi index bea05014..975d322a 100755 --- a/lighttpd/htdocs/index.cgi +++ b/lighttpd/htdocs/index.cgi @@ -8,7 +8,7 @@ print_user_table() echo '
' echo ' - ' + ' ovpn_listclients | tail -n +2 | while IFS=, read -r name valid_from valid_to status; do @@ -21,24 +21,28 @@ print_user_table()

Existing users
namevalid fromvalid tostatusconfig
UsernameValid fromValid toStatusConfig
- - - + + + + + + + +
Change user
Username
User management
Action
Username
CA passphrase*
-
* Passphrase can be found in keepassxc pwd db
+
* Global passphrase for the user management, can be found in keepassxc pwd db
' } From 4febd150df2ab2ec852d1cfabdc0ba6d4425209f Mon Sep 17 00:00:00 2001 From: nanda Date: Sat, 27 Mar 2021 15:03:30 +0800 Subject: [PATCH 07/21] change htpasswd encryption from 'crypt' to sha512 --- bin/openssl-htpasswd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/openssl-htpasswd b/bin/openssl-htpasswd index 0c73a9a3..d807419c 100755 --- a/bin/openssl-htpasswd +++ b/bin/openssl-htpasswd @@ -14,7 +14,7 @@ ensure_pwd() { [ "$STDIN" = 1 ] && read -s PWD [ -z "$PWD" ] && echo "missing or empty password" >&2 && print_help >&2 && exit 1 - PWD=$(openssl passwd -crypt "$PWD") + PWD=$(openssl passwd -6 "$PWD") } action="modify" From d2104da1dd6daae6edda3568de0e416019986f75 Mon Sep 17 00:00:00 2001 From: nanda Date: Sat, 27 Mar 2021 15:03:49 +0800 Subject: [PATCH 08/21] protect web by htpasswd --- lighttpd/config/lighttpd.conf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lighttpd/config/lighttpd.conf b/lighttpd/config/lighttpd.conf index d07e8ac5..9521b75a 100644 --- a/lighttpd/config/lighttpd.conf +++ b/lighttpd/config/lighttpd.conf @@ -184,19 +184,19 @@ url.access-deny = ("~", ".inc") auth.backend = "htpasswd" auth.backend.htpasswd.userfile = "/etc/openvpn/http/htpasswd" -# auth.require = ( "/server-status" => + auth.require = ( "" => # ( # "method" => "digest", # "realm" => "download archiv", # "require" => "user=jan" # ), # "/server-info" => -# ( -# "method" => "digest", -# "realm" => "download archiv", -# "require" => "valid-user" -# ) -# ) + ( + "method" => "basic", + "realm" => "Openvpn config", + "require" => "valid-user" + ) + ) # }}} # {{{ mod_evhost From 4bc499daa650f7e6b2ab6c3c863641a61d596747 Mon Sep 17 00:00:00 2001 From: nanda Date: Sat, 27 Mar 2021 15:25:14 +0800 Subject: [PATCH 09/21] forgotten files added --- lighttpd/htdocs/style.css | 11 +++++++++++ lighttpd/htdocs/user_config.cgi | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 lighttpd/htdocs/style.css create mode 100755 lighttpd/htdocs/user_config.cgi diff --git a/lighttpd/htdocs/style.css b/lighttpd/htdocs/style.css new file mode 100644 index 00000000..47d7d016 --- /dev/null +++ b/lighttpd/htdocs/style.css @@ -0,0 +1,11 @@ +table, th, td { + padding: 5px; +} + +th { + border: 1px solid black; +} + +tr { + height: 12px; +} diff --git a/lighttpd/htdocs/user_config.cgi b/lighttpd/htdocs/user_config.cgi new file mode 100755 index 00000000..86a88e08 --- /dev/null +++ b/lighttpd/htdocs/user_config.cgi @@ -0,0 +1,18 @@ +#!/bin/bash + +MY_PATH=$(readlink -f "$BASH_SOURCE") +MYDIR=$(dirname "$MY_PATH") +. "$MYDIR/defs" + + +username=$(parse_arg username) +[ "$?" != 0 -o -z "$username" ] && echo -e "$HEAD\n no valid user supplied!\n$END" && exit 1 + +CONFIG=$(ovpn_getclient "$username") +[ -z "$CONFIG" -o $? != 0 ] && echo -e "$HEAD error generating config for user $username\n$END" && exit 1 + +echo "Content-type: application/x-openvpn-profile" +echo "Content-Disposition:attachment; filename=$username.ovpn" +echo "" +echo "$CONFIG" + From c008010b08726882fa3d1ff3076c8af9261197dc Mon Sep 17 00:00:00 2001 From: nanda Date: Sat, 27 Mar 2021 15:50:04 +0800 Subject: [PATCH 10/21] use POST for form data --- lighttpd/htdocs/defs | 17 ++++++++++++++--- lighttpd/htdocs/index.cgi | 10 ++++++---- lighttpd/htdocs/user_config.cgi | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lighttpd/htdocs/defs b/lighttpd/htdocs/defs index 85ece883..74d158b4 100644 --- a/lighttpd/htdocs/defs +++ b/lighttpd/htdocs/defs @@ -11,15 +11,26 @@ END='' function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; } -parse_arg() + +parse_get_arg() { while IFS='=' read -r -d '&' var val; do var=$(urldecode "$var") [ "$var" = "$1" ] && echo $(urldecode "$val") && return 0 - done <<<"${QUERY_STRING}&" + done<<<"${QUERY_STRING}&" + return 1 +} +export -f parse_get_arg +parse_post_arg() +{ + while IFS='=' read -r -d '&' var val; do + var=$(urldecode "$var") + [ "$var" = "$1" ] && echo $(urldecode "$val") && return 0 + done<<<"${POST_STRING}&" return 1 } -export -f parse_arg +export -f parse_post_arg + . /etc/openvpn/http/easyrsa.env diff --git a/lighttpd/htdocs/index.cgi b/lighttpd/htdocs/index.cgi index 975d322a..df2c66a5 100755 --- a/lighttpd/htdocs/index.cgi +++ b/lighttpd/htdocs/index.cgi @@ -5,7 +5,7 @@ print_user_table() # name,begin,end,status # ariya,Jul 21 11:15:44 2020 GMT,Jul 6 11:15:44 2023 GMT,VALID - echo '
' + echo '
' echo '' @@ -52,9 +52,11 @@ MY_PATH=$(readlink -f "$BASH_SOURCE") MYDIR=$(dirname "$MY_PATH") . "$MYDIR/defs" -action=$(parse_arg "action") -username=$(parse_arg "username") -capassphrase=$(parse_arg "capassphrase") +read -t 5 POST_STRING + +action=$(parse_post_arg "action") +username=$(parse_post_arg "username") +capassphrase=$(parse_post_arg "capassphrase") export EASYRSA_PASSIN="pass:$capassphrase" export EASYRSA_BATCH=1 case "$action" in diff --git a/lighttpd/htdocs/user_config.cgi b/lighttpd/htdocs/user_config.cgi index 86a88e08..af30795c 100755 --- a/lighttpd/htdocs/user_config.cgi +++ b/lighttpd/htdocs/user_config.cgi @@ -5,7 +5,7 @@ MYDIR=$(dirname "$MY_PATH") . "$MYDIR/defs" -username=$(parse_arg username) +username=$(parse_get_arg username) [ "$?" != 0 -o -z "$username" ] && echo -e "$HEAD\n no valid user supplied!\n$END" && exit 1 CONFIG=$(ovpn_getclient "$username") From c3688c1df05c5c37461911585f96aae8a83da672 Mon Sep 17 00:00:00 2001 From: nanda Date: Sun, 28 Mar 2021 16:53:19 +0800 Subject: [PATCH 11/21] web passwd admin cgi --- lighttpd/htdocs/index.cgi | 3 ++ lighttpd/htdocs/web_password.cgi | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100755 lighttpd/htdocs/web_password.cgi diff --git a/lighttpd/htdocs/index.cgi b/lighttpd/htdocs/index.cgi index df2c66a5..4863416e 100755 --- a/lighttpd/htdocs/index.cgi +++ b/lighttpd/htdocs/index.cgi @@ -43,6 +43,9 @@ print_user_table()
Existing users
UsernameValid fromValid toStatusConfig
* Global passphrase for the user management, can be found in keepassxc pwd db
+
+ +
Openvpn admin web (this page) access management ' } diff --git a/lighttpd/htdocs/web_password.cgi b/lighttpd/htdocs/web_password.cgi new file mode 100755 index 00000000..fb68c9bd --- /dev/null +++ b/lighttpd/htdocs/web_password.cgi @@ -0,0 +1,59 @@ +#!/bin/bash + + +MY_PATH=$(readlink -f "$BASH_SOURCE") +MYDIR=$(dirname "$MY_PATH") +. "$MYDIR/defs" +db="$OPENVPN/http/htpasswd" + +read -t 5 POST_STRING + +username=$(parse_post_arg "username") +pass=$(parse_post_arg "password") + +res=-1 +if [ -n "$username" ]; then + if [ -z "$pass" ]; then + openssl-htpasswd -D "$db" "$username" + res=$? + else + openssl-htpasswd "$db" "$username" "$pass" + res=$? + fi +fi + +echo "$HEAD" +echo ' +

Openvpn admin web access config

+

Current user list

+

+

    +' +cat "$db" | cut -d ':' -f 1 | while read un; do echo "
  • $un
  • "; done +echo '

+

User Management

+

+

+ + + + + + + + + +
Username
Password*
+ +
+

+
*use empty password to delete user
' + +if [ "$res" != '-1' ]; then + [ "$res" = 0 ] && echo "

Success

" || echo "

Failed

" + echo "

(modyfiing user $username)

" +fi + +echo "$END" + From 80dd5ca691b980cdf84c46db3f41789e23302f36 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 30 Mar 2021 19:15:14 +0800 Subject: [PATCH 12/21] help for https server config --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c578bac9..dd50fd1b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ a corresponding [Digital Ocean Community Tutorial](http://bit.ly/1AGUZkq). * Start OpenVPN server process - docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn + docker run --user root -v $OVPN_DATA:/etc/openvpn -v $OVPN_LOGS:/var/log -d -p 1194:1194/udp -p 443:443 --cap-add=NET_ADMIN kylemanna/openvpn * Generate a client certificate without a passphrase @@ -133,6 +133,16 @@ and they might not answer to you. If that happens, use public DNS resolvers like those of Google (8.8.4.4 and 8.8.8.8) or OpenDNS (208.67.222.222 and 208.67.220.220). +## Https user admin +If you wish to use https interface for configuring the clients +* Pass -H to ovpn_genconfig + docker run -v $OVPN_DATA:/etc/openvpn -H --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM +It will ask you to specify username/password for the interface & for domain name for https certificate +* If you wish to supply your certificate/key for the https server, place it in $OPENVPN/http/ and set ownership and access rights. + cp server.pem server.key $OPENVPN/http/ + chown 101:102 $OPENVPN/http/server* + chmod 600 $OPENVPN/http/server.key + chmod 644 $OPENVPN/http/server.cer ## Security Discussion From 885a936bafb19ce2e34395b09a3de95994b2d863 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 30 Mar 2021 19:20:21 +0800 Subject: [PATCH 13/21] do stuff as openvpn user&group --- Dockerfile | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index e26a23ed..9fd37c18 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,9 +11,19 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/reposi ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* +ENV OVPN_USER=openvpn +ENV OVPN_GROUP=openvpn + ADD ./lighttpd/htdocs/ /var/www/localhost/htdocs/ ADD ./lighttpd/config/* /etc/lighttpd/ -RUN chown -R openvpn:openvpn /var/www/localhost/htdocs /etc/lighttpd /var/log/lighttpd +RUN sed -i /etc/lighttpd/lighttpd.conf -e 's/server\.username.*/server.username\ =\ "$OVPN_USER"/' -e 's/server\.groupname.*/server.groupname\ =\ "$OVPN_GROUP"/' && \ + chown -R ${OVPN_USER}:${OVPN_GROUP} /var/www/localhost/htdocs /etc/lighttpd /var/log/lighttpd + +ADD ./bin /usr/local/bin +RUN chmod 755 /usr/local/bin/* && chown root:${OVPN_GROUP} /usr/local/bin/* + +# Add support for OTP authentication using a PAM module +ADD ./otp/openvpn /etc/pam.d/ # Needed by scripts ENV OPENVPN=/etc/openvpn @@ -29,11 +39,5 @@ EXPOSE 1194/udp EXPOSE 443/tcp CMD ["ovpn_run"] +USER $OVPN_USER:$OVPN_GROUP -ADD ./bin /usr/local/bin -RUN chmod a+x /usr/local/bin/* && chown -RH root:openvpn /usr/local/bin/ - -# Add support for OTP authentication using a PAM module -ADD ./otp/openvpn /etc/pam.d/ - -# TODO: make sure here & in scripts that everything is done as "openvpn" user From 78084be3a20196299498dbcfddb6e2ad475c41f0 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 30 Mar 2021 19:20:52 +0800 Subject: [PATCH 14/21] gen https certificate if requested --- bin/ovpn_genconfig | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/bin/ovpn_genconfig b/bin/ovpn_genconfig index c49d3fcc..02be6f6b 100755 --- a/bin/ovpn_genconfig +++ b/bin/ovpn_genconfig @@ -134,7 +134,16 @@ process_extra_config() { gen_lighttpd_config() { read -p "https username:" http_user || return 1 read -sp "$http_user password:" http_password || return 1 - openssl-htpasswd /etc/openvpn/http/htpasswd "$http_user" "$http_password" + openssl-htpasswd "$OPENVPN/http/htpasswd" "$http_user" "$http_password" + + if [ ! -f "$OPENVPN/http/server.key" ]; then + echo "generating https server cert..." + read -p "https server domain/ip:" cn || return 1 + openssl req -x509 -newkey rsa:4096 -nodes -subj "/CN=$cn" -keyout "$OPENVPN/http/server.key" -out "$OPENVPN/http/server.pem" -days +365 || return 1 + chown openvpn:openvpn "$OPENVPN"/http/server.* + fi + + return 0 } if [ "${DEBUG:-}" == "1" ]; then @@ -421,6 +430,9 @@ if diff -q "${bak:-}" "$conf" 2>/dev/null; then rm -fv "$bak" fi - [ "$OVPN_HTTPS_ADMIN" = 1 ] && gen_lighttpd_config +[ "$OVPN_HTTPS_ADMIN" = 1 ] && gen_lighttpd_config + +# just to be sure if someone run this as root +chown -R openvpn:openvpn "$OPENVPN" "/var/www" "/etc/lighttpd" echo "Successfully generated config" From 8f269404d228042c34b2fc9f994257cdcfeec1fa Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 30 Mar 2021 19:21:10 +0800 Subject: [PATCH 15/21] force openvpn to switch user after init to 'openvpn' --- bin/ovpn_run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ovpn_run b/bin/ovpn_run index 10c71b0a..35d311f6 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -111,7 +111,7 @@ fi # TODO: ovpn user echo "Running 'openvpn ${ARGS[@]} ${USER_ARGS[@]}'" -exec openvpn ${ARGS[@]} ${USER_ARGS[@]} +exec openvpn --user ${OVPN_USER} -- group "${OVPN_GROUP}" ${ARGS[@]} ${USER_ARGS[@]} echo "shutting down https admin iface" [ "$OVPN_HTTPS_ADMIN" = 1 ] && [ -f /var/run/lighttpd.pid ] && kill -TERM $(cat /var/run/lighttpd.pid) From 7cf65db78318ebd3bc3fb1ec7b0fea0385493939 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 30 Mar 2021 21:20:25 +0800 Subject: [PATCH 16/21] fixed substition of user&group in Dockerfile, use OPENVPN in lighttpd config as well --- Dockerfile | 21 +++++++++++---------- bin/ovpn_genconfig | 2 ++ bin/ovpn_run | 5 ++++- lighttpd/config/lighttpd.conf | 7 ++++--- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9fd37c18..acc20940 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,13 +11,20 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/reposi ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* -ENV OVPN_USER=openvpn -ENV OVPN_GROUP=openvpn +# Needed by scripts +ENV OPENVPN=/etc/openvpn +ENV EASYRSA=/usr/share/easy-rsa \ + EASYRSA_CRL_DAYS=3650 \ + EASYRSA_PKI=$OPENVPN/pki \ + OVPN_USER=openvpn \ + OVPN_GROUP=openvpn ADD ./lighttpd/htdocs/ /var/www/localhost/htdocs/ ADD ./lighttpd/config/* /etc/lighttpd/ -RUN sed -i /etc/lighttpd/lighttpd.conf -e 's/server\.username.*/server.username\ =\ "$OVPN_USER"/' -e 's/server\.groupname.*/server.groupname\ =\ "$OVPN_GROUP"/' && \ - chown -R ${OVPN_USER}:${OVPN_GROUP} /var/www/localhost/htdocs /etc/lighttpd /var/log/lighttpd +RUN OPENVPN=$(echo $OPENVPN | sed -e 's/\//\\\//g') && sed -i /etc/lighttpd/lighttpd.conf -e 's/server\.username.*/server.username\ =\ "'$OVPN_USER'"/' \ + -e 's/server\.groupname.*/server.groupname\ =\ "'$OVPN_GROUP'"/' \ + -e 's/^var\.ovpndir.*$/var.ovpndir\ =\ "'${OPENVPN}'"/' && \ + chown -R ${OVPN_USER}:${OVPN_GROUP} /var/www/localhost/htdocs /etc/lighttpd /var/log/lighttpd ADD ./bin /usr/local/bin RUN chmod 755 /usr/local/bin/* && chown root:${OVPN_GROUP} /usr/local/bin/* @@ -25,12 +32,6 @@ RUN chmod 755 /usr/local/bin/* && chown root:${OVPN_GROUP} /usr/local/bin/* # Add support for OTP authentication using a PAM module ADD ./otp/openvpn /etc/pam.d/ -# Needed by scripts -ENV OPENVPN=/etc/openvpn -ENV EASYRSA=/usr/share/easy-rsa \ - EASYRSA_CRL_DAYS=3650 \ - EASYRSA_PKI=$OPENVPN/pki - VOLUME ["/etc/openvpn"] VOLUME ["/var/log"] diff --git a/bin/ovpn_genconfig b/bin/ovpn_genconfig index 02be6f6b..9267226f 100755 --- a/bin/ovpn_genconfig +++ b/bin/ovpn_genconfig @@ -185,6 +185,8 @@ OVPN_SERVER=192.168.255.0/24 OVPN_SERVER_URL='' OVPN_TLS_CIPHER='' OVPN_HTTPS_ADMIN=0 +OVPN_USER=openvpn +OVPN_GROUP=openvpn # Import existing configuration if present [ -r "$OVPN_ENV" ] && source "$OVPN_ENV" diff --git a/bin/ovpn_run b/bin/ovpn_run index 35d311f6..529c6198 100755 --- a/bin/ovpn_run +++ b/bin/ovpn_run @@ -54,6 +54,9 @@ addArg "--config" "$OPENVPN/openvpn.conf" source "$OPENVPN/ovpn_env.sh" +[ -n "${OVPN_USER}" ] && addArg "--user" "${OVPN_USER}" +[ -n "${OVPN_GROUP}" ] && addArg "--group" "${OVPN_GROUP}" + mkdir -p /dev/net if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200 @@ -111,7 +114,7 @@ fi # TODO: ovpn user echo "Running 'openvpn ${ARGS[@]} ${USER_ARGS[@]}'" -exec openvpn --user ${OVPN_USER} -- group "${OVPN_GROUP}" ${ARGS[@]} ${USER_ARGS[@]} +exec openvpn ${ARGS[@]} ${USER_ARGS[@]} echo "shutting down https admin iface" [ "$OVPN_HTTPS_ADMIN" = 1 ] && [ -f /var/run/lighttpd.pid ] && kill -TERM $(cat /var/run/lighttpd.pid) diff --git a/lighttpd/config/lighttpd.conf b/lighttpd/config/lighttpd.conf index 9521b75a..95ab1c7a 100644 --- a/lighttpd/config/lighttpd.conf +++ b/lighttpd/config/lighttpd.conf @@ -7,6 +7,7 @@ var.basedir = "/var/www/localhost" var.logdir = "/var/log/lighttpd" var.statedir = "/var/lib/lighttpd" +var.ovpndir = "/etc/openvpn" # }}} # {{{ modules @@ -151,8 +152,8 @@ url.access-deny = ("~", ".inc") # see ssl.txt # ssl.engine = "enable" - ssl.pemfile = "/etc/openvpn/http/server.pem" - ssl.privkey = "/etc/openvpn/http/server.key" + ssl.pemfile = var.ovpndir + "/http/server.pem" + ssl.privkey = var.ovpndir + "/http/server.key" # }}} # {{{ mod_status @@ -182,7 +183,7 @@ url.access-deny = ("~", ".inc") # see authentication.txt # auth.backend = "htpasswd" - auth.backend.htpasswd.userfile = "/etc/openvpn/http/htpasswd" + auth.backend.htpasswd.userfile = var.ovpndir + "/http/htpasswd" auth.require = ( "" => # ( From 557af3658af7c72ec94f133b13dc083410fd85ae Mon Sep 17 00:00:00 2001 From: nanda Date: Wed, 31 Mar 2021 07:10:32 +0800 Subject: [PATCH 17/21] note about https logs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd50fd1b..7eee8c53 100644 --- a/README.md +++ b/README.md @@ -136,13 +136,14 @@ resolvers like those of Google (8.8.4.4 and 8.8.8.8) or OpenDNS ## Https user admin If you wish to use https interface for configuring the clients * Pass -H to ovpn_genconfig - docker run -v $OVPN_DATA:/etc/openvpn -H --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM + docker run -v $OVPN_DATA:/etc/openvpn -v $OVPN_LOG:/var/log -H --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM It will ask you to specify username/password for the interface & for domain name for https certificate * If you wish to supply your certificate/key for the https server, place it in $OPENVPN/http/ and set ownership and access rights. cp server.pem server.key $OPENVPN/http/ chown 101:102 $OPENVPN/http/server* chmod 600 $OPENVPN/http/server.key chmod 644 $OPENVPN/http/server.cer +* Be aware that the lighttpd log files are not logrotated. ## Security Discussion From b17ab8e89327b64ef7d0c6f75eefc85940195825 Mon Sep 17 00:00:00 2001 From: nanda Date: Wed, 31 Mar 2021 11:18:17 +0800 Subject: [PATCH 18/21] note about alpine requirement --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7eee8c53..63081b25 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,6 @@ 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). -NOTE: requires easy-rsa 3.0.8 or higher ## OpenVPN Details @@ -145,6 +144,8 @@ It will ask you to specify username/password for the interface & for domain name chmod 644 $OPENVPN/http/server.cer * Be aware that the lighttpd log files are not logrotated. +NOTE: requires easy-rsa 3.0.8 or higher (make sure you make the docker image from alpine 3.13 or so) + ## Security Discussion The Docker container runs its own EasyRSA PKI Certificate Authority. This was From 503205dc067dead694e23196188ae8a5cc6f343f Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 18 Apr 2023 20:16:25 +0800 Subject: [PATCH 19/21] coreutils added for date -d is used bx easyrsa --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 Dockerfile diff --git a/Dockerfile b/Dockerfile old mode 100644 new mode 100755 index acc20940..0a94c5b4 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ LABEL maintainer="Nanda Bhikkhu " # Testing: pamtester 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 libqrencode lighttpd lighttpd-mod_auth && \ + apk add --update openvpn iptables bash easy-rsa openvpn-auth-pam google-authenticator pamtester libqrencode lighttpd lighttpd-mod_auth coreutils && \ ln -s /usr/share/easy-rsa/easyrsa /usr/local/bin && \ rm -rf /tmp/* /var/tmp/* /var/cache/apk/* /var/cache/distfiles/* From eabcaf5b66beecee7998895f6f8bcabe1a7b14dd Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 18 Apr 2023 21:18:14 +0800 Subject: [PATCH 20/21] fixed renew - use nopass --- lighttpd/htdocs/index.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lighttpd/htdocs/index.cgi b/lighttpd/htdocs/index.cgi index 4863416e..4d421d88 100755 --- a/lighttpd/htdocs/index.cgi +++ b/lighttpd/htdocs/index.cgi @@ -65,7 +65,7 @@ export EASYRSA_BATCH=1 case "$action" in del) echo "$capassphrase" | ovpn_revokeclient "$username" remove 1>&2 && message="

User $username removed

";; add) echo "$capassphrase" | easyrsa build-client-full "$username" nopass 1>&2 && message="

Succesfully created user $username

";; - renew) echo "$capassphrase" | easyrsa renew "$username" 1>&2 && message="

Certificate of user $username renewed

";; + renew) echo "$capassphrase" | easyrsa renew "$username" nopass 1>&2 && message="

Certificate of user $username renewed

";; esac echo "$HEAD" From 1a0b8256e00a6e7d41eb63b874ff4719e6ad941f Mon Sep 17 00:00:00 2001 From: nanda Date: Sun, 9 Jul 2023 01:06:41 +0800 Subject: [PATCH 21/21] allow renew "anytime" --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 0a94c5b4..c984c54e 100755 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,9 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/reposi ENV OPENVPN=/etc/openvpn ENV EASYRSA=/usr/share/easy-rsa \ EASYRSA_CRL_DAYS=3650 \ + EASYRSA_CERT_RENEW=3650 \ EASYRSA_PKI=$OPENVPN/pki \ + EASYRSA_BATCH=1 \ OVPN_USER=openvpn \ OVPN_GROUP=openvpn