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 $HOSTNAME or $CLIENT_HOST. If the cert
29 already exists on the server, with the CLIENT_NAME
30 name, we use the existing one. See comment below if we
31 ever want to check existing common names. They must be
32 unique per server, so you can use $(uuidgen) if
33 needed. You used to be able to create multiple with the
34 same name, but not connect at the same time, but now,
35 the generator keeps track, so you can't generate.
36 -c CLIENT_HOST default is localhost. Else we ssh to root@CLIENT_HOST
37 -n CONFIG_NAME default is client
38 -s SCRIPT_PATH Use custom up/down script at PATH, copied to same path
41 Generate a client cert and config and install it on locally or on
42 CLIENT_HOST if given. Uses default config options, and expects be able
43 to ssh to VPN_SERVER_HOST and CLIENT_HOST as root, or if CLIENT_HOST is
44 localhost, just to sudo this script as root.
49 Note: Uses GNU getopt options parsing style
54 # to get the common name
55 # cn=$(s openssl x509 -noout -nameopt multiline -subject \
56 # -in /etc/openvpn/client/mail.crt | \
57 # sed -rn 's/^\s*commonName\s*=\s*(.*)/\1/p')
60 ####### begin command line parsing and checking ##############
65 script=/etc
/openvpn
/update-resolv-conf
66 client_host
=$CLIENT_HOST
68 temp
=$
(getopt
-l help hb
:c
:n
:s
: "$@") || usage
1
72 -b) common_name
="$2"; shift 2 ;;
73 -c) client_host
=$2; shell
="ssh root@$client_host"; shift 2 ;;
74 -n) name
="$2"; shift 2 ;;
75 -s) custom_script
=true
; script="$2"; shift 2 ;;
78 *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
82 if [[ ! $common_name ]]; then
83 if [[ $client_host ]]; then
84 common_name
=$client_host
91 [[ $host ]] || usage
1
93 ####### end command line parsing and checking ##############
96 # bash or else we get motd spam. note sleep 2, sleep 1 failed.
97 if ! ssh root@
$host bash
-s -- $name $common_name < client-cert-helper \
98 |
$shell 'id -u | grep -xF 0 || s=sudo; $s tar xzv -C /etc/openvpn/client'; then
99 echo ssh root@
$host cat /tmp
/vpn-mk-client-cert.log
:
100 ssh root@
$host cat /tmp
/vpn-mk-client-cert.log
105 f
=/etc
/openvpn
/client
/$name.crt
106 if ! $shell "test -s $f"; then
107 # if common name is not unique, you get empty file. and if we didn't silence
108 # build-key, you'd see an error "TXT_DB error number 2"
109 echo "$0: error: $f is empty or otherwise bad. is this common name unique?"
113 $shell "dd of=/etc/openvpn/client/$name.conf" <<EOF
114 # From example config, from debian stretch to buster
119 resolv-retry infinite
126 # disabled for better performance
130 # This script will update local dns
131 # to what the server sends, if it sends dns.
136 # matching server config
140 # example config has the commented line, but this other thing looks stronger,
141 # and I've seen it in a vpn provider I trust
142 # ns-cert-type server
143 remote-cert-tls server
145 # more resilient when running as nonroot
148 # See comments in server side configuration.
149 # The minimum of the client & server config is what is used by openvpn.
152 tls-auth $name-ta.key 1
155 if [[ $client_host ]] && $custom_script; then
156 $shell "dd of=$script" <$script
157 $shell "chmod +x $script"
160 $shell 'cd /etc/openvpn; for f in client/*; do ln -sf $f .; done'