mirror of
https://github.com/angristan/openvpn-install.git
synced 2025-10-24 11:47:37 +02:00
feat(headless): make script idempotent
This set of changes adjusts the script so that you can run it multiple times with the same input and not have any unexpected changes. This makes it appropriate for "enforcing state", as required by automated provisioners like Puppet, Salt, Chef, or Ansible.
- Unbound, OpenVPN, easy-rsa, and other dependencies are only installed from upstream if they are not already present. This prevents multiple runs of the script from causing unexpected version upgrades.
- The easy-rsa system is put in a folder called "easy-rsa-auto" so it can't conflict with the "easy-rsa" folder from some older OpenVPN packages
- The easy-rsa CA is only initialized once
- SERVER_CN and SERVER_NAME are randomly generated once and saved for future reference
- File append ('>>') is only done strictly after a file is created with '>' (e.g. /etc/sysctl.d/20-openvpn.conf)
- Clients are only added to easy-rsa once
- If AUTO_INSTALL == y, then the script operates in install mode and doesn't enter manageMenu
This commit is contained in:
@@ -97,6 +97,7 @@ function initialCheck () {
|
||||
}
|
||||
|
||||
function installUnbound () {
|
||||
# If Unbound isn't installed, install it
|
||||
if [[ ! -e /etc/unbound/unbound.conf ]]; then
|
||||
|
||||
if [[ "$OS" =~ (debian|ubuntu) ]]; then
|
||||
@@ -136,7 +137,9 @@ prefetch: yes' >> /etc/unbound/unbound.conf
|
||||
# Get root servers list
|
||||
curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache
|
||||
|
||||
mv /etc/unbound/unbound.conf /etc/unbound/unbound.conf.old
|
||||
if [[ ! -f /etc/unbound/unbound.conf.old ]]; then
|
||||
mv /etc/unbound/unbound.conf /etc/unbound/unbound.conf.old
|
||||
fi
|
||||
|
||||
echo 'server:
|
||||
use-syslog: yes
|
||||
@@ -595,9 +598,13 @@ function installOpenVPN () {
|
||||
PASS=${PASS:-1}
|
||||
CONTINUE=${CONTINUE:-y}
|
||||
|
||||
# Behind NAT, we'll default to the publicly reachable IPv4.
|
||||
PUBLIC_IPV4=$(curl ifconfig.co)
|
||||
ENDPOINT=${ENDPOINT:-$PUBLIC_IPV4}
|
||||
# Behind NAT, we'll default to the publicly reachable IPv4/IPv6.
|
||||
if [[ $IPV6_SUPPORT == "y" ]]; then
|
||||
PUBLIC_IP=$(curl https://ifconfig.co)
|
||||
else
|
||||
PUBLIC_IP=$(curl -4 https://ifconfig.co)
|
||||
fi
|
||||
ENDPOINT=${ENDPOINT:-$PUBLIC_IP}
|
||||
fi
|
||||
|
||||
# Run setup questions first, and set other variales if auto-install
|
||||
@@ -622,33 +629,42 @@ function installOpenVPN () {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$OS" =~ (debian|ubuntu) ]]; then
|
||||
apt-get update
|
||||
apt-get -y install ca-certificates gnupg
|
||||
# We add the OpenVPN repo to get the latest version.
|
||||
if [[ "$VERSION_ID" == "8" ]]; then
|
||||
echo "deb http://build.openvpn.net/debian/openvpn/stable jessie main" > /etc/apt/sources.list.d/openvpn.list
|
||||
wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add -
|
||||
# If OpenVPN isn't installed yet, install it. This script is more-or-less
|
||||
# idempotent on multiple runs, but will only install OpenVPN from upstream
|
||||
# the first time.
|
||||
if [[ ! -e /etc/openvpn/server.conf ]]; then
|
||||
if [[ "$OS" =~ (debian|ubuntu) ]]; then
|
||||
apt-get update
|
||||
apt-get -y install ca-certificates gnupg
|
||||
# We add the OpenVPN repo to get the latest version.
|
||||
if [[ "$VERSION_ID" = "8" ]]; then
|
||||
echo "deb http://build.openvpn.net/debian/openvpn/stable jessie main" > /etc/apt/sources.list.d/openvpn.list
|
||||
wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add -
|
||||
apt-get update
|
||||
fi
|
||||
if [[ "$VERSION_ID" = "16.04" ]]; then
|
||||
echo "deb http://build.openvpn.net/debian/openvpn/stable xenial main" > /etc/apt/sources.list.d/openvpn.list
|
||||
wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add -
|
||||
apt-get update
|
||||
fi
|
||||
# Ubuntu > 16.04 and Debian > 8 have OpenVPN >= 2.4 without the need of a third party repository.
|
||||
apt-get install -y openvpn iptables openssl wget ca-certificates curl
|
||||
elif [[ "$OS" = 'centos' ]]; then
|
||||
yum install -y epel-release
|
||||
yum install -y openvpn iptables openssl wget ca-certificates curl tar 'policycoreutils-python*'
|
||||
elif [[ "$OS" = 'amzn' ]]; then
|
||||
amazon-linux-extras install -y epel
|
||||
yum install -y openvpn iptables openssl wget ca-certificates curl
|
||||
elif [[ "$OS" = 'fedora' ]]; then
|
||||
dnf install -y openvpn iptables openssl wget ca-certificates curl
|
||||
elif [[ "$OS" = 'arch' ]]; then
|
||||
# Install required dependencies and upgrade the system
|
||||
pacman --needed --noconfirm -Syu openvpn iptables openssl wget ca-certificates curl
|
||||
fi
|
||||
if [[ "$VERSION_ID" == "16.04" ]]; then
|
||||
echo "deb http://build.openvpn.net/debian/openvpn/stable xenial main" > /etc/apt/sources.list.d/openvpn.list
|
||||
wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg | apt-key add -
|
||||
apt-get update
|
||||
# An old version of easy-rsa was available by default in some openvpn packages
|
||||
if [[ -d /etc/openvpn/easy-rsa/ ]]; then
|
||||
rm -rf /etc/openvpn/easy-rsa/
|
||||
fi
|
||||
# Ubuntu > 16.04 and Debian > 8 have OpenVPN >= 2.4 without the need of a third party repository.
|
||||
apt-get install -y openvpn iptables openssl wget ca-certificates curl
|
||||
elif [[ "$OS" == 'centos' ]]; then
|
||||
yum install -y epel-release
|
||||
yum install -y openvpn iptables openssl wget ca-certificates curl tar 'policycoreutils-python*'
|
||||
elif [[ "$OS" == 'amzn' ]]; then
|
||||
amazon-linux-extras install -y epel
|
||||
yum install -y openvpn iptables openssl wget ca-certificates curl
|
||||
elif [[ "$OS" == 'fedora' ]]; then
|
||||
dnf install -y openvpn iptables openssl wget ca-certificates curl
|
||||
elif [[ "$OS" == 'arch' ]]; then
|
||||
# Install required dependencies and upgrade the system
|
||||
pacman --needed --noconfirm -Syu openvpn iptables openssl wget ca-certificates curl
|
||||
fi
|
||||
|
||||
# Find out if the machine uses nogroup or nobody for the permissionless group
|
||||
@@ -658,63 +674,70 @@ function installOpenVPN () {
|
||||
NOGROUP=nobody
|
||||
fi
|
||||
|
||||
# An old version of easy-rsa was available by default in some openvpn packages
|
||||
if [[ -d /etc/openvpn/easy-rsa/ ]]; then
|
||||
rm -rf /etc/openvpn/easy-rsa/
|
||||
# Install the latest version of easy-rsa from source, if not already
|
||||
# installed.
|
||||
if [[ ! -d /etc/openvpn/easy-rsa/ ]]; then
|
||||
local version="3.0.6"
|
||||
wget -O ~/EasyRSA-unix-v${version}.tgz https://github.com/OpenVPN/easy-rsa/releases/download/v${version}/EasyRSA-unix-v${version}.tgz
|
||||
tar xzf ~/EasyRSA-unix-v${version}.tgz -C ~/
|
||||
mkdir -p /etc/openvpn/easy-rsa
|
||||
mv ~/EasyRSA-v${version}/* /etc/openvpn/easy-rsa/
|
||||
chown -R root:root /etc/openvpn/easy-rsa/
|
||||
rm -f ~/EasyRSA-unix-v${version}.tgz
|
||||
|
||||
cd /etc/openvpn/easy-rsa/ || return
|
||||
case $CERT_TYPE in
|
||||
1)
|
||||
echo "set_var EASYRSA_ALGO ec" > vars
|
||||
echo "set_var EASYRSA_CURVE $CERT_CURVE" >> vars
|
||||
;;
|
||||
2)
|
||||
echo "set_var EASYRSA_KEY_SIZE $RSA_KEY_SIZE" > vars
|
||||
;;
|
||||
esac
|
||||
|
||||
# Generate a random, alphanumeric identifier of 16 characters for CN and one for server name
|
||||
SERVER_CN="cn_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
|
||||
echo "$SERVER_CN" > SERVER_CN_GENERATED
|
||||
SERVER_NAME="server_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
|
||||
echo "$SERVER_NAME" > SERVER_NAME_GENERATED
|
||||
|
||||
echo "set_var EASYRSA_REQ_CN $SERVER_CN" >> vars
|
||||
|
||||
# Create the PKI, set up the CA, the DH params and the server certificate
|
||||
./easyrsa init-pki
|
||||
|
||||
# Workaround to remove unharmful error until easy-rsa 3.0.7
|
||||
# https://github.com/OpenVPN/easy-rsa/issues/261
|
||||
sed -i 's/^RANDFILE/#RANDFILE/g' pki/openssl-easyrsa.cnf
|
||||
|
||||
./easyrsa --batch build-ca nopass
|
||||
|
||||
if [[ $DH_TYPE == "2" ]]; then
|
||||
# ECDH keys are generated on-the-fly so we don't need to generate them beforehand
|
||||
openssl dhparam -out dh.pem $DH_KEY_SIZE
|
||||
fi
|
||||
|
||||
./easyrsa build-server-full "$SERVER_NAME" nopass
|
||||
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
|
||||
|
||||
case $TLS_SIG in
|
||||
1)
|
||||
# Generate tls-crypt key
|
||||
openvpn --genkey --secret /etc/openvpn/tls-crypt.key
|
||||
;;
|
||||
2)
|
||||
# Generate tls-auth key
|
||||
openvpn --genkey --secret /etc/openvpn/tls-auth.key
|
||||
;;
|
||||
esac
|
||||
else
|
||||
# If easy-rsa is already installed, grab the generated SERVER_NAME
|
||||
# for client configs
|
||||
cd /etc/openvpn/easy-rsa/ || return
|
||||
SERVER_NAME=$(cat SERVER_NAME_GENERATED)
|
||||
fi
|
||||
|
||||
# Install the latest version of easy-rsa from source
|
||||
local version="3.0.6"
|
||||
wget -O ~/EasyRSA-unix-v${version}.tgz https://github.com/OpenVPN/easy-rsa/releases/download/v${version}/EasyRSA-unix-v${version}.tgz
|
||||
tar xzf ~/EasyRSA-unix-v${version}.tgz -C ~/
|
||||
mv ~/EasyRSA-v${version} /etc/openvpn/easy-rsa
|
||||
chown -R root:root /etc/openvpn/easy-rsa/
|
||||
rm -f ~/EasyRSA-unix-v${version}.tgz
|
||||
|
||||
cd /etc/openvpn/easy-rsa/ || return
|
||||
case $CERT_TYPE in
|
||||
1)
|
||||
echo "set_var EASYRSA_ALGO ec" > vars
|
||||
echo "set_var EASYRSA_CURVE $CERT_CURVE" >> vars
|
||||
;;
|
||||
2)
|
||||
echo "set_var EASYRSA_KEY_SIZE $RSA_KEY_SIZE" > vars
|
||||
;;
|
||||
esac
|
||||
|
||||
# Generate a random, alphanumeric identifier of 16 characters for CN and one for server name
|
||||
SERVER_CN="cn_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
|
||||
SERVER_NAME="server_$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)"
|
||||
echo "set_var EASYRSA_REQ_CN $SERVER_CN" >> vars
|
||||
|
||||
# Create the PKI, set up the CA, the DH params and the server certificate
|
||||
./easyrsa init-pki
|
||||
|
||||
# Workaround to remove unharmful error until easy-rsa 3.0.7
|
||||
# https://github.com/OpenVPN/easy-rsa/issues/261
|
||||
sed -i 's/^RANDFILE/#RANDFILE/g' pki/openssl-easyrsa.cnf
|
||||
|
||||
./easyrsa --batch build-ca nopass
|
||||
|
||||
if [[ $DH_TYPE == "2" ]]; then
|
||||
# ECDH keys are generated on-the-fly so we don't need to generate them beforehand
|
||||
openssl dhparam -out dh.pem $DH_KEY_SIZE
|
||||
fi
|
||||
|
||||
./easyrsa build-server-full "$SERVER_NAME" nopass
|
||||
EASYRSA_CRL_DAYS=3650 ./easyrsa gen-crl
|
||||
|
||||
case $TLS_SIG in
|
||||
1)
|
||||
# Generate tls-crypt key
|
||||
openvpn --genkey --secret /etc/openvpn/tls-crypt.key
|
||||
;;
|
||||
2)
|
||||
# Generate tls-auth key
|
||||
openvpn --genkey --secret /etc/openvpn/tls-auth.key
|
||||
;;
|
||||
esac
|
||||
|
||||
# Move all the generated files
|
||||
cp pki/ca.crt pki/private/ca.key "pki/issued/$SERVER_NAME.crt" "pki/private/$SERVER_NAME.key" /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn
|
||||
if [[ $DH_TYPE == "2" ]]; then
|
||||
@@ -858,8 +881,8 @@ verb 3" >> /etc/openvpn/server.conf
|
||||
mkdir -p /var/log/openvpn
|
||||
|
||||
# Enable routing
|
||||
echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.d/20-openvpn.conf
|
||||
if [[ "$IPV6_SUPPORT" == 'y' ]]; then
|
||||
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/20-openvpn.conf
|
||||
if [[ "$IPV6_SUPPORT" = 'y' ]]; then
|
||||
echo 'net.ipv6.conf.all.forwarding=1' >> /etc/sysctl.d/20-openvpn.conf
|
||||
fi
|
||||
# Apply sysctl rules
|
||||
@@ -1028,16 +1051,23 @@ function newClient () {
|
||||
read -rp "Select an option [1-2]: " -e -i 1 PASS
|
||||
done
|
||||
|
||||
cd /etc/openvpn/easy-rsa/ || return
|
||||
case $PASS in
|
||||
1)
|
||||
./easyrsa build-client-full "$CLIENT" nopass
|
||||
;;
|
||||
2)
|
||||
echo "⚠️ You will be asked for the client password below ⚠️"
|
||||
./easyrsa build-client-full "$CLIENT"
|
||||
;;
|
||||
esac
|
||||
CLIENTEXISTS=$(tail -n +2 /etc/openvpn/easy-rsa/pki/index.txt | grep -c -E "/CN=$CLIENT\$")
|
||||
if [[ "$CLIENTEXISTS" = '1' ]]; then
|
||||
echo ""
|
||||
echo "The specified client CN was found in easy-rsa."
|
||||
else
|
||||
cd /etc/openvpn/easy-rsa/ || return
|
||||
case $PASS in
|
||||
1)
|
||||
./easyrsa build-client-full "$CLIENT" nopass
|
||||
;;
|
||||
2)
|
||||
echo "⚠️ You will be asked for the client password below ⚠️"
|
||||
./easyrsa build-client-full "$CLIENT"
|
||||
;;
|
||||
esac
|
||||
echo "Client $CLIENT added."
|
||||
fi
|
||||
|
||||
# Home directory of the user, where the client configuration (.ovpn) will be written
|
||||
if [ -e "/home/$CLIENT" ]; then # if $1 is a user name
|
||||
@@ -1086,7 +1116,7 @@ function newClient () {
|
||||
} >> "$homeDir/$CLIENT.ovpn"
|
||||
|
||||
echo ""
|
||||
echo "Client $CLIENT added, the configuration file is available at $homeDir/$CLIENT.ovpn."
|
||||
echo "The configuration file has been written to $homeDir/$CLIENT.ovpn."
|
||||
echo "Download the .ovpn file and import it in your OpenVPN client."
|
||||
|
||||
exit 0
|
||||
@@ -1276,7 +1306,7 @@ function manageMenu () {
|
||||
initialCheck
|
||||
|
||||
# Check if OpenVPN is already installed
|
||||
if [[ -e /etc/openvpn/server.conf ]]; then
|
||||
if [[ -e /etc/openvpn/server.conf && $AUTO_INSTALL != "y" ]]; then
|
||||
manageMenu
|
||||
else
|
||||
installOpenVPN
|
||||
|
||||
Reference in New Issue
Block a user