From dec1b44091dc6494540641cdce7012b998960cdc Mon Sep 17 00:00:00 2001 From: hwdsl2 Date: Tue, 12 Jan 2016 18:28:34 -0600 Subject: [PATCH] Update VPN scripts for better security and usability - Install Fail2Ban to protect SSH server from web attacks - Check public/private IPs against regex for the correct format - Use printf instead of "read -r -p" for better POSIX compliance - Other small code enhancements to the scripts - Update README.md to add "OS update" to Installation --- README.md | 12 +++-- vpnsetup.sh | 64 +++++++++++++++------- vpnsetup_centos.sh | 97 ++++++++++++++++++++++++---------- vpnupgrade_Libreswan.sh | 21 +++++--- vpnupgrade_Libreswan_centos.sh | 35 +++++++----- 5 files changed, 159 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 0b927fd..c96abf7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Scripts for automatic configuration of IPsec/L2TP VPN server on Ubuntu 14.04 & 1 We will use Libreswan as the IPsec server, and xl2tpd as the L2TP provider. -#### Link to my VPN tutorial with detailed usage instructions +### My VPN tutorial with detailed usage instructions ## Features @@ -25,7 +25,7 @@ We will use Libreswan as th ## Requirements A newly created Amazon EC2 instance, using these AMIs: (See the link above for usage instructions) -- Ubuntu 14.04 (Trusty) or 12.04 (Precise) +- Ubuntu 14.04 (Trusty) or 12.04 (Precise) - Debian 8 (Jessie) EC2 Images - CentOS 7 (x86_64) with Updates HVM - CentOS 6 (x86_64) with Updates HVM - Does NOT have cloud-init. Run script manually via SSH. @@ -48,6 +48,8 @@ OpenVZ VPS users should instead use Google Public DNS when the VPN connection is active. This setting is controlled by `ms-dns` in `/etc/ppp/options.xl2tpd`. -If using Amazon EC2, these ports must be open in the instance's security group: **UDP ports 500 & 4500**, and **TCP port 22** (optional, for SSH). +If using Amazon EC2, these ports must be open in the instance's security group: **UDP ports 500 & 4500** (for the VPN), and **TCP port 22** (optional, for SSH). If your server uses a custom SSH port (not 22), or if you wish to allow other services through IPTables, be sure to edit the IPTables rules in the scripts before using. The scripts will backup files `/etc/rc.local`, `/etc/sysctl.conf`, `/etc/iptables.rules` and `/etc/sysconfig/iptables` before overwriting them. Backups can be found under the same folder with `.old` suffix. +iPhone/iOS users: If unable to connect, try replacing `rightprotoport=17/%any` in `ipsec.conf` with `rightprotoport=17/0`. + ## Copyright and license Copyright (C) 2014 Lin Song   View my profile on LinkedIn diff --git a/vpnsetup.sh b/vpnsetup.sh index ea19e02..17b9e35 100644 --- a/vpnsetup.sh +++ b/vpnsetup.sh @@ -40,15 +40,19 @@ VPN_PASSWORD=your_very_secure_password # IMPORTANT NOTES: -# If you need multiple VPN users with different credentials, -# please see: https://gist.github.com/hwdsl2/123b886f29f4c689f531 - -# For Windows users, a one-time registry change is required in order to -# connect to a VPN server behind NAT (e.g. in Amazon EC2). Please see: +# For **Windows users**, a one-time registry change is required for connections +# to a VPN server behind NAT (e.g. Amazon EC2). Please see: # https://documentation.meraki.com/MX-Z/Client_VPN/Troubleshooting_Client_VPN#Windows_Error_809 -# If using Amazon EC2, these ports must be open in the security group of -# your VPN server: UDP ports 500 & 4500, and TCP port 22 (optional, for SSH). +# To support multiple VPN users with different credentials, see: +# https://gist.github.com/hwdsl2/123b886f29f4c689f531 + +# Clients are configured to use Google Public DNS when the VPN connection is active. +# This setting is controlled by "ms-dns" in /etc/ppp/options.xl2tpd. +# https://developers.google.com/speed/public-dns/ + +# If using Amazon EC2, these ports must be open in the instance's security group: +# UDP ports 500 & 4500 (for the VPN), and TCP port 22 (optional, for SSH). # If your server uses a custom SSH port (not 22), or if you wish to allow other services # through IPTables, be sure to edit the IPTables rules below before running this script. @@ -56,7 +60,7 @@ VPN_PASSWORD=your_very_secure_password # This script will backup /etc/rc.local, /etc/sysctl.conf and /etc/iptables.rules # before overwriting them. Backups can be found under the same folder with .old suffix. -# iPhone/iOS users may need to replace this line in ipsec.conf: +# iPhone/iOS users: In case you're unable to connect, try replacing this line in /etc/ipsec.conf: # "rightprotoport=17/%any" with "rightprotoport=17/0". # Create and change to working dir @@ -91,6 +95,17 @@ PRIVATE_IP=$(wget --retry-connrefused -t 3 -T 15 -qO- 'http://169.254.169.254/la [ "$PRIVATE_IP" = "" ] && PRIVATE_IP=$(ifconfig eth0 | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*') [ "$PRIVATE_IP" = "" ] && { echo "Could not find Private IP, please edit the VPN script manually."; exit 1; } +# Check public/private IPs for correct format +IP_REGEX="^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" +if printf %s "$PUBLIC_IP" | grep -vEq "$IP_REGEX"; then + echo "Could not find valid Public IP, please edit the VPN script manually." + exit 1 +fi +if printf %s "$PRIVATE_IP" | grep -vEq "$IP_REGEX"; then + echo "Could not find valid Private IP, please edit the VPN script manually." + exit 1 +fi + # Install necessary packages apt-get -y install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ libcap-ng-dev libcap-ng-utils libselinux1-dev \ @@ -99,15 +114,18 @@ apt-get -y install libnss3-dev libnspr4-dev pkg-config libpam0g-dev \ apt-get -y --no-install-recommends install xmlto apt-get -y install xl2tpd +# Install Fail2Ban to protect SSH server +apt-get -y install fail2ban + # Compile and install Libreswan (https://libreswan.org/) -# To upgrade Libreswan when a newer version is available, just re-run -# these commands with the new "SWAN_VER", and then restart services with -# "service ipsec restart" and "service xl2tpd restart". SWAN_VER=3.16 -SWAN_URL=https://download.libreswan.org/libreswan-${SWAN_VER}.tar.gz -wget -t 3 -T 30 -qO- $SWAN_URL | tar xvz -[ ! -d libreswan-${SWAN_VER} ] && { echo "Could not retrieve Libreswan source files. Aborting."; exit 1; } -cd libreswan-${SWAN_VER} +SWAN_FILE="libreswan-${SWAN_VER}.tar.gz" +SWAN_URL="https://download.libreswan.org/${SWAN_FILE}" +wget -t 3 -T 30 -nv -O "$SWAN_FILE" "$SWAN_URL" +[ ! -f "$SWAN_FILE" ] && { echo "Could not retrieve Libreswan source file. Aborting."; exit 1; } +/bin/rm -rf "/opt/src/libreswan-${SWAN_VER}" +tar xvzf "$SWAN_FILE" && rm -f "$SWAN_FILE" +cd "libreswan-${SWAN_VER}" || { echo "Failed to enter Libreswan source directory. Aborting."; exit 1; } make programs && make install # Prepare various config files @@ -290,8 +308,10 @@ cat > /etc/rc.local < /proc/sys/net/ipv4/ip_forward exit 0 EOF @@ -303,9 +323,15 @@ if [ ! -f /etc/ipsec.d/cert8.db ] ; then fi /sbin/sysctl -p +/bin/chmod +x /etc/rc.local /bin/chmod +x /etc/network/if-pre-up.d/iptablesload /bin/chmod 600 /etc/ipsec.secrets /etc/ppp/chap-secrets /sbin/iptables-restore < /etc/iptables.rules -/usr/sbin/service ipsec restart -/usr/sbin/service xl2tpd restart +/usr/sbin/service fail2ban stop >/dev/null 2>&1 +/usr/sbin/service ipsec stop >/dev/null 2>&1 +/usr/sbin/service xl2tpd stop >/dev/null 2>&1 + +/usr/sbin/service fail2ban start +/usr/sbin/service ipsec start +/usr/sbin/service xl2tpd start diff --git a/vpnsetup_centos.sh b/vpnsetup_centos.sh index f6cd82a..fbd0e9c 100644 --- a/vpnsetup_centos.sh +++ b/vpnsetup_centos.sh @@ -51,15 +51,19 @@ VPN_PASSWORD=your_very_secure_password # IMPORTANT NOTES: -# If you need multiple VPN users with different credentials, -# please see: https://gist.github.com/hwdsl2/123b886f29f4c689f531 - -# For Windows users, a one-time registry change is required in order to -# connect to a VPN server behind NAT (e.g. in Amazon EC2). Please see: +# For **Windows users**, a one-time registry change is required for connections +# to a VPN server behind NAT (e.g. Amazon EC2). Please see: # https://documentation.meraki.com/MX-Z/Client_VPN/Troubleshooting_Client_VPN#Windows_Error_809 -# If using Amazon EC2, these ports must be open in the security group of -# your VPN server: UDP ports 500 & 4500, and TCP port 22 (optional, for SSH). +# To support multiple VPN users with different credentials, see: +# https://gist.github.com/hwdsl2/123b886f29f4c689f531 + +# Clients are configured to use Google Public DNS when the VPN connection is active. +# This setting is controlled by "ms-dns" in /etc/ppp/options.xl2tpd. +# https://developers.google.com/speed/public-dns/ + +# If using Amazon EC2, these ports must be open in the instance's security group: +# UDP ports 500 & 4500 (for the VPN), and TCP port 22 (optional, for SSH). # If your server uses a custom SSH port (not 22), or if you wish to allow other services # through IPTables, be sure to edit the IPTables rules below before running this script. @@ -67,7 +71,7 @@ VPN_PASSWORD=your_very_secure_password # This script will backup /etc/rc.local, /etc/sysctl.conf and /etc/sysconfig/iptables # before overwriting them. Backups can be found under the same folder with .old suffix. -# iPhone/iOS users may need to replace this line in ipsec.conf: +# iPhone/iOS users: In case you're unable to connect, try replacing this line in /etc/ipsec.conf: # "rightprotoport=17/%any" with "rightprotoport=17/0". # Create and change to working dir @@ -100,6 +104,17 @@ PRIVATE_IP=$(wget --retry-connrefused -t 3 -T 15 -qO- 'http://169.254.169.254/la [ "$PRIVATE_IP" = "" ] && PRIVATE_IP=$(ifconfig eth0 | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*') [ "$PRIVATE_IP" = "" ] && { echo "Could not find Private IP, please edit the VPN script manually."; exit 1; } +# Check public/private IPs for correct format +IP_REGEX="^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" +if printf %s "$PUBLIC_IP" | grep -vEq "$IP_REGEX"; then + echo "Could not find valid Public IP, please edit the VPN script manually." + exit 1 +fi +if printf %s "$PRIVATE_IP" | grep -vEq "$IP_REGEX"; then + echo "Could not find valid Private IP, please edit the VPN script manually." + exit 1 +fi + # Add the EPEL repository if grep -qs "release 6" /etc/redhat-release; then EPEL_RPM="epel-release-6-8.noarch.rpm" @@ -111,9 +126,9 @@ else echo "Sorry, this script only supports versions 6 and 7 of CentOS/RHEL." exit 1 fi -wget -t 3 -T 30 -nv -O $EPEL_RPM $EPEL_URL -[ ! -f $EPEL_RPM ] && { echo "Could not retrieve EPEL repository RPM file. Aborting."; exit 1; } -rpm -ivh --force $EPEL_RPM && /bin/rm -f $EPEL_RPM +wget -t 3 -T 30 -nv -O "$EPEL_RPM" "$EPEL_URL" +[ ! -f "$EPEL_RPM" ] && { echo "Could not retrieve EPEL repository RPM file. Aborting."; exit 1; } +rpm -ivh --force "$EPEL_RPM" && /bin/rm -f "$EPEL_RPM" # Install necessary packages yum -y install nss-devel nspr-devel pkgconfig pam-devel \ @@ -122,29 +137,31 @@ yum -y install nss-devel nspr-devel pkgconfig pam-devel \ fipscheck-devel unbound-devel gmp gmp-devel xmlto yum -y install ppp xl2tpd +# Install Fail2Ban to protect SSH server +yum -y install fail2ban + # Installed Libevent 2. Use backported version for CentOS 6. if grep -qs "release 6" /etc/redhat-release; then LE2_URL="https://people.redhat.com/pwouters/libreswan-rhel6" RPM1="libevent2-2.0.21-1.el6.x86_64.rpm" RPM2="libevent2-devel-2.0.21-1.el6.x86_64.rpm" - wget -t 3 -T 30 -nv -O $RPM1 $LE2_URL/$RPM1 - wget -t 3 -T 30 -nv -O $RPM2 $LE2_URL/$RPM2 - [ ! -f $RPM1 ] || [ ! -f $RPM2 ] && { echo "Could not retrieve Libevent2 RPM file(s). Aborting."; exit 1; } - rpm -ivh --force $RPM1 $RPM2 && /bin/rm -f $RPM1 $RPM2 + wget -t 3 -T 30 -nv -O "$RPM1" "$LE2_URL/$RPM1" + wget -t 3 -T 30 -nv -O "$RPM2" "$LE2_URL/$RPM2" + [ ! -f "$RPM1" ] || [ ! -f "$RPM2" ] && { echo "Could not retrieve Libevent2 RPM file(s). Aborting."; exit 1; } + rpm -ivh --force "$RPM1" "$RPM2" && /bin/rm -f "$RPM1" "$RPM2" elif grep -qs "release 7" /etc/redhat-release; then yum -y install libevent-devel fi # Compile and install Libreswan (https://libreswan.org/) -# To upgrade Libreswan when a newer version is available, just re-run these -# commands with the new "SWAN_VER", then restore SELinux contexts using -# the commands at the end of this script, and finally restart services with -# "service ipsec restart" and "service xl2tpd restart". SWAN_VER=3.16 -SWAN_URL=https://download.libreswan.org/libreswan-${SWAN_VER}.tar.gz -wget -t 3 -T 30 -qO- $SWAN_URL | tar xvz -[ ! -d libreswan-${SWAN_VER} ] && { echo "Could not retrieve Libreswan source files. Aborting."; exit 1; } -cd libreswan-${SWAN_VER} +SWAN_FILE="libreswan-${SWAN_VER}.tar.gz" +SWAN_URL="https://download.libreswan.org/${SWAN_FILE}" +wget -t 3 -T 30 -nv -O "$SWAN_FILE" "$SWAN_URL" +[ ! -f "$SWAN_FILE" ] && { echo "Could not retrieve Libreswan source file. Aborting."; exit 1; } +/bin/rm -rf "/opt/src/libreswan-${SWAN_VER}" +tar xvzf "$SWAN_FILE" && rm -f "$SWAN_FILE" +cd "libreswan-${SWAN_VER}" || { echo "Failed to enter Libreswan source directory. Aborting."; exit 1; } make programs && make install # Prepare various config files @@ -306,6 +323,25 @@ COMMIT COMMIT EOF +if [ ! -f /etc/fail2ban/jail.local ] ; then + +cat > /etc/fail2ban/jail.local </dev/null cat > /etc/rc.local < /etc/rc.local < /proc/sys/net/ipv4/ip_forward EOF @@ -333,8 +370,14 @@ restorecon /usr/local/sbin -Rv 2>/dev/null restorecon /usr/local/libexec/ipsec -Rv 2>/dev/null /sbin/sysctl -p +/bin/chmod +x /etc/rc.local /bin/chmod 600 /etc/ipsec.secrets /etc/ppp/chap-secrets /sbin/iptables-restore < /etc/sysconfig/iptables -/sbin/service ipsec restart -/sbin/service xl2tpd restart +/sbin/service fail2ban stop >/dev/null 2>&1 +/sbin/service ipsec stop >/dev/null 2>&1 +/sbin/service xl2tpd stop >/dev/null 2>&1 + +/sbin/service fail2ban start +/sbin/service ipsec start +/sbin/service xl2tpd start diff --git a/vpnupgrade_Libreswan.sh b/vpnupgrade_Libreswan.sh index 925ebea..512fa30 100644 --- a/vpnupgrade_Libreswan.sh +++ b/vpnupgrade_Libreswan.sh @@ -10,6 +10,7 @@ # Attribution required: please include my name in any derivative and let me # know how you have improved it! +# Check https://libreswan.org and update version number if necessary SWAN_VER=3.16 if [ "$(lsb_release -si)" != "Ubuntu" ] && [ "$(lsb_release -si)" != "Debian" ]; then @@ -34,11 +35,14 @@ if [ "$?" != "0" ]; then exit 1 fi +clear + ipsec --version 2>/dev/null | grep -qs "Libreswan ${SWAN_VER}" if [ "$?" = "0" ]; then echo "You already have Libreswan ${SWAN_VER} installed! " echo - read -r -p "Do you wish to continue anyway? [y/N] " response + printf "Do you wish to continue anyway? [y/N] " + read -r response case $response in [yY][eE][sS]|[yY]) echo @@ -55,7 +59,8 @@ echo "This is intended for use on VPN servers with an older version of Libreswan echo "Your existing VPN configuration files will NOT be modified." echo -read -r -p "Do you wish to continue? [y/N] " response +printf "Do you wish to continue? [y/N] " +read -r response case $response in [yY][eE][sS]|[yY]) echo @@ -86,14 +91,16 @@ apt-get -y --no-install-recommends install xmlto apt-get -y install xl2tpd # Compile and install Libreswan (https://libreswan.org/) -SWAN_URL=https://download.libreswan.org/libreswan-${SWAN_VER}.tar.gz +SWAN_FILE="libreswan-${SWAN_VER}.tar.gz" +SWAN_URL="https://download.libreswan.org/${SWAN_FILE}" +wget -t 3 -T 30 -nv -O "$SWAN_FILE" "$SWAN_URL" +[ ! -f "$SWAN_FILE" ] && { echo "Could not retrieve Libreswan source file. Aborting."; exit 1; } /bin/rm -rf "/opt/src/libreswan-${SWAN_VER}" -wget -t 3 -T 30 -qO- $SWAN_URL | tar xvz -[ ! -d libreswan-${SWAN_VER} ] && { echo "Could not retrieve Libreswan source files. Aborting."; exit 1; } -cd libreswan-${SWAN_VER} +tar xvzf "$SWAN_FILE" && rm -f "$SWAN_FILE" +cd "libreswan-${SWAN_VER}" || { echo "Failed to enter Libreswan source directory. Aborting."; exit 1; } make programs && make install -ipsec --version 2>/dev/null | grep -qs "Libreswan ${SWAN_VER}" +ipsec --version 2>/dev/null | grep -qs "${SWAN_VER}" if [ "$?" != "0" ]; then echo echo "Sorry, something went wrong." diff --git a/vpnupgrade_Libreswan_centos.sh b/vpnupgrade_Libreswan_centos.sh index 891d766..0d7225c 100644 --- a/vpnupgrade_Libreswan_centos.sh +++ b/vpnupgrade_Libreswan_centos.sh @@ -10,6 +10,7 @@ # Attribution required: please include my name in any derivative and let me # know how you have improved it! +# Check https://libreswan.org and update version number if necessary SWAN_VER=3.16 if [ ! -f /etc/redhat-release ]; then @@ -39,11 +40,14 @@ if [ "$?" != "0" ]; then exit 1 fi +clear + ipsec --version 2>/dev/null | grep -qs "Libreswan ${SWAN_VER}" if [ "$?" = "0" ]; then echo "You already have Libreswan ${SWAN_VER} installed! " echo - read -r -p "Do you wish to continue anyway? [y/N] " response + printf "Do you wish to continue anyway? [y/N] " + read -r response case $response in [yY][eE][sS]|[yY]) echo @@ -60,7 +64,8 @@ echo "This is intended for use on VPN servers with an older version of Libreswan echo "Your existing VPN configuration files will NOT be modified." echo -read -r -p "Do you wish to continue? [y/N] " response +printf "Do you wish to continue? [y/N] " +read -r response case $response in [yY][eE][sS]|[yY]) echo @@ -91,9 +96,9 @@ else echo "Sorry, this script only supports versions 6 and 7 of CentOS/RHEL." exit 1 fi -wget -t 3 -T 30 -nv -O $EPEL_RPM $EPEL_URL -[ ! -f $EPEL_RPM ] && { echo "Could not retrieve EPEL repository RPM file. Aborting."; exit 1; } -rpm -ivh --force $EPEL_RPM && /bin/rm -f $EPEL_RPM +wget -t 3 -T 30 -nv -O "$EPEL_RPM" "$EPEL_URL" +[ ! -f "$EPEL_RPM" ] && { echo "Could not retrieve EPEL repository RPM file. Aborting."; exit 1; } +rpm -ivh --force "$EPEL_RPM" && /bin/rm -f "$EPEL_RPM" # Install necessary packages yum -y install nss-devel nspr-devel pkgconfig pam-devel \ @@ -107,23 +112,25 @@ if grep -qs "release 6" /etc/redhat-release; then LE2_URL="https://people.redhat.com/pwouters/libreswan-rhel6" RPM1="libevent2-2.0.21-1.el6.x86_64.rpm" RPM2="libevent2-devel-2.0.21-1.el6.x86_64.rpm" - wget -t 3 -T 30 -nv -O $RPM1 $LE2_URL/$RPM1 - wget -t 3 -T 30 -nv -O $RPM2 $LE2_URL/$RPM2 - [ ! -f $RPM1 ] || [ ! -f $RPM2 ] && { echo "Could not retrieve Libevent2 RPM file(s). Aborting."; exit 1; } - rpm -ivh --force $RPM1 $RPM2 && /bin/rm -f $RPM1 $RPM2 + wget -t 3 -T 30 -nv -O "$RPM1" "$LE2_URL/$RPM1" + wget -t 3 -T 30 -nv -O "$RPM2" "$LE2_URL/$RPM2" + [ ! -f "$RPM1" ] || [ ! -f "$RPM2" ] && { echo "Could not retrieve Libevent2 RPM file(s). Aborting."; exit 1; } + rpm -ivh --force "$RPM1" "$RPM2" && /bin/rm -f "$RPM1" "$RPM2" elif grep -qs "release 7" /etc/redhat-release; then yum -y install libevent-devel fi # Compile and install Libreswan (https://libreswan.org/) -SWAN_URL=https://download.libreswan.org/libreswan-${SWAN_VER}.tar.gz +SWAN_FILE="libreswan-${SWAN_VER}.tar.gz" +SWAN_URL="https://download.libreswan.org/${SWAN_FILE}" +wget -t 3 -T 30 -nv -O "$SWAN_FILE" "$SWAN_URL" +[ ! -f "$SWAN_FILE" ] && { echo "Could not retrieve Libreswan source file. Aborting."; exit 1; } /bin/rm -rf "/opt/src/libreswan-${SWAN_VER}" -wget -t 3 -T 30 -qO- $SWAN_URL | tar xvz -[ ! -d libreswan-${SWAN_VER} ] && { echo "Could not retrieve Libreswan source files. Aborting."; exit 1; } -cd libreswan-${SWAN_VER} +tar xvzf "$SWAN_FILE" && rm -f "$SWAN_FILE" +cd "libreswan-${SWAN_VER}" || { echo "Failed to enter Libreswan source directory. Aborting."; exit 1; } make programs && make install -ipsec --version 2>/dev/null | grep -qs "Libreswan ${SWAN_VER}" +ipsec --version 2>/dev/null | grep -qs "${SWAN_VER}" if [ "$?" != "0" ]; then echo echo "Sorry, something went wrong."