EasyRSA: Difference between revisions

From Lolly's Wiki
Jump to navigationJump to search
m (Text replacement - "[[Kategorie:" to "[[Category:")
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Kategorie: Security]]
[[Category: Security]]
[[Kategorie: Linux]]
[[Category: Linux]]


=create CA user=
=create CA user=


<source lang=bash>
<syntaxhighlight lang=bash>
# groupadd -g 22000 ca && adduser --uid 22000 --gid 22000 --gecos "CA user" --encrypt-home ca  
# groupadd -g 22000 ca && adduser --uid 22000 --gid 22000 --gecos "CA user" --encrypt-home ca  
</source>
</syntaxhighlight>


=Do everything CA specific as CA user!=
=Do everything CA specific as CA user!=
<source lang=bash>
<syntaxhighlight lang=bash>
# su - ca
# su - ca
ca@rzeasyrsa:~$ ecryptfs-mount-private  
ca@rzeasyrsa:~$ ecryptfs-mount-private  
ca@rzeasyrsa:~$ cd  
ca@rzeasyrsa:~$ cd  
ca@rzeasyrsa:~$ exec bash
ca@rzeasyrsa:~$ exec bash
</source>
</syntaxhighlight>


=Setup EasyRSA=
=Setup EasyRSA=


==Ubuntu packets==
==Ubuntu packets==
<source lang=bash>
<syntaxhighlight lang=bash>
# aptitude install openvpn easy-rsa
# aptitude install openvpn easy-rsa
</source>
</syntaxhighlight>


==Create your CA==
==Create your CA==
<source lang=bash>
<syntaxhighlight lang=bash>
mkdir --mode=0700 OpenVPN-CA
mkdir --mode=0700 OpenVPN-CA
cd OpenVPN-CA
cd OpenVPN-CA
Line 30: Line 30:
rm -f vars clean-all
rm -f vars clean-all
cp /usr/share/easy-rsa/vars .
cp /usr/share/easy-rsa/vars .
</source>
</syntaxhighlight>


==Edit the defaults==
==Edit the defaults==
Line 60: Line 60:


Add a line after <i># output_password = secret</i>:
Add a line after <i># output_password = secret</i>:
<source lang=bash>
<syntaxhighlight lang=bash>
# output_password = secret
# output_password = secret
output_password = $ENV::KEY_PASS
output_password = $ENV::KEY_PASS
</source>
</syntaxhighlight>


After that the openssl calls taking the needed password from the environment variable <i>KEY_PASS</i>.
After that the openssl calls taking the needed password from the environment variable <i>KEY_PASS</i>.


You can call it like this for example:
You can call it like this for example:
<source lang=bash>
<syntaxhighlight lang=bash>
KEY_PASS="password" ./build-key-pass --batch user
KEY_PASS="password" ./build-key-pass --batch user
</source>
</syntaxhighlight>


==Create your CA certificate==
==Create your CA certificate==
Line 83: Line 83:
  $ cd OpenVPN-CA
  $ cd OpenVPN-CA
  $ . vars
  $ . vars
  $ ./build-key-server
  $ ./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=
=Create your OpenVPN config=
Line 89: Line 92:
==get_ovpn.sh==
==get_ovpn.sh==
I wrote a little helper script called get_ovpn.sh:
I wrote a little helper script called get_ovpn.sh:
<source lang=bash>
<syntaxhighlight lang=bash>
#!/bin/bash
#!/bin/bash


Line 95: Line 98:
# You may use it for free but on your own risk!!!
# You may use it for free but on your own risk!!!


# Defaults:
TYPE="client"
TYPE="client"
KEY_DIR="OpenVPN-CA/keys"
KEY_DIR="OpenVPN-CA/keys"
Line 156: Line 158:
   -s|--server-name)
   -s|--server-name)
     SERVER=${value}
     SERVER=${value}
    export SERVER
     ;;
     ;;
   *)
   *)
Line 178: Line 179:
[ ! -f "${KEY_DIR}/${OVPN_USER}.crt" -a "_${TYPE}_" == "_client_" ] && usage "Certificate ${KEY_DIR}/${OVPN_USER}.crt 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 \
gawk \
   -v user="${OVPN_USER}" \
   -v user="${OVPN_USER}" \
Line 197: Line 199:
     if ($1 == part) {
     if ($1 == part) {
       for(i=2;i<=NF;i++){
       for(i=2;i<=NF;i++){
        if(i==NF) gsub(/\//,", ", $i)
         retval=retval""$i;
         retval=retval""$i;
         if(i<NF) retval=retval" ";
         if(i<NF) retval=retval" ";
Line 203: Line 206:
   };
   };
   close(command);
   close(command);
  gsub(/\//,", ", retval)
   return retval;
   return retval;
}
}
Line 218: Line 220:
{
{
   # Static part
   # Static part
  # Replace all <VARIABLE> in template file with ENVIRON["VARIABLE"]
   rest=$0;
   rest=$0;
   while(match(rest,/<[A-Z0-9_]+>/)) {
   while(match(rest,/<[A-Z0-9_]+>/)) {
Line 245: Line 245:
   printf "\n";
   printf "\n";


   # CA Certificate
   # Ca Certificate
   if (configtype=="client") {
   if (configtype=="client") {
     printf "verify-x509-name \"%s\"\n",print_part("Subject:",key_dir"/"server".crt");
     printf "verify-x509-name \"%s\"\n",print_part("Subject:",key_dir"/"server".crt");
Line 266: Line 266:
   #print ENVIRON["SERVER_NET"];
   #print ENVIRON["SERVER_NET"];
}' ${TEMPLATE}
}' ${TEMPLATE}
</source>
</syntaxhighlight>


  ca@rzeasyrsa:~$ ./get_ovpn.sh --help
  ca@rzeasyrsa:~$ ./get_ovpn.sh --help
Line 277: Line 277:
   -s|--server                             Servername for --config-type=server
   -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
   --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 ==
Line 337: Line 335:


===Generate OpenVPN Config for server===
===Generate OpenVPN Config for server===
<source lang=bash>
<syntaxhighlight lang=bash>
ca@rzeasyrsa:~$ ./get_ovpn.sh  \
ca@rzeasyrsa:~$ ./get_ovpn.sh  \
   --server openvpn \
   --server openvpn \
Line 351: Line 349:
   --template server.ovpn \
   --template server.ovpn \
   --key-dir=OpenVPN-CA/keys
   --key-dir=OpenVPN-CA/keys
</source>
</syntaxhighlight>


==OpenVPN Client==
==OpenVPN Client==
Line 383: Line 381:
</pre>
</pre>
===Generate OpenVPN Config for server===
===Generate OpenVPN Config for server===
<source lang=bash>
<syntaxhighlight lang=bash>
ca@rzeasyrsa:~$ ./get_ovpn.sh  \
ca@rzeasyrsa:~$ ./get_ovpn.sh  \
   --config-type client \
   --config-type client \
Line 391: Line 389:
   --key-dir    OpenVPN-CA/keys \
   --key-dir    OpenVPN-CA/keys \
   --user        vpnclient
   --user        vpnclient
</source>
</syntaxhighlight>

Latest revision as of 04:54, 26 November 2021


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

  1. I am using the mysql-auth-plugin from https://github.com/chantra/openvpn-mysql-auth
  2. 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