Last active
June 25, 2016 17:52
-
-
Save benfairless/faf9c83ed9d1b43e8977 to your computer and use it in GitHub Desktop.
OpenVPN installation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Installs OpenVPN server on CentOS 7 | |
# Check yo' privilege | |
[[ $(id -u) != 0 ]] && echo 'You must run this script as root!' && exit 1 | |
################################################################################ | |
################################## VARIABLES ################################### | |
################################################################################ | |
# User-modifiable variables | |
IFACE='eth0' | |
ADDRESS=$(ip -4 addr show dev $IFACE | awk '/inet/{print $2}' | cut -d '/' -f 1) | |
PORT=1194 | |
DNS=192.168.139.104 | |
SUBNET=192.168.139.128 | |
MASK=255.255.255.128 | |
IFACE='eth0' | |
# Script static variables | |
CLIENT_TAR='/tmp/openvpn-client.tar.gz' | |
EASY_RSA='/etc/openvpn/.easy-rsa' | |
KEYS_DIR='/etc/openvpn/keys' | |
################################################################################ | |
################################## UTILITIES ################################### | |
################################################################################ | |
# Provides pretty colourful output with timestamps | |
output() { | |
local LABEL='OpenVPN' | |
local TIMESTAMP=$(date +%H:%M) | |
local COLOUR='\033[34m' # Blue | |
local RESET='\033[0m' # Standard | |
case $1 in | |
ERROR) local COLOUR='\033[31m' ;; # Red | |
SUCCESS) local COLOUR='\033[32m' ;; # Green | |
WARN) local COLOUR='\033[33m' ;; # Yellow | |
esac | |
while read LINE; do | |
echo -e "${COLOUR}${LABEL} [${TIMESTAMP}]${RESET} ${LINE}" | |
done | |
} | |
# Produces bold output | |
say() { | |
local BOLD=$(tput bold) | |
local STD=$(tput sgr0) | |
echo "${BOLD}$@${STD}" | |
} | |
# Creates a copy of $2 at $2.old | |
backup() { | |
[[ -z $1 ]] && echo 'backup() - No name variable set' | output ERROR | |
[[ -z $2 ]] && echo 'backup() - No file variable set' | output ERROR | |
local NAME=$1 | |
local FILE=$2 | |
if [[ -f $FILE ]]; then | |
echo "Backing up previous ${NAME} file..." | output | |
RESULT=$(cp -f ${FILE} ${FILE}.old 2>&1) | |
if [[ $? != 0 ]]; then | |
echo "Failed to backup previous ${FILE} file!" | output WARN | |
echo $RESULT | output WARN | |
else | |
echo "${NAME} backup created successfully" | output | |
fi | |
fi | |
} | |
# Just a pretty way of creating here documents, with error handling and backing | |
# up of the previous version. | |
createfile() { | |
[[ -z $1 ]] && echo 'createfile() - No name variable set' | output ERROR | |
[[ -z $2 ]] && echo 'createfile() - No file variable set' | output ERROR | |
local NAME=$1 | |
local FILE=$2 | |
backup "$NAME" "$FILE" | |
echo "Creating ${NAME}..." | output | |
while read -r LINE; do | |
# Add each line of STDIN to $CONTENT, along with a line break | |
local CONTENT+="${LINE}\n" | |
done | |
RESULT=$(echo -e ${CONTENT} > ${FILE} 2>&1) | |
if [[ $? != 0 ]]; then | |
echo "Failed to create ${NAME} file!" | output ERROR | |
echo $RESULT | output ERROR | |
exit 1 | |
else | |
echo "${NAME} file created successfully" | output | |
fi | |
} | |
# Checks that the previous command exited correctly and quits the script if not, | |
# with a pretty error message. Optionally a second string can be provided to | |
# print on success. | |
onfail() { | |
if [[ $? != 0 ]]; then | |
echo $1 | output ERROR | |
elif [[ ! -z $2 ]]; then | |
echo $2 | output | |
fi | |
} | |
################################################################################ | |
################################# INSTALLATION ################################# | |
################################################################################ | |
say 'Installing RPM packages...' | output | |
yum install -e 0 -y openvpn \ | |
easy-rsa \ | |
iptables \ | |
iptables-utils \ | |
iptables-services | output | |
onfail 'Failed to install RPM packages!' 'RPM packages installed successfully' | |
say 'Setting up Easy-RSA...' | output | |
mkdir -p $EASY_RSA | |
onfail "Failed to create Easy-RSA directory at ${EASY_RSA}" | |
cp -rf /usr/share/easy-rsa/2.0/* $EASY_RSA/ | |
onfail "Unable to copy Easy-RSA to $EASY_RSA" | |
cp -f $EASY_RSA/openssl-1.0.0.cnf $EASY_RSA/openssl.cnf | |
onfail "Unable to create $EASY_RSA/openssl.cnf to force the OpenSSL version" | |
restorecon -R $EASY_RSA | |
onfail "Unable to set SELinux context labels for ${EASY_RSA}" | |
################################################################################ | |
################################ CONFIGURATION ################################# | |
################################################################################ | |
say 'Generating configuration files...' | output | |
# This is the main configuration file for OpenVPN and provides the core | |
# configuration parameters for running the service. | |
createfile 'OpenVPN server configuration' '/etc/openvpn/server.conf' <<OPENVPN | |
local $ADDRESS | |
port $PORT | |
proto udp | |
dev tun | |
comp-lzo | |
topology subnet | |
user nobody | |
group nobody | |
persist-key | |
persist-tun | |
ifconfig-pool-persist ipp.txt | |
keepalive 10 120 | |
max-clients 100 | |
status openvpn-status.log | |
log-append openvpn.log | |
verb 3 | |
mute 20 | |
ca ${KEYS_DIR}/ca.crt | |
cert ${KEYS_DIR}/server.crt | |
key ${KEYS_DIR}/server.key | |
dh ${KEYS_DIR}/dh2048.pem | |
cipher AES-256-CBC | |
duplicate-cn | |
plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn | |
server ${SUBNET} ${MASK} | |
push "route 192.168.139.0 255.255.255.128" | |
push "dhcp-option DNS $DNS" | |
OPENVPN | |
# The PAM configuration file permits access through the VPN to users with local | |
# POSIX accounts. Additional configuration can be added to only permit certain | |
# groups or users to authenticate using this method. | |
createfile 'OpenVPN PAM security configuration' '/etc/pam.d/openvpn' <<PAM | |
auth required pam_unix.so shadow nodelay | |
account required pam_unix.so | |
PAM | |
# This minimal firewall configuration permits only SSH and OpenVPN connections | |
# as well as allowing SNAT connections through the VPN. | |
createfile 'Firewall rules' '/etc/sysconfig/iptables' <<IPTABLES | |
*nat | |
:PREROUTING ACCEPT [0:0] | |
:INPUT ACCEPT [0:0] | |
:OUTPUT ACCEPT [0:0] | |
:POSTROUTING ACCEPT [0:0] | |
-A POSTROUTING -o $IFACE -j SNAT --to-source $ADDRESS | |
-A POSTROUTING -o $IFACE -j SNAT --to-source $ADDRESS | |
COMMIT | |
*filter | |
:INPUT ACCEPT [0:0] | |
:FORWARD ACCEPT [0:0] | |
:OUTPUT ACCEPT [0:0] | |
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT | |
-A INPUT -p icmp -j ACCEPT | |
-A INPUT -i lo -j ACCEPT | |
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT | |
-A INPUT -i $IFACE -p udp -m state --state NEW -m udp --dport $PORT -j ACCEPT | |
-A INPUT -j REJECT --reject-with icmp-host-prohibited | |
COMMIT | |
IPTABLES | |
createfile 'Easy-RSA configuration' "${EASY_RSA}/vars" <<EASYRSA | |
export EASY_RSA="$EASY_RSA" | |
export OPENSSL="openssl" | |
export PKCS11TOOL="pkcs11-tool" | |
export GREP="grep" | |
export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA` | |
export KEY_DIR="$KEYS_DIR" | |
export PKCS11_MODULE_PATH="dummy" | |
export PKCS11_PIN="dummy" | |
export KEY_SIZE=2048 | |
export CA_EXPIRE=3650 | |
export KEY_EXPIRE=3650 | |
export KEY_COUNTRY="GB" | |
export KEY_PROVINCE="DEVON" | |
export KEY_CITY="PLYMOUTH" | |
export KEY_ORG="Land Registry" | |
export KEY_EMAIL="[email protected]" | |
export KEY_OU="IT Operations" | |
export KEY_NAME="server" | |
export KEY_CN="$(hostname)" | |
EASYRSA | |
createfile 'Client OpenVPN configuration' '/etc/openvpn/client.ovpn' <<CLIENT | |
client | |
dev tun | |
proto udp | |
remote $ADDRESS $PORT | |
resolv-retry infinite | |
remote-cert-tls server | |
ns-cert-type server | |
auth-nocache | |
auth-user-pass | |
nobind | |
persist-key | |
persist-tun | |
comp-lzo | |
verb 3 | |
ca ca.crt | |
cert client.crt | |
key client.key | |
cipher AES-256-CBC | |
CLIENT | |
say 'Configuring kernel parameters...' | output | |
createfile 'Kernel parameters' '/etc/sysctl.d/openvpn' <<KERNEL | |
net.ipv4.ip_forward = 1 | |
net.ipv4.conf.default.rp_filter = 0 | |
net.ipv4.conf.all.send_redirects = 0 | |
net.ipv4.conf.all.accept_redirects = 0 | |
net.ipv4.conf.default.send_redirects = 0 | |
net.ipv4.conf.default.accept_source_route = 0 | |
net.ipv4.icmp_ignore_bogus_error_responses = 1 | |
KERNEL | |
sysctl -p | |
onfail 'Unable to set runtime parameters' 'Runtime parameters set' | |
################################################################################ | |
################################### RUNTIME #################################### | |
################################################################################ | |
say 'Creating authentication certificates...' | output | |
source $EASY_RSA/vars | |
onfail "Failed to load Easy-RSA variables from ${EASY_RSA}/vars!" | |
bash $EASY_RSA/clean-all | output | |
onfail "Failed to clean up ${KEYS_DIR}!" | |
echo 'Creating Diffie Hellman key... (this may take some time)' | output | |
bash $EASY_RSA/build-dh 2>/dev/null | output | |
onfail 'Failed to create Diffie Hellman key!' | |
echo 'Creating Certificate Authority...' | output | |
bash $EASY_RSA/build-ca --batch 2>/dev/null | output | |
onfail 'Failed to create Certificate Authority!' | |
echo 'Creating server-side certificate...' | output | |
bash $EASY_RSA/build-key-server --batch server 2>/dev/null | output | |
onfail 'Failed to create server certificate!' | |
echo 'Creating client-side certificate...' | output | |
KEY_NAME="client" bash $EASY_RSA/build-key --batch client 2>/dev/null | output | |
onfail 'Failed to create client certificate!' | |
restorecon -R ${KEYS_DIR} | |
onfail "Unable to set SELinnux context labels for ${KEYS_DIR}" | |
say 'Reconfiguring SystemD network services...' | output | |
systemctl stop NetworkManager.service 2>&1 | output | |
onfail 'Failed to stop NetworkManager.service!' | |
systemctl stop firewalld.service 2>&1 | output | |
onfail 'Failed to stop firewalld.service!' | |
systemctl start iptables.service 2>&1 | output | |
onfail 'Failed to start iptables.service' | |
systemctl restart network.service 2>&1 | output | |
onfail 'Failed to restart network.service' | |
systemctl enable iptables.service >/dev/null 2>&1 | |
systemctl disable firewalld.service >/dev/null 2>&1 | |
systemctl disable NetworkManager.service >/dev/null 2>&1 | |
say 'Starting OpenVPN service...' | output | |
systemctl stop [email protected] 2>&1 | output | |
systemctl start [email protected] 2>&1 | output | |
onfail 'Failed to start OpenVPN service' | |
systemctl enable [email protected] >/dev/null 2>&1 | |
say 'Packaging client configuration...' | output | |
TMP_DIR="/tmp/$(openssl rand -hex 6)" | |
mkdir -p $TMP_DIR | |
onfail "Unable to create temporary directory at $TMP_DIR" | |
cp $KEYS_DIR/{ca.crt,client.crt,client.key} $TMP_DIR | |
onfail "Unable to copy necessary certificates to $TMP_DIR" | |
cp /etc/openvpn/client.ovpn $TMP_DIR | |
onfail "Unable to copy client configuration to $TMP_DIR" | |
tar -C $TMP_DIR -caf $CLIENT_TAR . | |
onfail "Unable to create compressed archive at $CLIENT_TAR" | |
rm -rf $TMP_DIR | |
echo "Client configuration can be found at $CLIENT_TAR" | output | |
[[ -d '/vagrant' ]] && cp -f $CLIENT_TAR /vagrant | |
say 'Installation complete!' | output SUCCESS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment