Skip to content

Instantly share code, notes, and snippets.

@jriguera
Created September 21, 2020 08:27
Embed
What would you like to do?
AnyConnect VPN up/down single command + service cleanup
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
readonly _CISCO_VPN="/opt/cisco/anyconnect/bin/vpn"
readonly _GREEN='\033[0;32m'
readonly _RED='\033[0;31m'
readonly _NC='\033[0m'
bg_services() {
if [[ "$(uname)" == 'Darwin' ]]; then
local COMMAND="$1"
echo 'Managing background services - you may need to enter your system password'
for BG_TASK in ciscod64 vpnagentd; do
sudo launchctl "$COMMAND" "/Library/LaunchDaemons/com.cisco.anyconnect.$BG_TASK.plist" >/dev/null 2>/dev/null
done
fi
}
vpn_up() {
local VPN_PROFILE="$1"
local VPN_USERNAME="$2"
local VPN_PASSWORD="$3"
bg_services 'load'
"$_CISCO_VPN" -s connect "$VPN_PROFILE" <<EOF
1
$VPN_USERNAME
$VPN_PASSWORD
y
exit
EOF
}
vpn_down() {
"$_CISCO_VPN" disconnect
bg_services 'unload'
}
vpn_verify() {
local VPN_PROFILE="$1"
local VPN_USERNAME="$2"
local CISCO_CERT_DIR="$HOME/.cisco/certificates"
local CLIENT_CERT="$CISCO_CERT_DIR/client/$VPN_USERNAME.pem"
local CLIENT_KEY="$CISCO_CERT_DIR/client/private/$VPN_USERNAME.key"
local RESULT=0
mkdir -p "$CISCO_CERT_DIR/ca" "$CISCO_CERT_DIR/client/private"
echo -n "Checking client certificate exists..."
if [[ ! -f "$CLIENT_CERT" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo "Cannot find client certificate at $CLIENT_CERT"
RESULT=1
else
echo -e "${_GREEN}OK${_NC}"
fi
echo -n "Checking client key exists..."
if [[ ! -f "$CLIENT_KEY" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo "Cannot find client key at $CLIENT_KEY"
RESULT=1
else
echo -e "${_GREEN}OK${_NC}"
fi
if [[ $RESULT -eq 1 ]]; then
echo "If you have your certificate as a PFX file you can extract the components via:"
echo " openssl pkcs12 -in $VPN_USERNAME.pfx -clcerts -nokeys -out $CLIENT_CERT"
echo " openssl pkcs12 -in $VPN_USERNAME.pfx -nocerts -nodes -out $CLIENT_KEY"
fi
local DIGI_CERT_ROOT="DigiCertAssuredIDRootCA.crt.pem"
echo -n "Checking root certificate $DIGI_CERT_ROOT exists..."
if [[ ! -f "$CISCO_CERT_DIR/ca/$DIGI_CERT_ROOT" ]]; then
local DIGI_CERT_URI="https://cacerts.digicert.com/DigiCertAssuredIDRootCA.crt.pem"
echo -e "${_RED}FAILED${_NC}"
echo -n "Downloading from $DIGI_CERT_URI..."
curl -Lso "$CISCO_CERT_DIR/ca/$DIGI_CERT_ROOT" "$DIGI_CERT_URI"
if [[ ! -f "$CISCO_CERT_DIR/ca/$DIGI_CERT_ROOT" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo "Cannot find expected root certificate at $CISCO_CERT_DIR/ca/$DIGI_CERT_ROOT"
echo " You can download it from $DIGI_CERT_URI"
RESULT=1
else
echo -e "${_GREEN}OK${_NC}"
fi
else
echo -e "${_GREEN}OK${_NC}"
fi
for ROOT_CERT_URI in https://pki.springernature.com/certenroll/senldogo5092_SpringerNatureRootCA.crt \
https://pki.springernature.com/certenroll/senldogo5337.springernature.com_SpringerNatureCA4.crt; do
local LOCAL_CERT="$(echo $ROOT_CERT_URI | cut -d_ -f2 | cut -d. -f1 ).pem"
echo -n "Checking root certificate $LOCAL_CERT exists..."
if [[ ! -f "$CISCO_CERT_DIR/ca/$LOCAL_CERT" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo -n " Downloading from $ROOT_CERT_URI..."
curl -Ls "$ROOT_CERT_URI" | openssl x509 -inform DER -outform PEM -out $CISCO_CERT_DIR/ca/$LOCAL_CERT
if [[ ! -f "$CISCO_CERT_DIR/ca/$LOCAL_CERT" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo "Cannot find expected root certificate at $CISCO_CERT_DIR/ca/$LOCAL_CERT"
echo " You can download it from $ROOT_CERT_URI and then convert to PEM format with"
echo " openssl x509 -inform DER -outform PEM -in senldogo????_$LOCAL_CERT.crt -out $LOCAL_CERT.pem"
RESULT=1
else
echo -e "${_GREEN}OK${_NC}"
fi
else
echo -e "${_GREEN}OK${_NC}"
fi
done
if [[ -f "$CLIENT_CERT" && -f "$CLIENT_KEY" ]]; then
echo -n "Checking client certificate and key match..."
local CLIENT_CERT_HASH=$(openssl x509 -noout -modulus -in "$CLIENT_CERT" | openssl md5)
local CLIENT_KEY_HASH=$(openssl rsa -noout -modulus -in "$CLIENT_KEY" | openssl md5)
if [[ "$CLIENT_CERT_HASH" != "$CLIENT_KEY_HASH" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo "Client certificate and client key do not appear to match"
RESULT=1
else
echo -e "${_GREEN}OK${_NC}"
fi
fi
if [[ $RESULT == 0 ]]; then
echo -n "Checking certificate chain..."
local VERIFY_OUTPUT=$(openssl verify -CAfile "$HOME/.cisco/certificates/ca/SpringerNatureRootCA.pem" \
-untrusted "$HOME/.cisco/certificates/ca/SpringerNatureCA4.pem" \
"$HOME/.cisco/certificates/client/$VPN_USERNAME.pem" 2>&1)
if echo "$VERIFY_OUTPUT" | grep OK >/dev/null 2>&1; then
echo -e "${_GREEN}OK${_NC}"
else
echo -e "${_RED}FAILED${_NC}"
echo " Output was: $VERIFY_OUTPUT"
RESULT=1
fi
else
echo "WARN: Certificate chain check will be skipped due to previous errors"
fi
echo -n "Checking profile $VPN_PROFILE exists..."
if [[ ! -f "/opt/cisco/anyconnect/profile/$VPN_PROFILE.xml" ]]; then
echo -e "${_RED}FAILED${_NC}"
echo "Profile $VPN_PROFILE was not found - please connect once via '$_CISCO_VPN -s connect vpn.springernature.com' to download this"
RESULT=1
else
echo -e "${_GREEN}OK${_NC}"
fi
return $RESULT
}
verify_prerequisites() {
if [[ ! -f "$_CISCO_VPN" ]]; then
echo "Cannot find AnyConnect at $_CISCO_VPN - please ensure you've installed it."
echo "You can download binaries from https://anyconnect.springernature.com"
return 1
fi
}
main() {
local ACTION="${1:-}"
verify_prerequisites
if [[ "$(uname)" == 'Darwin' ]]; then
local VPN_USERNAME="$(security find-generic-password -a "$USER" -s sn-vpn-username -w 2>/dev/null)"
local VPN_PASSWORD="$(security find-generic-password -a "$USER" -s sn-vpn-password -w 2>/dev/null)"
else
local VPN_USERNAME="$(secret-tool lookup $USER sn-vpn-username)"
local VPN_PASSWORD="$(secret-tool lookup $USER sn-vpn-password)"
fi
if [[ -z "$VPN_USERNAME" || -z "$VPN_PASSWORD" ]]; then
if [[ "$(uname)" == 'Darwin' ]]; then
echo "Error: you must add your VPN username/password to Keychain!"
echo ' security add-generic-password -a "$USER" -s sn-vpn-username -w "<your username>"'
echo ' security add-generic-password -a "$USER" -s sn-vpn-password -w "<your password>"'
else
echo "Error: you must add your VPN username/password to secret-tool!"
echo ' echo "<your username>" | secret-tool store --label="$USER sn-vpn-username" $USER sn-vpn-username'
echo ' echo "<your password>" | secret-tool store --label="$USER sn-vpn-password" $USER sn-vpn-password'
fi
exit 1
fi
local VPN_PROFILE="SpringerNature-Int"
case "$ACTION" in
up)
vpn_up "$VPN_PROFILE" "$VPN_USERNAME" "$VPN_PASSWORD"
;;
down)
vpn_down
;;
verify)
vpn_verify "$VPN_PROFILE" "$VPN_USERNAME"
;;
*)
echo "Usage: $0 <up|down|verify>"
exit 1
;;
esac
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment