Skip to content

Instantly share code, notes, and snippets.

@nhibberd
Last active January 8, 2020 00:02
Show Gist options
  • Save nhibberd/b53df2f952e534115b658ded11c413f9 to your computer and use it in GitHub Desktop.
Save nhibberd/b53df2f952e534115b658ded11c413f9 to your computer and use it in GitHub Desktop.
Wireguard update script
#!/bin/sh -eu
TEMPLATE_DIR=${TEMPLATE_DIR:-/tmp}
: ${ROOT:=/etc/config}
: ${ENV:=$(cat /etc/config/env)}
: ${REGION:=$(cat /etc/config/region)}
: ${SUBNET:=$(cat /etc/config/subnet)}
: ${PREFIX:?"s3 location"}
if [ -z "${ENV}" ]; then
echo "ENV is not defined"
exit 1
elif [ -z "${REGION}" ]; then
echo "REGION is not defined"
exit 1
elif [ -z "${SUBNET}" ]; then
echo "SUBNET is not defined"
exit 1
fi
if [ ! "$(whoami)" == "root" ]; then
echo "Run as root"
exit 1
fi
## Pull private key secret
PRIVATE_KEY=$(aws secretsmanager get-secret-value --secret-id "${ENV}/vpn-private-key" --region ${REGION} | jq .SecretString -r)
PUBLIC_KEY=$(echo $PRIVATE_KEY | wg pubkey)
SERVER_ADDRESS=$(${ROOT}/wg-ip --subnet ${SUBNET} gen ${PUBLIC_KEY})
mkdir -p /etc/wireguard
# Forcibly rewrite MSS to 1360 to prevent TCP fragmentation. Based on
# https://www.zeitgeist.se/2013/11/26/mtu-woes-in-ipsec-tunnels-how-to-fix/
# TODO: This can probably be 1380, as wg headers are 20b smaller than IPsec
# Find latest payload
PAYLOAD=$(aws s3 ls "${PREFIX}/" --recursive | awk -F'/' '{ print $3 }' | sort -nr | head -n 1)
RAW_PAYLOAD=$(aws s3 cp ${PREFIX}/${PAYLOAD} -)
KEYS=$(echo ${RAW_PAYLOAD} | jq -r '.employees | map (.vpn."'${ENV}'") | map (select(. != null)) | map(join("\n")) | join ("\n")')
CURRENT=$(mktemp)
CONFIG=$(mktemp)
CREATE=$(mktemp)
cleanup () {
rm -f ${CURRENT}
rm -f ${CONFIG}
rm -f ${CREATE}
}
trap cleanup EXIT 1
ADDING=""
REMOVING=""
if [ ! -f /etc/wireguard/wg0.conf ]; then
echo "No existing config, loading - ${PAYLOAD}"
cat > ${CREATE} << _CONFIG
[Interface]
Address = ${SERVER_ADDRESS}
ListenPort = 51820
PostUp = /usr/sbin/iptables -A FORWARD -i wg0 -j ACCEPT; /usr/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; /usr/sbin/iptables -t mangle -A FORWARD -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
PostDown = /usr/sbin/iptables -D FORWARD -i wg0 -j ACCEPT; /usr/sbin/iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; /usr/sbin/iptables -t mangle -D FORWARD -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
PrivateKey = ${PRIVATE_KEY}
SaveConfig = true
_CONFIG
for KEY in ${KEYS}; do
ADDR=$(${ROOT}/wg-ip --subnet "${SUBNET}" gen "${KEY}")
echo "[Peer]
PublicKey = ${KEY}
AllowedIps = ${ADDR}
" >> ${CREATE}
done
cp ${CREATE} /etc/wireguard/wg0.conf
${ROOT}/wg-quick up wg0
wg show
else
echo "Checking VPN config - ${PAYLOAD}"
wg show wg0 peers | sort > ${CURRENT}
echo $KEYS | tr -d '\n' | xargs -d ' ' -L 1 echo | sort > ${CONFIG}
for NEW in $(comm -13 ${CURRENT} ${CONFIG}); do
echo "Adding peer: $NEW"
ADDING+="${NEW}\n"
ADDR=$(${ROOT}/wg-ip --subnet "${SUBNET}" gen "${NEW}")
echo "[Peer]
PublicKey = ${NEW}
AllowedIps = ${ADDR}
" > ${CREATE}
wg addconf wg0 ${CREATE}
/usr/sbin/ip route add ${ADDR} dev wg0
done
for REMOVE in $(comm -23 ${CURRENT} ${CONFIG}); do
echo "Removing peer: $REMOVE"
REMOVING+="${REMOVE}\n"
ADDR=$(${ROOT}/wg-ip --subnet "${SUBNET}" gen "${REMOVE}")
wg set wg0 peer ${REMOVE} remove
/usr/sbin/ip route del ${ADDR}
done
fi
### Slack notifications
RAW_SLACK_VALUE=$(aws secretsmanager get-secret-value --secret-id "${ENV}/vpn-slack" --region ${REGION} || echo "")
if [ ! "${RAW_SLACK_VALUE}" == "" ]; then
SLACK_URL=$(echo $RAW_SLACK_VALUE | jq .SecretString -r)
PAYLOAD=""
if [ ! "${ADDING}" == "" ]; then
NAME=$(echo $RAW_PAYLOAD | jq -r '.employees | map(select(.vpn."'${ENV}'") | select(.vpn."'${ENV}'"[] | contains("'${ADDING}'"))) | map (.name) | join("")')
PAYLOAD+="{
\"title\": \"Adding peers\",
\"value\": \"${ADDING} - $NAME\"
}"
fi
if [ ! "${REMOVING}" == "" ]; then
if [ ! "${PAYLOAD}" == "" ]; then
PAYLOAD+=",
"
fi
PAYLOAD+="{
\"title\": \"Removing peers\",
\"value\": \"${REMOVING}\"
}"
fi
if [ ! "${PAYLOAD}" == "" ]; then
echo "Sending slack notification"
curl -X POST -H "Content-type: application/json" $SLACK_URL --silent -d "{
\"icon_emoji\": \":shield:\",
\"attachments\": [
{
\"text\": \"VPN Config updates for \`${ENV}\` environment.\",
\"color\": \"good\",
\"fields\": [
${PAYLOAD}
]
}
]
}"
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment