Skip to content

Instantly share code, notes, and snippets.

@rudymccomb
Forked from kwilczynski/vpn.sh
Created June 9, 2017 23:27
Show Gist options
  • Select an option

  • Save rudymccomb/81f59c12125f10a3b5720aba452a7826 to your computer and use it in GitHub Desktop.

Select an option

Save rudymccomb/81f59c12125f10a3b5720aba452a7826 to your computer and use it in GitHub Desktop.

Revisions

  1. @kwilczynski kwilczynski revised this gist Jun 23, 2016. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions vpn.sh
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,6 @@ service openvpn stop || true
    # Stop with extreme prejudice.
    pgrep -f openvpn &>/dev/null && pkill -9 -f openvpn


    # Add missing log rotation.
    cat <<'EOF' > /etc/logrotate.d/openvpn
    /var/log/openvpn.log
    @@ -261,15 +260,15 @@ topology subnet
    push "topology subnet"
    $(if [[ $mode == "TCP" ]]; then
    cat <<'EOS'
    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'
    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
  2. @kwilczynski kwilczynski revised this gist Jun 9, 2016. 1 changed file with 26 additions and 10 deletions.
    36 changes: 26 additions & 10 deletions vpn.sh
    Original file line number Diff line number Diff line change
    @@ -55,6 +55,22 @@ service openvpn stop || true
    # Stop with extreme prejudice.
    pgrep -f openvpn &>/dev/null && pkill -9 -f openvpn


    # Add missing log rotation.
    cat <<'EOF' > /etc/logrotate.d/openvpn
    /var/log/openvpn.log
    /var/log/openvpn/*.log
    {
    daily
    rotate 7
    copytruncate
    notifempty
    missingok
    compress
    sharedscripts
    }
    EOF

    rm -Rf \
    /etc/openvpn/{easy-rsa,keys} \
    /etc/openvpn/{tcp,udp}-server.conf
    @@ -68,16 +84,16 @@ else
    fi

    EASY_RSA_VARS=(
    'CA_EXPIRE 365'
    'KEY_CITY Tokyo'
    'KEY_COUNTRY JP'
    'KEY_EMAIL security@kkversper.jp'
    'KEY_EXPIRE 30'
    'KEY_NAME OpenVPN Server'
    'KEY_ORG Vesper Co., Ltd.'
    'KEY_OU Operations'
    'KEY_PROVINCE Tokyo-to'
    'KEY_SIZE 2048'
    'CA_EXPIRE 365'
    'KEY_CITY London'
    'KEY_COUNTRY UK'
    'KEY_EMAIL security@example.com'
    '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
  3. @kwilczynski kwilczynski revised this gist Jun 9, 2016. 1 changed file with 33 additions and 14 deletions.
    47 changes: 33 additions & 14 deletions vpn.sh
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,9 @@ cidr_to_netmask() {

    export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

    # The name of the EC2 tag that holds the Elastic IP address to use.
    readonly TAG_NAME='PublicIP'

    readonly EC2_METADATA_URL='http://169.254.169.254/latest/meta-data'
    readonly UBUNTU_RELEASE=$(lsb_release -sc)

    @@ -29,7 +32,18 @@ cat <<EOF > /etc/apt/sources.list.d/openvpn.list
    deb http://swupdate.openvpn.net/apt $UBUNTU_RELEASE main
    EOF

    apt-get -qq update

    # Refresh packages index only when needed.
    UPDATE_STAMP='/var/lib/apt/periodic/update-success-stamp'
    if [[ ! -f $UPDATE_STAMP ]] || \
    (( $(date +%s) - $(date -r $UPDATE_STAMP +%s) > 300 )); then
    apt-get -qq update
    fi

    # Only refresh packages index from OpenVPN's repository.
    apt-get -qq update \
    -o Dir::Etc::SourceList='/etc/apt/sources.list.d/openvpn.list' \
    -o Dir::Etc::SourceParts='-' -o APT::Get::List-Cleanup='0'

    PACKAGES=(easy-rsa openvpn iptables-persistent zip)
    for package in "${PACKAGES[@]}"; do
    @@ -55,14 +69,14 @@ fi

    EASY_RSA_VARS=(
    'CA_EXPIRE 365'
    'KEY_CITY London'
    'KEY_COUNTRY UK'
    'KEY_EMAIL security@example.com'
    'KEY_CITY Tokyo'
    'KEY_COUNTRY JP'
    'KEY_EMAIL security@kkversper.jp'
    'KEY_EXPIRE 30'
    'KEY_NAME OpenVPN Server'
    'KEY_ORG Example Co.'
    'KEY_ORG Vesper Co., Ltd.'
    'KEY_OU Operations'
    'KEY_PROVINCE Greater London'
    'KEY_PROVINCE Tokyo-to'
    'KEY_SIZE 2048'
    )

    @@ -76,6 +90,7 @@ for value in "${EASY_RSA_VARS[@]}"; do
    "s/^#\?.*${SETTING[0]}.*/export ${SETTING[0]}=\"${VALUE}\"/" \
    /etc/openvpn/easy-rsa/vars

    # Add settings should they be missing from the file.
    grep -qF "${SETTING[0]}" /etc/openvpn/easy-rsa/vars || \
    echo "export ${SETTING[0]}=\"${VALUE}\"" | \
    tee -a /etc/openvpn/easy-rsa/vars 1>/dev/null
    @@ -119,6 +134,9 @@ mv -f ./easy-rsa/keys .

    chmod 700 ./keys

    # Clean files that are not needed any more.
    find ./keys -type f \( ! -name '*.pem' ! -name '*.crt' ! -name '*.csr' ! -name '*.key' \) -delete

    tar -zcf \
    /root/easy-rsa.tar.gz \
    ./easy-rsa
    @@ -161,11 +179,13 @@ INSTANCE_NAME_TAG=$(aws ec2 describe-tags \
    # 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)
    # Fetch the EC2 instance tag which contains
    # the Elastic IP that should be used when
    # requesting the re-assotiation.
    PUBLIC_IP_ADDRESS=$(aws ec2 describe-tags \
    --query 'Tags[*].Value' \
    --filters "Name=resource-id,Values=${INSTANCE_ID}" "Name=key,Values=${TAG_NAME}" \
    --region $REGION --output 'text' 2>/dev/null)

    # Fetech current CIDR block for this VPC.
    VPC_CIDR=$(aws ec2 describe-vpcs \
    @@ -332,9 +352,8 @@ nobind
    dev tun
    dev-type tun
    $(for server in '443 tcp' '1194 udp'; do
    echo "remote $PUBLIC_IP_ADDRESS $server"
    done)
    remote $PUBLIC_IP_ADDRESS 443 tcp
    remote $PUBLIC_IP_ADDRESS 1194 udp
    push-peer-info
    server-poll-timeout 5
  4. @kwilczynski kwilczynski revised this gist Jun 8, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions vpn.sh
    Original file line number Diff line number Diff line change
    @@ -135,7 +135,7 @@ rm -Rf ./easy-rsa

    popd &>/dev/null

    for directory in /run/openvpn{,/tmp} /var/log/openvpn; do
    for directory in /var/lib/openvpn{,/tmp} /var/log/openvpn; do
    if [[ -d $directory ]]; then
    rm -Rf ${directory}/*
    else
    @@ -218,7 +218,7 @@ dev-type tun
    user nobody
    group nogroup
    chroot "/run/openvpn"
    chroot "/var/lib/openvpn"
    tmp-dir "/tmp"
    topology subnet
  5. @kwilczynski kwilczynski created this gist Jun 8, 2016.
    447 changes: 447 additions & 0 deletions vpn.sh
    Original file line number Diff line number Diff line change
    @@ -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