From 940c738b215c06e248f9ddeacd316cfad6eb58e9 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdanowski Date: Fri, 2 Dec 2022 08:44:36 -0600 Subject: [PATCH] Implement automatic profiles for openconnect (#16) --- Readme.md | 11 +++++++ vpn.sh | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 8267de6..f66a1b4 100644 --- a/Readme.md +++ b/Readme.md @@ -52,6 +52,17 @@ To connect to the `foo` VPN put your config file at `~/.vpn/foo.ovpn` and then y You can optionally put your credentials in `~/.vpn/foo.creds`. The username goes on the first line and the password on the second line. This gives up some security for the convenience of not having to enter your username and password. You will still be prompted for your 2FA code if your VPN endpoint requires it. You can run `chmod 600 ~/.vpn/foo.creds` to ensure only the file owner can read it. +### OpenConnect Profile + +OpenConnect offers an additional interactive command `openconnect_new_profile` which will guide you through a creation of a configuration profile. Once created, the profile is saved in `~/.vpn/NAME.profile` and `~/.vpn/NAME.secret`. To connect using a profile you can simply use `openconnect NAME` and the VPN connection will be established without any interaction. Currently the following options are supported: + +- Hostname & optional port +- Username authentication + - with password + - without password + - with password & external 2-factor authentication +- Connection group + ## Customizing You can customize options by setting the following environment variables. The defaults are shown below. diff --git a/vpn.sh b/vpn.sh index c396db1..66b5d1c 100644 --- a/vpn.sh +++ b/vpn.sh @@ -82,6 +82,8 @@ openconnect() { local authorizedKeys="${AUTHORIZED_KEYS}" local vpnConfig="$HOME/.vpn" + local vpnProfile="$vpnConfig/$vpnName.profile" + local vpnSecret="$vpnConfig/$vpnName.secret" local dockerImage="ethack/vpn" # AUTHORIZED_KEYS not specified. Use some defaults. @@ -102,7 +104,7 @@ openconnect() { local vpnCmd=("openconnect") dockerCmd+=("--rm" "--name" "vpn-$vpnName") dockerCmd+=("--hostname" "vpn-$vpnName") - dockerCmd+=("--interactive" "--tty") + dockerCmd+=("--interactive") dockerCmd+=("--cap-add" "NET_ADMIN") dockerCmd+=("--device" "/dev/net/tun") dockerCmd+=("--publish" "$bindIf:$sshPort:22") @@ -112,7 +114,20 @@ openconnect() { dockerCmd+=("--mount" "type=bind,src=$vpnConfig/$vpnName.xml,dst=/vpn/config,readonly=true") vpnCmd+=("--xmlconfig" "/vpn/config") fi - dockerCmd+=("$dockerImage") + if [ -f "${vpnProfile}" ]; then + source "${vpnProfile}" + vpnCmd+=("${OC_HOST}") + vpnCmd+=("--user" "${OC_USER}") + + if [ -f "${vpnSecret}" ]; then + vpnCmd+=("--passwd-on-stdin") + else + vpnCmd+=("--no-passwd") + fi + if ! [ -z "{$OC_GROUP}" ]; then + vpnCmd+=("--authgroup" "${OC_GROUP}") + fi + fi # append any extra args provided vpnCmd+=("$@") @@ -131,7 +146,76 @@ openconnect() { echo "Use: ssh $vpnName" echo "============================================" - "${dockerCmd[@]}" "${vpnCmd[@]}" + if [ -f "${vpnSecret}" ]; then + dockerCmd+=("--interactive") + dockerCmd+=("$dockerImage") + cat "${vpnSecret}" - | "${dockerCmd[@]}" "${vpnCmd[@]}" + else + dockerCmd+=("--interactive" "--tty") + dockerCmd+=("$dockerImage") + "${dockerCmd[@]}" "${vpnCmd[@]}" + fi +} + +openconnect_new_profile() { + echo "This tool will create automatic OpenConnect profile to allow automatic connections" + echo + + echo -n "Name for the profile: " + read -r vpnProfile + if ! [[ "${vpnProfile}" =~ ^[A-Za-z0-9_]+$ ]]; then + echo "Profile name should only contain letters, numbers, and underscores!" + return 1 + fi + local vpnProfilePath="$HOME/.vpn/${vpnProfile}.profile" + if [[ -f "${vpnProfilePath}" ]]; then + echo "Profile \"${vpnProfile}\" already exists in ${vpnProfilePath}" + return 1 + fi + + echo -n "Hostname: " + read -r vpnHost + + echo -n "Port [443]: " + read -r vpnPort + + echo -n "Username: " + read -r vpnUser + + echo -n "Password: " + read -s -r vpnPass + echo + + local vpnHostPort="${vpnHost}" + if [[ ! -z "${vpnPort}" ]]; then + vpnHostPort+="${vpnPort}" + fi + echo + echo "Some VPNs require group code. Go to https://${vpnHostPort}/ and see if there's a \"GROUP\" dropdown present. It will show all possible group codes. If there's no such dropdown leave this field empty." + echo -n "Group: " + read -r vpnGroup + + echo + echo "If your VPN requires two-factor authentication you need to specify its type. Usually it will be one of the following: pin, push, phone, sms. If your VPN doesn't use 2FA leave this field empty." + echo -n "2FA Type: " + read -r vpn2FaType + + printf "OC_HOST=%q\n" "${vpnHostPort}" >> "${vpnProfilePath}" + printf "OC_USER=%q\n" "${vpnUser}" >> "${vpnProfilePath}" + printf "OC_GROUP=%q\n" "${vpnGroup}" >> "${vpnProfilePath}" + + local vpnSecretPath="$HOME/.vpn/${vpnProfile}.secret" + echo "${vpnPass}" > "${vpnSecretPath}" + if ! [ -z "${vpn2FaType}" ]; then + echo "${vpn2FaType}" >> "${vpnSecretPath}" + fi + + chmod 0400 "${vpnProfilePath}" + chmod 0400 "${vpnSecretPath}" + + echo + echo "Your new profile has been saved in ${vpnProfilePath} and ${vpnSecretPath}" + echo "Connect by typing: openconnect ${vpnProfile}" } # Create and configure the .ssh/config.d directory if it's not already