EasyRSA
From Lolly's Wiki
create CA user
# groupadd -g 22000 ca && adduser --uid 22000 --gid 22000 --gecos "CA user" --encrypt-home ca
Do everything CA specific as CA user!
# su - ca
ca@rzeasyrsa:~$ ecryptfs-mount-private
ca@rzeasyrsa:~$ cd
ca@rzeasyrsa:~$ exec bash
Setup EasyRSA
Ubuntu packets
# aptitude install openvpn easy-rsa
Create your CA
mkdir --mode=0700 OpenVPN-CA
cd OpenVPN-CA
for i in /usr/share/easy-rsa/* ; do ln -s $i ; done
rm -f vars clean-all
cp /usr/share/easy-rsa/vars .
Edit the defaults
Setup proper defaults in your vars file. Source it every time before you do CA work.
Base setup (Only one time at the beginning!!!)
Really just do this before you start with your CA. It will delete everything: keys and certificates!!!
$ cd OpenVPN-CA $ . vars $ /usr/share/easy-rsa/clean-all
Generate DH parameter
$ cd OpenVPN-CA $ . vars $ KEY_SIZE=4096 ./build-dh
or
$ cd OpenVPN-CA/keys $ openssl dhparam -2 -out dh4096.pem 4096
Generate TLS-auth parameter
$ cd OpenVPN-CA/keys $ /usr/sbin/openvpn --genkey --secret ta.key
User certificates with passwords in scripts
If you want to work with password encrypted keys and wat to batch process many users, you might find this helpful.
Add a line after # output_password = secret:
# output_password = secret
output_password = $ENV::KEY_PASS
After that the openssl calls taking the needed password from the environment variable KEY_PASS.
You can call it like this for example:
KEY_PASS="password" ./build-key-pass --batch user
Create your CA certificate
$ cd OpenVPN-CA $ . vars $ ./buid-ca
Check it with
$ openssl x509 -noout -text -in keys/ca.crt
Create the server certificate
$ cd OpenVPN-CA $ . vars $ ./build-key-server openvpn-server
For example server keys with 5 years validity:
$ KEY_EXPIRE=1825 ./build-key-server openvpn-server
Create your OpenVPN config
get_ovpn.sh
I wrote a little helper script called get_ovpn.sh:
#!/bin/bash
# Written by Lars Timmann L@rs.Timmann.de> 2016
# You may use it for free but on your own risk!!!
TYPE="client"
KEY_DIR="OpenVPN-CA/keys"
function usage() {
if [ "_${1}_" != "_help_" ]
then
printf "ERROR: $*\n"
fi
printf "Options:\n"
cat <<EOF
-h|--help This help
-c|--config-type Default: client (client|server)
-k|--key-dir Default: OpenVPN-CA/keys Directory where certificates and keys can be found
-t|--template Default: ${configtype}.ovpn The template to use
-u|--user User to create config for
-s|--server Servername for --config-type=server
--what-ever=value Replace <WHAT_EVER> in template with value e.g.: --server-net=... replaces <SERVER_NET> with the given value
EOF
exit 1
}
while [ $# -gt 0 ]
do
#if [ $# -ge 2 ]; then value=$2; fi
case $1 in
-h|--help)
usage "help"
;;
--?*=?*|-?*=?*)
param=${1%=*}
value=${1#*=}
shift;
;;
--?*=|-?*=)
param=${1%=*}
usage "${param} needs a vlaue!"
;;
*)
if [ $# -lt 2 ] ; then usage "$1 needs a value!"; fi
param=$1
value=$2
shift; shift;
;;
esac
case $param in
-t|--template)
TEMPLATE=${value}
;;
-k|--key-dir)
KEY_DIR=${value}
;;
-u|--user)
OVPN_USER=${value}
;;
-c|--config-type)
TYPE=${value}
;;
-s|--server-name)
SERVER=${value}
;;
*)
param=${param#--}
param=${param/-/_}
export ${param^^}=${value}
;;
esac
done
TEMPLATE=${TEMPLATE:-"${TYPE}.ovpn"}
[ -z "${SERVER}" -a "_${TYPE}_" == "_server_" ] && usage "For which server?\n"
[ -z "${OVPN_USER}" -a "_${TYPE}_" == "_client_" ] && usage "For which user?\n"
[ ! -f "${TEMPLATE}" ] && usage "Template file ${TEMPLATE} not found!\n"
[ ! -d "${KEY_DIR}" ] && usage "Key directory ${KEY_DIR} not found!\n"
[ ! -f "${KEY_DIR}/ta.key" ] && usage "TLS Auth ${KEY_DIR}/ta.key not found!\n"
[ ! -f "${KEY_DIR}/ca.crt" ] && usage "CA Certificate ${KEY_DIR}/ca.crt not found!\n"
[ ! -f "${KEY_DIR}/${SERVER}.key" -a "_${TYPE}_" == "_server_" ] && usage "Private key ${KEY_DIR}/${SERVER}.key not found!\n"
[ ! -f "${KEY_DIR}/${SERVER}.crt" -a "_${TYPE}_" == "_server_" ] && usage "Certificate ${KEY_DIR}/${SERVER}.crt not found!\n"
[ ! -f "${KEY_DIR}/${OVPN_USER}.key" -a "_${TYPE}_" == "_client_" ] && usage "Private key ${KEY_DIR}/${OVPN_USER}.key not found!\n"
[ ! -f "${KEY_DIR}/${OVPN_USER}.crt" -a "_${TYPE}_" == "_client_" ] && usage "Certificate ${KEY_DIR}/${OVPN_USER}.crt not found!\n"
export SERVER
gawk \
-v user="${OVPN_USER}" \
-v key_dir="${KEY_DIR}" \
-v configtype="${TYPE}" \
-v server="${SERVER}" \
'
function print_fingerprint(certfile){
command="openssl x509 -noout -fingerprint -in "certfile;
FS="=";
while(command | getline);
retval=$2;
close(command);
return retval;
}
function print_part(part,certfile){
command="openssl x509 -noout -text -in "certfile;
while(command | getline){
if ($1 == part) {
for(i=2;i<=NF;i++){
if(i==NF) gsub(/\//,", ", $i)
retval=retval""$i;
if(i<NF) retval=retval" ";
}
}
};
close(command);
return retval;
}
function print_cert(name,certfile){
# Header
#printf "# %s\n",certfile;
while(getline < certfile){if(/^#/) print $0};
close(certfile);
printf "<%s>\n",name;
while(getline < certfile){if(!/^#/) print $0};
close(certfile);
printf "</%s>\n",name;
}
{
# Static part
rest=$0;
while(match(rest,/<[A-Z0-9_]+>/)) {
matched=substr(rest,RSTART+1,RLENGTH-2);
##print "Matched:",matched;
if (ENVIRON[matched]) gsub("<"matched">",ENVIRON[matched]);
rest=substr(rest,RSTART+RLENGTH);
}
print $0;
}
END{
# Dynamic part
if(configtype=="client") {
printf "remote-cert-tls server\n";
} else {
printf "remote-cert-tls client\n";
}
# TLS Auth
print_cert("tls-auth",key_dir"/ta.key");
printf "key-direction %d\n",(configtype=="client");
printf "\n";
print_cert("dh",key_dir"/dh4096.pem");
printf "\n";
# Ca Certificate
if (configtype=="client") {
printf "verify-x509-name \"%s\"\n",print_part("Subject:",key_dir"/"server".crt");
}
printf "verify-hash %s\n",print_fingerprint(key_dir"/ca.crt");
print_cert("ca",key_dir"/ca.crt");
printf "\n";
# User Data
if (configtype=="client") {
print_cert("cert",key_dir"/"user".crt");
printf "\n";
print_cert("key",key_dir"/"user".key");
printf "\n";
} else {
print_cert("cert",key_dir"/"server".crt");
printf "\n";
# key secret/<SERVER>.key is in template
}
#print ENVIRON["SERVER_NET"];
}' ${TEMPLATE}
ca@rzeasyrsa:~$ ./get_ovpn.sh --help Options: -h|--help This help -c|--config-type Default: client (client|server) -k|--key-dir Default: OpenVPN-CA/keys Directory where certificates and keys can be found -t|--template Default: .ovpn The template to use -u|--user User to create config for -s|--server Servername for --config-type=server --what-ever=value Replace <WHAT_EVER> in template with value e.g.: --server-net=... replaces <SERVER_NET> with the given value
OpenVPN Server
OpenVPN Server Template
- I am using the mysql-auth-plugin from https://github.com/chantra/openvpn-mysql-auth
- On the OpenVPN-Server the user openvpn has uid 1195 and gid 1195 and I have a TMP-dir for this user in the /etc/fstab like this:
none /run/openvpn_tmp tmpfs nodev,noexec,nosuid,size=5m,mode=0700,uid=1195,gid=1195 0 0
Example server.ovpn:
local <SERVER_IP> port <SERVER_PORT> tmp-dir /run/openvpn_tmp management <MANAGEMENT_IP> <MANAGEMENT_PORT> /etc/openvpn/management-password proto udp dev tun tun-mtu 1500 mssfix topology subnet server <SERVER_NET> <SERVER_NETMASK> push "redirect-gateway def1 bypass-dhcp" push "dhcp-option DNS <DNS1>" push "dhcp-option DNS <DNS2>" push "route 192.168.18.0 255.255.255.0 net_gateway" push "route 192.168.0.0 255.255.0.0" push "route 10.0.0.0 255.0.0.0" push "route 172.28.0.0 255.255.0.0" client-to-client duplicate-cn keepalive 10 120 auth SHA512 cipher AES-256-CBC tls-cipher DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-RSA-AES128-SHA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA reneg-sec 36000 comp-lzo adaptive max-clients 25 user openvpn group openvpn persist-key persist-tun status /var/log/openvpn/<SERVER>-status.log 2 status-version 2 log-append /var/log/openvpn/<SERVER>-openvpn.log verb 3 plugin /usr/lib/openvpn/libopenvpn-mysql-auth.so -c /etc/openvpn/auth/<SERVER>_auth_mysql.conf key secret/<SERVER>.key # This file should be kept secret remote-cert-tls client username-as-common-name
Generate OpenVPN Config for server
ca@rzeasyrsa:~$ ./get_ovpn.sh \
--server openvpn \
--config-type server \
--server-ip=192.168.18.23 \
--server-port=1234 \
--server-net=10.214.60.128 \
--server-netmask=255.255.255.128 \
--management-ip=192.168.17.23 \
--management-port=11234 \
--dns1=192.168.0.50 \
--dns2=192.168.0.30 \
--template server.ovpn \
--key-dir=OpenVPN-CA/keys
OpenVPN Client
OpenVPN client template
Example client.ovpn:
client dev tun proto udp remote <SERVER_IP> <SERVER_PORT> tls-client ns-cert-type server comp-lzo auth-user-pass auth SHA512 cipher AES-256-CBC tls-cipher DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-RSA-AES128-SHA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA #tls-version-min 1.2 route-delay 5 30 persist-key persist-tun nobind mssfix push-peer-info reneg-sec 0 tun-mtu 1500 verb 3 #auth-nocache
Generate OpenVPN Config for server
ca@rzeasyrsa:~$ ./get_ovpn.sh \
--config-type client \
--server-ip 192.168.18.23 \
--server-port 1234 \
--template client.ovpn \
--key-dir OpenVPN-CA/keys \
--user vpnclient