2 # Copyright (C) 2016 Ian Kelling
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
19 [[ $EUID == 0 ]] ||
exec sudo
-E "$BASH_SOURCE" "$@"
21 readonly this_file
="$(readlink -f -- "${BASH_SOURCE[0]}")"; cd "${this_file%/*}"
26 usage: ${0##*/} VPN_SERVER_HOST
28 -b COMMON_NAME By default, use $CLIENT_HOST or if it is not given,
29 $HOSTNAME. If the cert already exists on the server,
30 with the CLIENT_NAME name, we use the existing one. See
31 comment below if we ever want to check existing common
32 names. They must be unique per server, so you can use
33 $(uuidgen) if needed. You used to be able to create
34 multiple with the same name, but not connect at the
35 same time, but now, the generator keeps track, so you
38 -c CLIENT_HOST Default is localhost. Else we ssh to root@CLIENT_HOST.
39 -f Force. Proceed even if cert already exists.
40 -n CONFIG_NAME default is client
41 -o SERVER_CONFIG_NAME Default is CONFIG_NAME
42 -s SCRIPT_PATH Use custom up/down script at SCRIPT_PATH. copied to same path
43 on client, if client is not localhost.
45 Generate a client cert and config and install it on locally or on
46 CLIENT_HOST if given. Uses default config options, and expects be able
47 to ssh to VPN_SERVER_HOST and CLIENT_HOST as root, or if CLIENT_HOST is
48 localhost, just to sudo this script as root.
53 Note: Uses GNU getopt options parsing style
58 # to get the common name
59 # cn=$(s openssl x509 -noout -nameopt multiline -subject \
60 # -in /etc/openvpn/client/mail.crt | \
61 # sed -rn 's/^\s*commonName\s*=\s*(.*)/\1/p')
64 ####### begin command line parsing and checking ##############
69 script=/etc
/openvpn
/update-resolv-conf
70 client_host
=$CLIENT_HOST
73 temp
=$
(getopt
-l help hb
:c
:fn
:o
:s
: "$@") || usage
1
77 -b) common_name
="$2"; shift 2 ;;
78 -c) client_host
=$2; shell
="ssh root@$client_host"; shift 2 ;;
79 -f) force
=true
; shift ;;
80 -n) name
="$2"; shift 2 ;;
81 -o) server_name
="$2"; shift 2 ;;
82 -s) custom_script
=true
; script="$2"; shift 2 ;;
85 *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
89 if [[ ! $server_name ]]; then
93 if [[ ! $common_name ]]; then
94 if [[ $client_host ]]; then
95 common_name
=$client_host
102 [[ $host ]] || usage
1
104 ####### end command line parsing and checking ##############
107 f
=/etc
/openvpn
/client
/$name.crt
110 if [[ $client_host ]]; then
111 cert_to_test
=$
(mktemp
)
112 ssh root@
$client_host cat $f 2>/dev
/null
>$cert_to_test ||
:
114 if ! $force && openssl x509
-checkend $
(( 60 * 60 * 24 * 30 )) -noout -in $cert_to_test &>/dev
/null
; then
115 echo "$0: cert already exists. exiting early"
120 # bash or else we get motd spam. note sleep 2, sleep 1 failed.
121 $shell '[[ -e /etc/openvpn ]] || apt install openvpn'
122 if ! ssh root@
$host bash
-s -- $server_name $common_name < client-cert-helper \
123 |
$shell 'id -u | grep -xF 0 || s=sudo; $s tar xzv -C /etc/openvpn/client'; then
124 echo ssh root@
$host cat /tmp
/vpn-mk-client-cert.log
:
125 ssh root@
$host cat /tmp
/vpn-mk-client-cert.log
126 echo EOF
for root@
$host:/tmp
/vpn-mk-client-cert.log
130 port
=$
(echo '/^port/ {print $2}' |
ssh root@
$host awk -f - /etc
/openvpn
/server
/$name.conf |
tail -n1)
133 if ! $shell "test -s $f"; then
134 # if common name is not unique, you get empty file. and if we didn't silence
135 # build-key, you'd see an error "TXT_DB error number 2"
136 echo "$0: error: $f is empty or otherwise bad. is this common name unique?"
140 $shell "dd of=/etc/openvpn/client/$name.conf" <<EOF
141 # From example config, from debian stretch to buster
146 resolv-retry infinite
153 # disabled for better performance
157 # matching server config
160 # example config has the commented line, but this other thing looks stronger,
161 # and I've seen it in a vpn provider I trust
162 # ns-cert-type server
163 remote-cert-tls server
165 # more resilient when running as nonroot
168 # See comments in server side configuration.
169 # The minimum of the client & server config is what is used by openvpn.
172 tls-auth ta-$name.key 1
175 if [[ $script ]]; then
176 $shell "tee -a /etc/openvpn/client/$name.conf" <<EOF
177 # This script will update local dns
178 # to what the server sends, if it sends dns.
184 if [[ $client_host ]] && $custom_script; then
185 $shell "dd of=$script" <$script
186 $shell "chmod +x $script"
190 $shell 'cd /etc/openvpn; for f in client/*; do ln -sf $f .; done'