Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

https interface for user management #648

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
web nearly done, init done as well
  • Loading branch information
nanda committed Mar 26, 2021
commit 9fe28a167005a88c3e9c5924ed6baad617386cf8
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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/
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 15 additions & 1 deletion bin/ovpn_genconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand All @@ -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() {
Expand All @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
13 changes: 13 additions & 0 deletions bin/ovpn_run
Original file line number Diff line number Diff line change
Expand Up @@ -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)

1 change: 1 addition & 0 deletions lighttpd/config/lighttpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
16 changes: 16 additions & 0 deletions lighttpd/htdocs/defs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,24 @@ HEAD='<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" href="style.css">
<title>Openvpn client management</title>
</head>
<body>'

END='</body></html>'

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
50 changes: 44 additions & 6 deletions lighttpd/htdocs/index.cgi
Original file line number Diff line number Diff line change
@@ -1,29 +1,67 @@
#!/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 '<table>'
echo '<tr><th>name</th><th>valid from</th><th>valid to</th><th>status</th><th>actions</th></tr>'
echo '<form><table>'

echo '<tr><th colspan=5>Existing users</th></tr>
<tr><th>name</th><th>valid from</th><th>valid to</th><th>status</th><th>config</th></tr>'

ovpn_listclients | tail -n +2 | while IFS=, read -r name valid_from valid_to status; do
echo "<tr><td>$name</td><td>$valid_from</td><td>$valid_to</td><td>$status</td><td>DELETE RENEW DOWNLOAD_CONFIG</td></tr>"

echo "<tr><td>$name</td><td>$valid_from</td><td>$valid_to</td><td>$status</td>
<td><a href=\"user_config.cgi?username=$name\">DOWNLOAD_CONFIG</a></td>
</tr>"
done

echo '</table>
<br/><br/>
<div id="popup">
<table
<tr><th colspan=2>Change user</th></tr>
<tr><td>Username</td>
<td><input type="text" id="username" name="username"/></td>
</tr>

echo '</table>'
<tr><td>Action</td>
<td><select id="action" name="action">
<option value="del">delete</option>
<option value="add">add</option>
<option value="renew">renew</option>
</select></td>

<tr><td>CA passphrase*</td>
<td><input type="password" id="capassphrase" name="capassphrase"/></td>
<tr><td colspan=2><button type="submit" onclick="done()">Do it!</button></td></tr>
</table>
</div>
<div>* Passphrase can be found in keepassxc pwd db</div>

</form>'
}


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="<h2>User $username removed</h2>";;
add) echo "$capassphrase" | easyrsa build-client-full "$username" nopass 1>&2 && message="<h2>Succesfully created user $username<h2>";;
renew) echo "$capassphrase" | easyrsa renew "$username" 1>&2 && message="<h2>Certificate of user $username renewed</h2>";;
esac

echo "$HEAD"

print_user_table
echo "$message"

echo "$END"