Last active
January 4, 2016 08:19
-
-
Save GedowFather/8594220 to your computer and use it in GitHub Desktop.
BashScript for connecting VPN between VPC G/W and Debian Linux. operating HA by monit.
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
#!/bin/bash | |
# | |
# Setup VPN between Debian Linux and VPC G/W. | |
# How to use : ./this_script.sh Generic.txt | |
# | |
# For connecting IPsec VPN, you need to allow these connections. | |
# If VPN has global address, you change FORWARD to OUTPUT. | |
# | |
# ex) iptables -A FORWARD -p udp --dport 500 -j ACCEPT | |
# iptables -A FORWARD -p tcp --dport 500 -j ACCEPT | |
# iptables -A FORWARD -p esp -j ACCEPT | |
# | |
PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin | |
exitMessage() { | |
echo "$@" >&2 | |
exit 1 | |
} | |
[ `id -u` = 0 ] || exitMessage "Set user to root." | |
# | |
# Opetion | |
# | |
CONF=$1 | |
[ -z "$CONF" -o ! -r "$CONF" ] && exitMessage "Input VPC+VPN Generic config." | |
######### | |
# | |
# Config | |
# | |
HOSTNAME=`hostname` | |
INTERFACE="eth0" | |
CUSTOMER_SOURCE="172.30.4.0/22" | |
VPC_SUBNET="10.100.0.0/16" | |
QUAGGA_PASSWORD="QuaggaPassword" | |
CUSTOMER_SUBNET=`LANG=C ip addr show dev $INTERFACE \ | |
| grep -m1 "inet " | sed -e 's/^.*inet \([\.0-9\/]\+\) .*/\1/g'` | |
CUSTOMER_ADDR=`echo "$CUSTOMER_SUBNET" | cut -d/ -f1` | |
RACOON_LOG="/var/log/racoon/racoon.log" | |
BGPD_LOG="/var/log/quagga/bgpd.log" | |
DEPLOY_DIR="/usr/local/etc/aws-vpc/" | |
VPN1_DIR=$DEPLOY_DIR"vpn1/" | |
VPN2_DIR=$DEPLOY_DIR"vpn2/" | |
EMAIL="root@localhost" | |
######### | |
# | |
# Generic Config Values | |
# | |
CONNECTION_ID=`cat $CONF | grep "Your VPN Connection ID" | awk '{print $6}'` | |
T1_OUT_CUSTOMER_GW=`cat $CONF | grep -m1 "\- Customer Gateway" | tail -1 | awk '{print $5}'` | |
T1_OUT_VPC_GW=` cat $CONF | grep -m1 "\- Virtual Private Gateway" | tail -1 | awk '{print $6}'` | |
T1_IN_CUSTOMER_GW=` cat $CONF | grep -m2 "\- Customer Gateway" | tail -1 | awk '{print $5}'` | |
T1_IN_VPC_GW=` cat $CONF | grep -m2 "\- Virtual Private Gateway" | tail -1 | awk '{print $6}'` | |
T1_PSK=` cat $CONF | grep -m1 "\- Pre-Shared Key" | tail -1 | awk '{print $5}'` | |
T1_ASN=` cat $CONF | grep -m1 "Private *Gateway ASN" | tail -1 | awk '{print $7}'` | |
T1_NEIGHBOR_ADDR=` cat $CONF | grep -m1 "Neighbor IP Address" | tail -1 | awk '{print $6}'` | |
T2_OUT_CUSTOMER_GW=`cat $CONF | grep -m4 "\- Customer Gateway" | tail -1 | awk '{print $5}'` | |
T2_OUT_VPC_GW=` cat $CONF | grep -m3 "\- Virtual Private Gateway" | tail -1 | awk '{print $6}'` | |
T2_IN_CUSTOMER_GW=` cat $CONF | grep -m5 "\- Customer Gateway" | tail -1 | awk '{print $5}'` | |
T2_IN_VPC_GW=` cat $CONF | grep -m4 "\- Virtual Private Gateway" | tail -1 | awk '{print $6}'` | |
T2_PSK=` cat $CONF | grep -m2 "\- Pre-Shared Key" | tail -1 | awk '{print $5}'` | |
T2_ASN=` cat $CONF | grep -m2 "Private *Gateway ASN" | tail -1 | awk '{print $7}'` | |
T2_NEIGHBOR_ADDR=` cat $CONF | grep -m2 "Neighbor IP Address" | tail -1 | awk '{print $6}'` | |
VALUES="T1_OUT_CUSTOMER_GW T1_OUT_VPC_GW T1_IN_CUSTOMER_GW T1_IN_VPC_GW" | |
VALUES+=" T1_PSK T1_ASN T1_NEIGHBOR_ADDR" | |
VALUES+=" T2_OUT_CUSTOMER_GW T2_OUT_VPC_GW T2_IN_CUSTOMER_GW T2_IN_VPC_GW" | |
VALUES+=" T2_PSK T2_ASN T2_NEIGHBOR_ADDR" | |
for v in $VALUES | |
do | |
[ -z `eval 'echo $'$v` ] && exitMessage "Colud not found $v from $CONF." | |
done | |
T1_IN_VPC_ADDR=`echo "$T1_IN_VPC_GW" | cut -d/ -f1` | |
T2_IN_VPC_ADDR=`echo "$T2_IN_VPC_GW" | cut -d/ -f1` | |
######### | |
# | |
# Package | |
# | |
apt-get -y install racoon ipsec-tools quagga monit | |
######### | |
# | |
# sysctl | |
# | |
cat << EOT > /etc/sysctl.d/vpn.conf | |
net.ipv4.ip_forward = 1 | |
# prevent the panic of client, when switching vpn route. | |
net.ipv4.conf.all.send_redirects = 0 | |
net.ipv4.conf.default.send_redirects = 0 | |
net.ipv4.conf.eth0.send_redirects = 0 | |
net.ipv4.conf.lo.send_redirects = 0 | |
net.ipv4.conf.all.accept_redirects = 0 | |
net.ipv4.conf.default.accept_redirects = 0 | |
net.ipv4.conf.eth0.accept_redirects = 0 | |
net.ipv4.conf.lo.accept_redirects = 0 | |
EOT | |
service procps restart | |
######### | |
# | |
# Create Config File | |
# | |
mkdir -p $VPN1_DIR $VPN2_DIR | |
## Pre-Shared Key ## | |
cat << EOT > /etc/racoon/aws-vpc.txt | |
$T1_OUT_VPC_GW $T1_PSK | |
$T2_OUT_VPC_GW $T2_PSK | |
EOT | |
chmod 600 /etc/racoon/aws-vpc.txt | |
# | |
# Racoon | |
# | |
cat << EOT > $VPN1_DIR/racoon.conf | |
log notify; | |
path pre_shared_key "/etc/racoon/aws-vpc.txt"; | |
remote $T1_OUT_VPC_GW { | |
exchange_mode main; | |
lifetime time 28800 seconds; | |
proposal { | |
encryption_algorithm aes128; | |
hash_algorithm sha1; | |
authentication_method pre_shared_key; | |
dh_group 2; | |
} | |
} | |
sainfo address $T1_IN_CUSTOMER_GW any address $T1_IN_VPC_GW any { | |
pfs_group 2; | |
lifetime time 3600 seconds; | |
encryption_algorithm aes128; | |
authentication_algorithm hmac_sha1; | |
compression_algorithm deflate; | |
} | |
EOT | |
cat << EOT > $VPN2_DIR/racoon.conf | |
log notify; | |
path pre_shared_key "/etc/racoon/aws-vpc.txt"; | |
remote $T2_OUT_VPC_GW { | |
exchange_mode main; | |
lifetime time 28800 seconds; | |
proposal { | |
encryption_algorithm aes128; | |
hash_algorithm sha1; | |
authentication_method pre_shared_key; | |
dh_group 2; | |
} | |
} | |
sainfo address $T2_IN_CUSTOMER_GW any address $T2_IN_VPC_GW any { | |
pfs_group 2; | |
lifetime time 3600 seconds; | |
encryption_algorithm aes128; | |
authentication_algorithm hmac_sha1; | |
compression_algorithm deflate; | |
} | |
EOT | |
# | |
# Setkey | |
# | |
cat << EOT > /etc/ipsec-tools.d/10-vpc-tunnels.conf | |
#!/usr/sbin/setkey -f | |
flush; | |
spdflush; | |
# Tunnel1 | |
spdadd $T1_IN_CUSTOMER_GW $T1_IN_VPC_GW any -P out ipsec esp/tunnel/$CUSTOMER_ADDR-$T1_OUT_VPC_GW/require; | |
spdadd $T1_IN_VPC_GW $T1_IN_CUSTOMER_GW any -P in ipsec esp/tunnel/$T1_OUT_VPC_GW-$CUSTOMER_ADDR/require; | |
spdadd $T1_IN_CUSTOMER_GW $VPC_SUBNET any -P out ipsec esp/tunnel/$CUSTOMER_ADDR-$T1_OUT_VPC_GW/require; | |
spdadd $VPC_SUBNET $T1_IN_CUSTOMER_GW any -P in ipsec esp/tunnel/$T1_OUT_VPC_GW-$CUSTOMER_ADDR/require; | |
# Tunnel2 | |
spdadd $T2_IN_CUSTOMER_GW $T2_IN_VPC_GW any -P out ipsec esp/tunnel/$CUSTOMER_ADDR-$T2_OUT_VPC_GW/require; | |
spdadd $T2_IN_VPC_GW $T2_IN_CUSTOMER_GW any -P in ipsec esp/tunnel/$T2_OUT_VPC_GW-$CUSTOMER_ADDR/require; | |
spdadd $T2_IN_CUSTOMER_GW $VPC_SUBNET any -P out ipsec esp/tunnel/$CUSTOMER_ADDR-$T2_OUT_VPC_GW/require; | |
spdadd $VPC_SUBNET $T2_IN_CUSTOMER_GW any -P in ipsec esp/tunnel/$T2_OUT_VPC_GW-$CUSTOMER_ADDR/require; | |
EOT | |
cat << EOT > $VPN1_DIR/20-vpc-private.conf | |
#!/usr/sbin/setkey -f | |
# VPN1 Between Local and VPC | |
spdadd $CUSTOMER_SOURCE $VPC_SUBNET any -P out ipsec esp/tunnel/$CUSTOMER_ADDR-$T1_OUT_VPC_GW/require; | |
spdadd $VPC_SUBNET $CUSTOMER_SOURCE any -P in ipsec esp/tunnel/$T1_OUT_VPC_GW-$CUSTOMER_ADDR/require; | |
EOT | |
cat << EOT > $VPN2_DIR/20-vpc-private.conf | |
#!/usr/sbin/setkey -f | |
# VPN2 Between Local and VPC | |
spdadd $CUSTOMER_SOURCE $VPC_SUBNET any -P out ipsec esp/tunnel/$CUSTOMER_ADDR-$T2_OUT_VPC_GW/require; | |
spdadd $VPC_SUBNET $CUSTOMER_SOURCE any -P in ipsec esp/tunnel/$T2_OUT_VPC_GW-$CUSTOMER_ADDR/require; | |
EOT | |
# | |
# bgpd | |
# | |
cat << EOT > $VPN1_DIR/bgpd.conf | |
hostname $HOSTNAME | |
password $QUAGGA_PASSWORD | |
enable password $QUAGGA_PASSWORD | |
! | |
log file $BGPD_LOG | |
!debug bgp events | |
!debug bgp zebra | |
debug bgp updates | |
! | |
router bgp 65000 | |
bgp router-id $CUSTOMER_ADDR | |
network $T1_IN_CUSTOMER_GW | |
! Routing for VPC to CUSTOMER (see Route Tables on VPC Console) | |
! if CustomerVPN forward using NAT, this is unnecessary. | |
network $CUSTOMER_SUBNET | |
! | |
! aws tunnel #1 neighbor | |
neighbor $T1_NEIGHBOR_ADDR remote-as $T1_ASN | |
! | |
line vty | |
EOT | |
cat << EOT > $VPN2_DIR/bgpd.conf | |
hostname $HOSTNAME | |
password $QUAGGA_PASSWORD | |
enable password $QUAGGA_PASSWORD | |
! | |
log file $BGPD_LOG | |
!debug bgp events | |
!debug bgp zebra | |
debug bgp updates | |
! | |
router bgp 65000 | |
bgp router-id $CUSTOMER_ADDR | |
network $T2_IN_CUSTOMER_GW | |
! Routing for VPC to CUSTOMER (see Route Tables on VPC Console) | |
! if CustomerVPN forward using NAT, this is unnecessary. | |
network $CUSTOMER_SUBNET | |
! | |
! aws tunnel #2 neighbor | |
neighbor $T2_NEIGHBOR_ADDR remote-as $T2_ASN | |
! | |
line vty | |
EOT | |
# | |
# zebra config | |
# | |
cat << EOT > /etc/quagga/zebra.conf | |
hostname $HOSTNAME | |
password $QUAGGA_PASSWORD | |
enable password $QUAGGA_PASSWORD | |
! | |
! list interfaces | |
interface $INTERFACE | |
interface lo | |
! | |
line vty | |
EOT | |
# | |
# Racoon log | |
# | |
sed -i "s|RACOON_ARGS.*$|RACOON_ARGS='-l $RACOON_LOG'|g" /etc/default/racoon | |
cat << EOT > /etc/logrotate.d/racoon | |
$RACOON_LOG { | |
rotate 10 | |
daily | |
compress | |
missingok | |
notifempty | |
copytruncate | |
} | |
EOT | |
# | |
# Monit | |
# | |
MONIT_HEALTHCHECK_SCRIPT="/usr/local/bin/aws-vpc-healthcheck.sh" | |
MONIT_SWITCH_SCRIPT="/usr/local/bin/aws-vpc-switch.sh" | |
cat << EOT > /etc/monit/conf.d/aws-vpc.cfg | |
set daemon 10 with start delay 5 | |
set mailserver localhost | |
set alert $EMAIL not on {INSTANCE} | |
check program aws-vpc | |
with path $MONIT_HEALTHCHECK_SCRIPT | |
if status != 0 for 10 cycles then exec "$MONIT_SWITCH_SCRIPT" | |
every 3 cycles | |
check process racoon with pidfile /var/run/racoon.pid | |
start program = "/etc/init.d/racoon start" | |
stop program = "/etc/init.d/racoon stop" | |
check process quagga with pidfile /var/run/quagga/zebra.pid | |
start program = "/etc/init.d/quagga start" | |
stop program = "/etc/init.d/quagga stop" | |
EOT | |
cat << EOT > $MONIT_HEALTHCHECK_SCRIPT | |
#!/bin/bash | |
# | |
# AWS VPC VPN healthcheck script. | |
# | |
# Error is that local can't ping to current vpc tunnel. | |
# | |
# Config | |
T1_OUT_VPC_GW=$T1_OUT_VPC_GW | |
T2_OUT_VPC_GW=$T2_OUT_VPC_GW | |
T1_IN_VPC_ADDR=$T1_IN_VPC_ADDR | |
T2_IN_VPC_ADDR=$T2_IN_VPC_ADDR | |
# Check setkey | |
OUT_VPN_NUMBER=0 | |
SETKEY_ROUTE=\`/usr/sbin/setkey -D -P | grep -m1 -A5 "$CUSTOMER_SOURCE" | grep -m1 "esp/tunnel"\` | |
echo "\$SETKEY_ROUTE" | grep \$T1_OUT_VPC_GW > /dev/null 2>&1 | |
[ \$? -eq 0 ] && OUT_VPN_NUMBER=1 | |
echo "\$SETKEY_ROUTE" | grep \$T2_OUT_VPC_GW > /dev/null 2>&1 | |
[ \$? -eq 0 ] && OUT_VPN_NUMBER=2 | |
[ \$OUT_VPN_NUMBER -eq 0 ] && echo -n "Not set private route yet." >& 2 && exit 1 | |
# Check ping | |
IN_VPC_ADDR=\`eval echo '\$T'\$OUT_VPN_NUMBER'_IN_VPC_ADDR'\` | |
ping -c 1 -w 1 \$IN_VPC_ADDR > /dev/null 2>&1 | |
[ \$? -eq 0 ] && exit 0 | |
# error | |
echo -n "VPN \$OUT_VPN_NUMBER tunnel is disconnected." >& 2 | |
exit 1 | |
EOT | |
chmod +x $MONIT_HEALTHCHECK_SCRIPT | |
cat << EOT > $MONIT_SWITCH_SCRIPT | |
#!/bin/bash | |
# | |
# Config | |
IPSEC_PRIVATE_CONF="/etc/ipsec-tools.d/20-vpc-private.conf" | |
VPN1_DIR="$VPN1_DIR" | |
VPN2_DIR="$VPN2_DIR" | |
CONF1=\$VPN1_DIR"20-vpc-private.conf" | |
CONF2=\$VPN2_DIR"20-vpc-private.conf" | |
# Check current conf | |
VPN_NUMBER=1 | |
if [ -r "\$IPSEC_PRIVATE_CONF" ];then | |
diff \$IPSEC_PRIVATE_CONF \$CONF1 > /dev/null 2>&1 | |
[ \$? -eq 0 ] && VPN_NUMBER=2 | |
fi | |
# Overwrite | |
CONF_DIR=\`eval echo '\$VPN'\$VPN_NUMBER'_DIR'\` | |
cp \$CONF_DIR'racoon.conf' /etc/racoon/ | |
cp \$CONF_DIR'20-vpc-private.conf' /etc/ipsec-tools.d/ | |
cp \$CONF_DIR'bgpd.conf' /etc/quagga/ | |
# Restart Services | |
service setkey restart | |
service racoon restart | |
service quagga restart | |
service monit restart | |
exit 0 | |
EOT | |
chmod +x $MONIT_SWITCH_SCRIPT | |
# | |
# Enable zebra and bgpd | |
# | |
sed -i 's/zebra=no/zebra=yes/' /etc/quagga/daemons | |
sed -i 's/bgpd=no/bgpd=yes/' /etc/quagga/daemons | |
# | |
# Create Static Tunnel Addr | |
# | |
ip addr add $T1_IN_CUSTOMER_GW dev $INTERFACE | |
ip addr add $T2_IN_CUSTOMER_GW dev $INTERFACE | |
# | |
# Restart Services | |
# | |
$MONIT_SWITCH_SCRIPT | |
service setkey restart | |
service racoon restart | |
service quagga restart | |
service monit restart |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment