|
|
@@ -0,0 +1,447 @@ |
|
|
#!/bin/bash |
|
|
|
|
|
set -e |
|
|
set -u |
|
|
set -o pipefail |
|
|
|
|
|
# Return netmask for a given network and CIDR. |
|
|
cidr_to_netmask() { |
|
|
value=$(( 0xffffffff ^ ((1 << (32 - $1)) - 1) )) |
|
|
echo "$(( (value >> 24) & 0xff )).$(( (value >> 16) & 0xff )).$(( (value >> 8) & 0xff )).$(( value & 0xff ))" |
|
|
} |
|
|
|
|
|
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin |
|
|
|
|
|
readonly EC2_METADATA_URL='http://169.254.169.254/latest/meta-data' |
|
|
readonly UBUNTU_RELEASE=$(lsb_release -sc) |
|
|
|
|
|
# Make sure files are 644 and directories are 755. |
|
|
umask 022 |
|
|
|
|
|
export DEBIAN_FRONTEND=noninteractive |
|
|
export DEBCONF_NONINTERACTIVE_SEEN=true |
|
|
|
|
|
curl -s -k \ |
|
|
https://swupdate.openvpn.net/repos/repo-public.gpg | \ |
|
|
apt-key add - |
|
|
|
|
|
cat <<EOF > /etc/apt/sources.list.d/openvpn.list |
|
|
deb http://swupdate.openvpn.net/apt $UBUNTU_RELEASE main |
|
|
EOF |
|
|
|
|
|
apt-get -qq update |
|
|
|
|
|
PACKAGES=(easy-rsa openvpn iptables-persistent zip) |
|
|
for package in "${PACKAGES[@]}"; do |
|
|
apt-get -qq install --assume-yes $package >/dev/null |
|
|
done |
|
|
|
|
|
service openvpn stop || true |
|
|
|
|
|
# Stop with extreme prejudice. |
|
|
pgrep -f openvpn &>/dev/null && pkill -9 -f openvpn |
|
|
|
|
|
rm -Rf \ |
|
|
/etc/openvpn/{easy-rsa,keys} \ |
|
|
/etc/openvpn/{tcp,udp}-server.conf |
|
|
|
|
|
if which make-cadir &>/dev/null; then |
|
|
# This will create symbolic links. |
|
|
make-cadir /etc/openvpn/easy-rsa |
|
|
else |
|
|
cp -R /usr/share/easy-rsa \ |
|
|
/etc/openvpn |
|
|
fi |
|
|
|
|
|
EASY_RSA_VARS=( |
|
|
'CA_EXPIRE 365' |
|
|
'KEY_CITY London' |
|
|
'KEY_COUNTRY UK' |
|
|
'KEY_EMAIL [email protected]' |
|
|
'KEY_EXPIRE 30' |
|
|
'KEY_NAME OpenVPN Server' |
|
|
'KEY_ORG Example Co.' |
|
|
'KEY_OU Operations' |
|
|
'KEY_PROVINCE Greater London' |
|
|
'KEY_SIZE 2048' |
|
|
) |
|
|
|
|
|
for value in "${EASY_RSA_VARS[@]}"; do |
|
|
SETTING=( $value ) |
|
|
VALUE=$(echo $value | \ |
|
|
awk '{ for (i = 2; i <= NF; i++) printf $i " "}' | \ |
|
|
sed -e 's/^\s\+//;s/\s\+$//') |
|
|
|
|
|
sed -i -e \ |
|
|
"s/^#\?.*${SETTING[0]}.*/export ${SETTING[0]}=\"${VALUE}\"/" \ |
|
|
/etc/openvpn/easy-rsa/vars |
|
|
|
|
|
grep -qF "${SETTING[0]}" /etc/openvpn/easy-rsa/vars || \ |
|
|
echo "export ${SETTING[0]}=\"${VALUE}\"" | \ |
|
|
tee -a /etc/openvpn/easy-rsa/vars 1>/dev/null |
|
|
done |
|
|
|
|
|
pushd /etc/openvpn &>/dev/null |
|
|
pushd ${PWD}/easy-rsa &>/dev/null |
|
|
|
|
|
source ./vars |
|
|
|
|
|
./clean-all |
|
|
./build-ca --batch |
|
|
./build-key-server --batch server |
|
|
./build-key --batch client |
|
|
|
|
|
DH_FILE="./keys/dh2048.pem" |
|
|
if [[ ! -f $DH_FILE ]]; then |
|
|
# Fetch the Diffie-Hellman Parameter set from |
|
|
# the company that offers continuusly fresh |
|
|
# copy as a public service. |
|
|
curl -k -s https://2ton.com.au/dhparam/2048 | \ |
|
|
tee -a $DH_FILE 1>/dev/null |
|
|
|
|
|
# Check if the file contains a certificate, |
|
|
# otherwise generate a new one, which might |
|
|
# take long time to finish. |
|
|
if ! grep -qF 'BEGIN DH PARAMETERS' $DH_FILE; then |
|
|
./build-dh |
|
|
fi |
|
|
fi |
|
|
|
|
|
# Generate a pre-shared static key which is |
|
|
# going to be used alongside the client and |
|
|
# server certificates to sign the requests |
|
|
# with a HMAC signature. |
|
|
openvpn --genkey --secret ./keys/ta.key |
|
|
|
|
|
popd &>/dev/null |
|
|
|
|
|
mv -f ./easy-rsa/keys . |
|
|
|
|
|
chmod 700 ./keys |
|
|
|
|
|
tar -zcf \ |
|
|
/root/easy-rsa.tar.gz \ |
|
|
./easy-rsa |
|
|
|
|
|
sha256sum -b /root/easy-rsa.tar.gz | \ |
|
|
tee /root/easy-rsa.tar.gz.SHA256SUM 1>/dev/null |
|
|
|
|
|
# Correct permission... |
|
|
chmod 600 \ |
|
|
/root/easy-rsa.tar.gz \ |
|
|
/root/easy-rsa.tar.gz.SHA256SUM |
|
|
|
|
|
rm -Rf ./easy-rsa |
|
|
|
|
|
popd &>/dev/null |
|
|
|
|
|
for directory in /run/openvpn{,/tmp} /var/log/openvpn; do |
|
|
if [[ -d $directory ]]; then |
|
|
rm -Rf ${directory}/* |
|
|
else |
|
|
mkdir -p $directory |
|
|
fi |
|
|
|
|
|
chmod 755 $directory |
|
|
chown root:nogroup $directory |
|
|
done |
|
|
|
|
|
# Fetch the EC2 instance ID. |
|
|
INSTANCE_ID=$(curl -s ${EC2_METADATA_URL}/instance-id) |
|
|
|
|
|
# Extract the region name. |
|
|
REGION=$(curl -s ${EC2_METADATA_URL}/placement/availability-zone | sed -e 's/\w$//') |
|
|
|
|
|
# Fetch current "StackName" tag. |
|
|
INSTANCE_NAME_TAG=$(aws ec2 describe-tags \ |
|
|
--query 'Tags[*].Value' \ |
|
|
--filters "Name=resource-id,Values=${INSTANCE_ID}" 'Name=key,Values=StackName' \ |
|
|
--region $REGION --output text 2>/dev/null) |
|
|
|
|
|
# Fetch current private IP address of this instance. |
|
|
PRIVATE_IP_ADDRESS=$(curl -s ${EC2_METADATA_URL}/local-ipv4) |
|
|
|
|
|
# Fetch current public IP address. |
|
|
PUBLIC_IP_ADDRESS=$(aws ec2 describe-addresses \ |
|
|
--query 'Addresses[].PublicIp[]' \ |
|
|
--filters "Name=instance-id,Values=${INSTANCE_ID}" \ |
|
|
--region $REGION --output text 2>/dev/null) |
|
|
|
|
|
# Fetech current CIDR block for this VPC. |
|
|
VPC_CIDR=$(aws ec2 describe-vpcs \ |
|
|
--query 'Vpcs[].CidrBlock[]' \ |
|
|
--filters "Name=tag-key,Values=StackName" "Name=tag-value,Values=${INSTANCE_NAME_TAG}" \ |
|
|
--region $REGION --output text 2>/dev/null) |
|
|
|
|
|
# Extract network and netmaks. |
|
|
VPC_NETMASK=(${VPC_CIDR%%\/*} $(cidr_to_netmask ${VPC_CIDR##*\/})) |
|
|
|
|
|
for mode in TCP UDP; do |
|
|
NAME="$(echo $mode | tr 'A-Z' 'a-z')-server" |
|
|
|
|
|
# Render configuration for both the TCP and UDP servers. |
|
|
cat <<EOF > /etc/openvpn/${NAME}.conf |
|
|
$(if [[ $mode == "TCP" ]]; then |
|
|
cat <<'EOS' |
|
|
proto tcp-server |
|
|
tcp-nodelay |
|
|
EOS |
|
|
else |
|
|
cat <<'EOS' |
|
|
proto udp |
|
|
fast-io |
|
|
EOS |
|
|
fi) |
|
|
push "block-ipv6" |
|
|
|
|
|
local $PRIVATE_IP_ADDRESS |
|
|
$(if [[ $mode == "TCP" ]]; then |
|
|
cat <<'EOS' |
|
|
port 443 |
|
|
EOS |
|
|
else |
|
|
cat <<'EOS' |
|
|
port 1194 |
|
|
EOS |
|
|
fi) |
|
|
|
|
|
$(if [[ $mode == "TCP" ]]; then |
|
|
cat <<'EOS' |
|
|
dev tun0s0 |
|
|
EOS |
|
|
else |
|
|
cat <<'EOS' |
|
|
dev tun0s1 |
|
|
EOS |
|
|
fi) |
|
|
dev-type tun |
|
|
|
|
|
user nobody |
|
|
group nogroup |
|
|
chroot "/run/openvpn" |
|
|
tmp-dir "/tmp" |
|
|
|
|
|
topology subnet |
|
|
push "topology subnet" |
|
|
|
|
|
$(if [[ $mode == "TCP" ]]; then |
|
|
cat <<'EOS' |
|
|
ifconfig 172.31.0.1 255.255.248.0 |
|
|
ifconfig-pool 172.31.0.2 172.31.0.254 255.255.248.0 |
|
|
|
|
|
push "route $(printf '%s %s' "${VPC_NETMASK[@]}")" |
|
|
push "route-gateway 172.31.0.1" |
|
|
EOS |
|
|
else |
|
|
cat <<'EOS' |
|
|
ifconfig 172.31.8.1 255.255.248.0 |
|
|
ifconfig-pool 172.31.8.2 172.31.8.254 255.255.248.0 |
|
|
|
|
|
push "route $(printf '%s %s' "${VPC_NETMASK[@]}")" |
|
|
push "route-gateway 172.31.8.1" |
|
|
EOS |
|
|
fi) |
|
|
|
|
|
push "redirect-gateway def1" |
|
|
push "redirect-gateway bypass-dhcp" |
|
|
push "redirect-gateway autolocal" |
|
|
|
|
|
$(grep -E '^nameserver' /etc/resolv.conf | awk '{ print $2 }' | \ |
|
|
while read line; do |
|
|
echo "push \"dhcp-option DNS $line\"" |
|
|
done) |
|
|
$(grep -qP '8.8.[\d\.]+' /etc/resolv.conf || echo 'push "dhcp-option DNS 8.8.8.8"') |
|
|
$(grep -qP '4.2.[\d\.]+' /etc/resolv.conf || echo 'push "dhcp-option DNS 4.2.2.2"') |
|
|
|
|
|
push "dhcp-option DOMAIN $(grep -E '^search' /etc/resolv.conf | grep -oE '[^.]*\.[^.]*$' )" |
|
|
push "dhcp-option DOMAIN-SEARCH $(grep -E '^search' /etc/resolv.conf | awk '{ print $2 }')" |
|
|
|
|
|
ca /etc/openvpn/keys/ca.crt |
|
|
cert /etc/openvpn/keys/server.crt |
|
|
key /etc/openvpn/keys/server.key |
|
|
dh /etc/openvpn/keys/dh2048.pem |
|
|
|
|
|
tls-version-min 1.2 or-highest |
|
|
tls-cipher TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 |
|
|
|
|
|
cipher AES-256-CBC |
|
|
auth SHA512 |
|
|
|
|
|
mode server |
|
|
tls-server |
|
|
tls-auth /etc/openvpn/keys/ta.key 0 |
|
|
|
|
|
duplicate-cn |
|
|
x509-track "CN" |
|
|
remote-cert-tls client |
|
|
reneg-sec 14400 |
|
|
|
|
|
comp-lzo yes |
|
|
push "comp-lzo yes" |
|
|
|
|
|
persist-key |
|
|
persist-tun |
|
|
push "persist-key" |
|
|
push "persist-tun" |
|
|
|
|
|
keepalive 10 120 |
|
|
push "explicit-exit-notify 3" |
|
|
|
|
|
push "route-delay 5 30" |
|
|
push "dhcp-pre-release" |
|
|
push "dhcp-renew" |
|
|
push "dhcp-release" |
|
|
push "route-metric 101" |
|
|
|
|
|
status /var/log/openvpn/${NAME}-status.log 30 |
|
|
status-version 3 |
|
|
|
|
|
log-append /var/log/openvpn/${NAME}.log |
|
|
verb 3 |
|
|
|
|
|
opt-verify |
|
|
mute-replay-warnings |
|
|
|
|
|
fragment 0 |
|
|
|
|
|
tun-mtu 1500 |
|
|
tun-mtu-extra 32 |
|
|
mssfix 1450 |
|
|
|
|
|
hash-size 4096 4096 |
|
|
max-clients 256 |
|
|
|
|
|
sndbuf 131072 |
|
|
rcvbuf 131072 |
|
|
|
|
|
txqueuelen 256 |
|
|
EOF |
|
|
|
|
|
# Correct permission... |
|
|
chmod 600 /etc/openvpn/${NAME}.conf |
|
|
done |
|
|
|
|
|
# Render self-contained client configuration file. |
|
|
cat <<EOF > /root/client.ovpn |
|
|
setenv FORWARD_COMPATIBLE 1 |
|
|
setenv PUSH_PEER_INFO |
|
|
|
|
|
client |
|
|
nobind |
|
|
|
|
|
dev tun |
|
|
dev-type tun |
|
|
|
|
|
$(for server in '443 tcp' '1194 udp'; do |
|
|
echo "remote $PUBLIC_IP_ADDRESS $server" |
|
|
done) |
|
|
|
|
|
push-peer-info |
|
|
server-poll-timeout 5 |
|
|
|
|
|
fragment 0 |
|
|
|
|
|
tun-mtu 1500 |
|
|
tun-mtu-extra 32 |
|
|
mssfix 1450 |
|
|
|
|
|
persist-key |
|
|
persist-tun |
|
|
|
|
|
resolv-retry infinite |
|
|
|
|
|
tls-version-min 1.2 or-higest |
|
|
tls-cipher TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 |
|
|
cipher AES-256-CBC |
|
|
|
|
|
auth SHA512 |
|
|
auth-retry none |
|
|
|
|
|
remote-cert-tls server |
|
|
|
|
|
reneg-sec 14400 |
|
|
|
|
|
sndbuf 131072 |
|
|
rcvbuf 131072 |
|
|
|
|
|
comp-lzo adaptive |
|
|
verb 3 |
|
|
|
|
|
<ca> |
|
|
$(cat /etc/openvpn/keys/ca.crt) |
|
|
</ca> |
|
|
|
|
|
<cert> |
|
|
$(sed -n -e '/BEGIN/,/END/p' /etc/openvpn/keys/client.crt) |
|
|
</cert> |
|
|
|
|
|
<key> |
|
|
$(cat /etc/openvpn/keys/client.key) |
|
|
</key> |
|
|
|
|
|
key-direction 1 |
|
|
<tls-auth> |
|
|
$(sed -n -e '/BEGIN/,/END/p' /etc/openvpn/keys/ta.key) |
|
|
</tls-auth> |
|
|
EOF |
|
|
|
|
|
# Correct permission... |
|
|
chmod 600 /root/client.ovpn |
|
|
|
|
|
pushd /root &>/dev/null |
|
|
|
|
|
rm -f \ |
|
|
client.zip \ |
|
|
client.zip.SHA256SUM |
|
|
|
|
|
zip --move client.zip client.ovpn |
|
|
|
|
|
sha256sum -b client.zip | \ |
|
|
tee client.zip.SHA256SUM 1>/dev/null |
|
|
|
|
|
# Correct permission... |
|
|
chmod 600 \ |
|
|
client.zip \ |
|
|
client.zip.SHA256SUM |
|
|
|
|
|
popd &>/dev/null |
|
|
|
|
|
# Enable IP packets forwarding... |
|
|
echo 1 > /proc/sys/net/ipv4/ip_forward |
|
|
|
|
|
cat <<'EOF' > /etc/sysctl.d/99-network-forward.conf |
|
|
net.ipv4.ip_forward = 1 |
|
|
EOF |
|
|
|
|
|
# Reset firewall rules... |
|
|
iptables -F |
|
|
iptables -X |
|
|
iptables -t nat -F |
|
|
iptables -t nat -X |
|
|
iptables -t mangle -F |
|
|
iptables -t mangle -X |
|
|
iptables -P INPUT ACCEPT |
|
|
iptables -P FORWARD ACCEPT |
|
|
iptables -P OUTPUT ACCEPT |
|
|
|
|
|
# Configure source NAT, forwarding, etc. |
|
|
iptables -I INPUT -i tun0s+ -j ACCEPT |
|
|
|
|
|
iptables -I FORWARD -i tun0s+ -o eth0 -m conntrack --ctstate NEW -j ACCEPT |
|
|
iptables -I FORWARD -i eth0 -o tun0s+ -m conntrack --ctstate NEW -j ACCEPT |
|
|
iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT |
|
|
|
|
|
for network in 172.31.0.0/21 172.31.8.0/21; do |
|
|
iptables -t nat -I POSTROUTING -s $network -j SNAT --to $PRIVATE_IP_ADDRESS |
|
|
done |
|
|
|
|
|
iptables -I OUTPUT -o tun0s+ -j ACCEPT |
|
|
|
|
|
# Save current rules. |
|
|
iptables-save > /etc/iptables/rules.v4 |
|
|
|
|
|
# Ensure that OpenVPN servers start automatically. |
|
|
update-rc.d -f openvpn enable |
|
|
|
|
|
# Start OpenVPN servers... |
|
|
service openvpn start |