setup-vpn.sh 11.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
#!/bin/sh

##
## Setup OpenVPN to create the OpenStack management network.
## This script only runs on the "network" node.
##

set -x

DIRNAME=`dirname $0`

# Grab our libs
. "$DIRNAME/setup-lib.sh"

if [ "$HOSTNAME" != "$CONCENTRATOR" ]; then
    exit 0;
fi

logtstart "vpn"

if [ ! -f $OURDIR/vpn-server-done ]; then
    maybe_install_packages openvpn easy-rsa
fi

# Only initiate client setup scripts on vpn client hosts.
VPNHOSTS=""

#
# Get our server CA config set up.
#
export EASY_RSA="/etc/openvpn/easy-rsa"

if [ ! -f $OURDIR/vpn-server-done ]; then
    mkdir -p $EASY_RSA
    cp -r /usr/share/easy-rsa/* $EASY_RSA
    cd $EASY_RSA
    # Batch mode
    sed -i -e s/--interact/--batch/ $EASY_RSA/build-ca
    sed -i -e s/--interact/--batch/ $EASY_RSA/build-key-server
    sed -i -e s/--interact/--batch/ $EASY_RSA/build-key
    sed -i -e s/DEBUG=0/DEBUG=1/ $EASY_RSA/pkitool
fi

export OPENSSL="openssl"
export PKCS11TOOL="pkcs11-tool"
export GREP="grep"
export KEY_CONFIG="`$EASY_RSA/whichopensslcnf $EASY_RSA`"
export KEY_DIR="$EASY_RSA/keys"
export PKCS11_MODULE_PATH="dummy"
export PKCS11_PIN="dummy"
export KEY_SIZE=2048
export CA_EXPIRE=3650
export KEY_EXPIRE=3650

export KEY_COUNTRY="US"
export KEY_PROVINCE="UT"
export KEY_CITY="Salt Lake City"
export KEY_ORG="$EPID-$EEID"
TRUNCATED_EMAIL=`echo ${SWAPPER_EMAIL} | cut -c 1-40`
export KEY_EMAIL="${TRUNCATED_EMAIL}"
export KEY_CN="POWDERAggVPNCon"
export KEY_NAME=$KEY_CN
export KEY_OU=$KEY_CN
# --batch mode is unhappy if it's not this
export KEY_ALTNAMES="DNS:$CONCENTRATOR"

mkdir -p $KEY_DIR
cd $EASY_RSA

70 71 72 73
#
# Setup some openvpn config file lines from our parameters.
#
CONFIG_COMPRESS="comp-lzo no"
74 75 76
if [ -z "$VPN_COMPRESSION" -o "$VPN_COMPRESSION" = "none" ]; then
    CONFIG_COMPRESS="comp-lzo no"
elif [ "$VPN_COMPRESSION" = "yes" ]; then
77
    CONFIG_COMPRESS="comp-lzo yes"
78 79
elif [ -n "$VPN_COMPRESSION" ]; then
    CONFIG_COMPRESS="comp-lzo $VPN_COMPRESSION"
80 81
fi
CONFIG_CRYPT="cipher none"
82 83 84
if [ -z "$VPN_CIPHER" -o "$VPN_CIPHER" = "none" ]; then
    CONFIG_CRYPT="cipher none"
elif [ "$VPN_CIPHER" = "yes" ]; then
85
    CONFIG_CRYPT="cipher AES-128-CBC"
86 87
elif [ -n "$VPN_CIPHER" ]; then
    CONFIG_CRYPT="cipher $VPN_CIPHER"
88 89
fi

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
if [ ! -f $OURDIR/vpn-server-done ]; then
    # Handle the case on Ubuntu18 where easy-rsa is broken for openssl 1.1.0
    # (https://github.com/OpenVPN/easy-rsa/issues/159)
    openssl version | grep -iq '^openssl 1\.1\.'
    if [ $? -eq 0 -a -n "$KEY_CONFIG" -a ! -e $KEY_CONFIG -a -e openssl-1.0.0.cnf ]; then
	    cp -p openssl-1.0.0.cnf $KEY_CONFIG
	    echo '# For use with easy-rsa version 2.x and OpenSSL 1.1.0*' >> $KEY_CONFIG
	    echo '# For use with easy-rsa version 2.0 and OpenSSL 1.1.0*' >> $KEY_CONFIG
    fi

    # Fixup the openssl.cnf files
    for file in `ls -1 /etc/openvpn/easy-rsa/openssl*.cnf | xargs` ; do
	sed -i -e 's/^\(subjectAltName=.*\)$/#\1/' $file
    done

    export KEY_CN="POWDERAggVPNCon"
    ./clean-all
    ./build-ca
    # We needed a CN for the CA build -- but now we have to drop it cause
    # the build-key* scripts don't want it set -- they set it to the first arg,
    # and behave badly if it IS set.
    unset KEY_CN
    ./build-key-server $CONCENTRATOR
    cp -p $KEY_DIR/$CONCENTRATOR.crt $KEY_DIR/$CONCENTRATOR.key $KEY_DIR/ca.crt \
	/etc/openvpn/

    if [ -f $DIRNAME/etc/dh2048.pem ]; then
	cp $DIRNAME/etc/dh2048.pem /etc/openvpn
    else
	./build-dh
	cp -p $KEY_DIR/dh2048.pem /etc/openvpn/
    fi

    #
    # Get openvpn setup and restarted.
    #
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    # First, ensure the openvpn systemd deps will be correct.
    # Make sure we don't start the VPN until our network is up.
    # This is sort of magical, but it works.
    #
    mkdir /etc/systemd/system/openvpn@.service.d
    systemctl list-units | grep -q networking\.service
    if [ $? -eq 0 ]; then
	cat <<EOF >/etc/systemd/system/openvpn@.service.d/local-ifup.conf
[Unit]
Requires=networking.service
After=networking.service
EOF
    else
	systemctl list-units | grep -q network-online\.target
	if [ $? -eq 0 ]; then
	    cat <<EOF >/etc/systemd/system/openvpn@.service.d/local-ifup.conf
[Unit]
Requires=network-online.target
After=network-online.target
EOF
	fi
    fi
    systemctl daemon-reload

    #
    # Generate the server-side config file(s).
    #
David Johnson's avatar
David Johnson committed
153
    mkdir -p /etc/openvpn/ccd
154
    if [ $VPNTYPE = $TOPO_SUBNET -o $VPNTYPE = $TOPO_NET30 ]; then
155 156 157 158 159
	cat <<EOF > /etc/openvpn/server.conf
local $con_conlink_IP
port 1194
proto udp
dev tun
160
topology $VPNTYPE
161 162 163 164 165 166 167 168 169
ca ca.crt
cert $CONCENTRATOR.crt
key $CONCENTRATOR.key
dh dh2048.pem
server $VPN_NETWORK $VPN_MASK
client-config-dir /etc/openvpn/ccd
;client-to-client
;duplicate-cn
keepalive 10 120
170 171
$CONFIG_COMPRESS
$CONFIG_CRYPT
172 173
fragment 1468
mssfix 1468
174 175 176 177 178
persist-key
persist-tun
status openvpn-status.log
verb 3

179
push "route $mlan_NETWORK $mlan_MASK"
180
EOF
181 182 183 184 185 186 187 188 189 190
	# For each aggregate network, add a route to it on the concentrator.
	for aggprefix in $AGGREGATES ; do
	    agglan="${aggprefix}lan"
	    eval "varname=${agglan}_NETWORK"
	    eval "agg_net=\$$varname"
	    eval "varname=${agglan}_MASK"
	    eval "agg_mask=\$$varname"

	    echo "route $agg_net $agg_mask" >> /etc/openvpn/server.conf
	done
191 192 193 194

	systemctl daemon-reload
	systemctl enable openvpn@server.service
	systemctl start openvpn@server.service
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    elif [ $VPNTYPE = $TOPO_NET30MP ]; then
	# For each aggregate, add a separate server config file.
	for aggprefix in $AGGREGATES ; do
	    agglan="${aggprefix}lan"
	    eval "varname=${aggprefix}_HOST"
	    eval "agghost=\$$varname"
	    eval "varname=${aggprefix}_GW"
	    eval "agg_gw=\$$varname"
	    eval "varname=${agglan}_NETWORK"
	    eval "agg_net=\$$varname"
	    eval "varname=${agglan}_MASK"
	    eval "agg_mask=\$$varname"
	    eval "varname=${agglan}_CIDR"
	    eval "agg_cidr=\$$varname"
	    aggnum=`echo $aggprefix | sed -n -r -e 's/^agg([0-9]+)$/\1/p'`
	    sport=`expr 1194 + $aggnum`
	    node="${agghost}${aggprefix}"
	    eval "varname=${aggprefix}_VPN_NETWORK"
	    eval "agg_vpn_net=\$$varname"
	    eval "varname=${aggprefix}_VPN_MASK"
	    eval "agg_vpn_mask=\$$varname"

	    cat <<EOF > /etc/openvpn/$node.conf
local $con_conlink_IP
port $sport
proto udp
dev tun-$aggprefix
topology net30
ca ca.crt
cert $CONCENTRATOR.crt
key $CONCENTRATOR.key
dh dh2048.pem
server $agg_vpn_net $agg_vpn_mask
client-config-dir /etc/openvpn/ccd
;client-to-client
;duplicate-cn
keepalive 10 120
$CONFIG_COMPRESS
$CONFIG_CRYPT
fragment 1468
mssfix 1468
persist-key
persist-tun
status openvpn-status.log
verb 3

route $agg_net $agg_mask
EOF
	    systemctl daemon-reload
	    systemctl enable openvpn@$node.service
	    systemctl start openvpn@$node.service
246 247 248

	    # XXX: do this in a script on server-side, somehow
	    i=8
249
	    while [ ! -e /sys/class/net/tun-$aggprefix -a $i -gt 0 ]; do
250 251 252 253 254 255
		i=`expr $i - 1`
		sleep 1
	    done
	    ip rule add from $agg_cidr table $aggprefix
	    ip rule add iif tun-$aggprefix to $agg_cidr table $aggprefix
	    ip route add $mlan_CIDR dev tun-$aggprefix table $aggnum
256
	done
257
    else
258 259
	echo "VPNTYPE '$VPNTYPE' not yet supported; aborting!"
	exit 1
260 261 262 263 264 265 266 267 268 269 270 271
    fi

    touch $OURDIR/vpn-server-done
fi

#
# Now build keys and set static IPs for the aggregate VPNs.  We also
# generate config files for the aggregate VPNs.
#
mkdir -p /etc/openvpn/clients
for aggprefix in $AGGREGATES ; do
    agglan="${aggprefix}lan"
David Johnson's avatar
David Johnson committed
272 273 274 275
    eval "varname=${aggprefix}_HOST"
    eval "agghost=\$$varname"
    eval "varname=${aggprefix}_GW"
    eval "agg_gw=\$$varname"
276
    eval "varname=${agglan}_NETWORK"
David Johnson's avatar
David Johnson committed
277
    eval "agg_net=\$$varname"
278
    eval "varname=${agglan}_MASK"
David Johnson's avatar
David Johnson committed
279
    eval "agg_mask=\$$varname"
280
    eval "varname=${agglan}_CIDR"
David Johnson's avatar
David Johnson committed
281
    eval "agg_cidr=\$$varname"
282
    aggnum=`echo $aggprefix | sed -n -r -e 's/^agg([0-9]+)$/\1/p'`
283 284 285 286
    sport=1194
    if [ $VPNTYPE = $TOPO_NET30MP ]; then
	sport=`expr 1194 + $aggnum`
    fi
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

    node="${agghost}${aggprefix}"
    if [ -f /etc/openvpn/ccd/$node ]; then
	continue
    fi

    fqdn=`getfqdn $agghost`
    echo $VPNHOSTS | grep -q $fqdn
    if [ ! $? -eq 0 ]; then
	VPNHOSTS="${VPNHOSTS} $fqdn"
    fi

    export KEY_CN="$node"
    ./build-key $node

    #
    # Write its server-side client config bits.
    #
    #echo "ifconfig-push $NMIP 255.255.0.0" \
    #	> /etc/openvpn/ccd/$node
    echo "iroute $agg_net $agg_mask" >> /etc/openvpn/ccd/$node

    #
    # Write a client configuration, complete with up/down scripts.
    #
    cat <<EOF > /etc/openvpn/clients/$node.conf
client
dev tun-$aggprefix
proto udp
316
remote $con_conlink_IP $sport
317 318 319 320 321 322 323 324
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert $node.crt
key $node.key
ns-cert-type server
325 326
$CONFIG_COMPRESS
$CONFIG_CRYPT
327 328
fragment 1468
mssfix 1468
329 330
verb 3
route-up "/etc/openvpn/$node-route-up.sh"
331
route-pre-down "/etc/openvpn/$node-route-pre-down.sh"
332 333 334 335 336 337 338 339 340 341
EOF
    #
    # Note that because we have to pack multiple aggregates onto ctlnuc
    # vhosts, we also need per-agg-subnet route tables that we use
    # source routing to feed.  Real aggregate control NUCs would not
    # need this, of course.
    #
    cat <<EOF > /etc/openvpn/clients/$node-route-up.sh
#!/bin/sh

David Johnson's avatar
David Johnson committed
342 343
VNODES=\`/usr/local/etc/emulab/tmcc vnodelist | sed -nre 's/^VNODEID=(pcvm[0-9]*-[0-9]*) .*$/\1/p' | xargs\`
for vnode in \$VNODES ; do
344
    VTAG=\`/usr/local/etc/emulab/tmcc -n \$vnode ifconfig | sed -nre 's/^.* LAN=$agglan .*VTAG=([0-9]*).*$/\1/p'\`
David Johnson's avatar
David Johnson committed
345
    if [ -n "\$VTAG" ]; then
346 347 348
        break;
    fi
done
David Johnson's avatar
David Johnson committed
349
if [ -z "\$VTAG" ]; then
350 351 352
    echo "ERROR: fatal: could not find bridge for $agglan"
    exit 1
fi
353
BRNAME=br\$VTAG
354 355 356 357 358 359 360

mkdir -p /etc/iproute2
echo $aggnum $aggprefix >> /etc/iproute2/rt_tables
ip rule add from $agg_cidr table $aggprefix
ip rule add iif tun-$aggprefix to $agg_cidr table $aggprefix
ip route add $mlan_CIDR via $VPN_SERVER dev tun-$aggprefix table $aggprefix
ip route add 192.168.0.0/16 via $VPN_SERVER dev tun-$aggprefix table $aggprefix
361 362 363 364
ifconfig \$BRNAME $agg_gw netmask $agg_mask up
ip route add $agg_cidr dev \$BRNAME table $aggprefix
iptables -I FORWARD -o tun-$aggprefix -i \$BRNAME -j ACCEPT
iptables -I FORWARD -i tun-$aggprefix -o \$BRNAME -j ACCEPT
365 366
EOF
    chmod 755 /etc/openvpn/clients/$node-route-up.sh
367
    cat <<EOF > /etc/openvpn/clients/$node-route-pre-down.sh
368 369
#!/bin/sh

David Johnson's avatar
David Johnson committed
370 371
VNODES=\`/usr/local/etc/emulab/tmcc vnodelist | sed -nre 's/^VNODEID=(pcvm[0-9]*-[0-9]*) .*$/\1/p' | xargs\`
for vnode in \$VNODES ; do
372
    VTAG=\`/usr/local/etc/emulab/tmcc -n \$vnode ifconfig | sed -nre 's/^.* LAN=$agglan .*VTAG=([0-9]*).*$/\1/p'\`
David Johnson's avatar
David Johnson committed
373 374 375 376 377 378 379 380
    if [ -n "\$VTAG" ]; then
        break;
    fi
done
if [ -z "\$VTAG" ]; then
    echo "ERROR: fatal: could not find bridge for $agglan"
    exit 1
fi
381
BRNAME=br\$VTAG
David Johnson's avatar
David Johnson committed
382

383 384 385
ip rule del from $agg_cidr table $aggprefix
ip rule del iif tun-$aggprefix to $agg_cidr table $aggprefix
ip route flush table $aggprefix
386 387 388
ifconfig \$BRNAME 0 up
iptables -D FORWARD -o tun-$aggprefix -i \$BRNAME -j ACCEPT
iptables -D FORWARD -i tun-$aggprefix -o \$BRNAME -j ACCEPT
389
EOF
390
    chmod 755 /etc/openvpn/clients/$node-route-pre-down.sh
391 392 393 394

    #
    # Ok, copy the key/crts/conf files to the agg host
    #
David Johnson's avatar
David Johnson committed
395
    scp -p -o StrictHostKeyChecking=no \
396
	/etc/openvpn/ca.crt $KEY_DIR/$node* $fqdn:$OURDIR
David Johnson's avatar
David Johnson committed
397
    scp -p -o StrictHostKeyChecking=no \
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	/etc/openvpn/clients/$node* $fqdn:$OURDIR
done

unset KEY_COUNTRY
unset KEY_PROVINCE
unset KEY_CITY
unset KEY_ORG
unset KEY_EMAIL
unset KEY_NAME
unset KEY_OU
unset KEY_ALTNAMES

unset EASY_RSA
unset OPENSSL
unset PKCS11TOOL
unset GREP
unset KEY_CONFIG
unset PKCS11_MODULE_PATH
unset PKCS11_PIN
unset KEY_SIZE
unset CA_EXPIRE
unset KEY_EXPIRE

#
# Get the hosts files setup to point to the new management network
# and setup the VPN on the clients.
#
maybe_install_packages pssh
PSSH='/usr/bin/parallel-ssh -t 0 -O StrictHostKeyChecking=no '
PHOSTS=""
mkdir -p $OURDIR/pssh.setup-vpn.stdout $OURDIR/pssh.setup-vpn.stderr

for fqdn in $VPNHOSTS ; do
    PHOSTS="$PHOSTS -H $fqdn"
done

$PSSH -o $OURDIR/pssh.setup-vpn.stdout -e $OURDIR/pssh.setup-vpn.stderr \
    $PHOSTS $DIRNAME/setup-vpn-client.sh

logtend "vpn"

exit 0