As part of writing up how to run OpenVPN on VyOS, I wrote about how to create a certificate authority with easy-rsa version 2 since that’s what comes with the VyOS distribution.

easy-rsa3 is current and what you get when you pull from github. Organizationally (directory hierarchy wise) it’s a bunch better than easy-rsa2, particularly if you’re locally generating certificates in one swoop and then installing them via some secure process (e.g. sneakernet thumb drive) onto your employees’ computers. It also doesn’t have a bajillion scripts; commands are all arguments to a 1200 line shell script.

Below is a walk-through on initializing a CA and creating a CRL and a pair of client certs.

merlot:~ rs$ git clone https://github.com/OpenVPN/easy-rsa.git
Cloning into 'easy-rsa'...
remote: Counting objects: 485, done.
remote: Total 485 (delta 0), reused 0 (delta 0), pack-reused 485
Receiving objects: 100% (485/485), 182.07 KiB | 0 bytes/s, done.
Resolving deltas: 100% (184/184), done.
Checking connectivity... done.
merlot:~ rs$ cd easy-rsa/easyrsa3
merlot:easyrsa3 rs$ ./easyrsa init-pki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /Users/rs/easy-rsa/easyrsa3/pki

merlot:easyrsa3 rs$ ./easyrsa build-ca
Generating a 2048 bit RSA private key
.+++
.+++
writing new private key to '/Users/rs/easy-rsa/easyrsa3/pki/private/ca.key.eDR26xNV2Q'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:Cool Kids CA

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/Users/rs/easy-rsa/easyrsa3/pki/ca.crt

merlot:easyrsa3 rs$ 

OK, now we have a CA. Next thing we need to do is create a cert pair and then immediately revoke it. Why would I want to do this? Well, almost all software that uses X.509 certs can be configured to check a CRL. Unfortunately, the OpenSSL libraries don’t deal well with pointing at an empty file for this - there has to be at least an single revoked cert in the file and it would stand to reason that it would barf if it wasn’t properly signed by the CA that it’s supposed to be issued against. So… create a bogus key pair and then revoke.

merlot:easyrsa3 rs$ ./easyrsa build-client-full boguscert
Generating a 2048 bit RSA private key
.........................................+++
.+++
writing new private key to '/Users/rs/easy-rsa/easyrsa3/pki/private/boguscert.key.IalHeBjQOl'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Using configuration from /Users/rs/easy-rsa/easyrsa3/openssl-1.0.cnf
Enter pass phrase for /Users/rs/easy-rsa/easyrsa3/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'boguscert'
Certificate is to be certified until Oct 26 12:02:50 2026 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
merlot:easyrsa3 rs$ 


merlot:easyrsa3 rs$ ./easyrsa revoke boguscert


Please confirm you wish to revoke the certificate with the following subject:

subject= 
commonName                = boguscert


Type the word 'yes' to continue, or any other input to abort.
  Continue with revocation: yes
Using configuration from /Users/rs/easy-rsa/easyrsa3/openssl-1.0.cnf
Enter pass phrase for /Users/rs/easy-rsa/easyrsa3/pki/private/ca.key:
Revoking Certificate ACEF63D602CF6940620EA28E1931F78E.
Data Base Updated

IMPORTANT!!!

Revocation was successful. You must run gen-crl and upload a CRL to your
infrastructure in order to prevent the revoked cert from being accepted.

merlot:easyrsa3 rs$ 


merlot:easyrsa3 rs$ ./easyrsa gen-crl
Using configuration from /Users/rs/easy-rsa/easyrsa3/openssl-1.0.cnf
Enter pass phrase for /Users/rs/easy-rsa/easyrsa3/pki/private/ca.key:

An updated CRL has been created.
CRL file: /Users/rs/easy-rsa/easyrsa3/pki/crl.pem

merlot:easyrsa3 rs$ 

Did you notice that I was using build-client-full rather than gen-req? If you are used to a workflow that involves creating a req for an SSL cert, sending it off to the CA, having them sign it, and getting a public key back in the email you may find this a little confusing, but since I’m both the CA and the certificate requester, the easy-rsa authors decided to make it easy for me by creating a CA command to gen-req then sign-req in one shot.

Now I’m going to make a client key pair for my laptop. Note the use of “nopass” here - I’m not password protecting the pair. I’m just going to import it to my Mac. If you decide to do this too, I won’t judge (hey, I’m the one giving the example here), but you better understand the ecosystem that you’re working in and be able to explain why it was or wan’t OK to do it that way.

merlot:easyrsa3 rs$ ./easyrsa build-client-full rs-laptop nopass
Generating a 2048 bit RSA private key
................+++
............................+++
writing new private key to '/Users/rs/easy-rsa/easyrsa3/pki/private/rs-laptop.key.BnkIZC1Hir'
-----
Using configuration from /Users/rs/easy-rsa/easyrsa3/openssl-1.0.cnf
Enter pass phrase for /Users/rs/easy-rsa/easyrsa3/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'rs-laptop'
Certificate is to be certified until Oct 26 12:25:51 2026 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
merlot:easyrsa3 rs$ 

Where do all the interesting bits end up? Three subdirectories, though to be fair the ones that are more than passingly interesting are ./pki/private and ./pki/issued

merlot:easyrsa3 rs$ find . -type f -name "*rs-laptop*" -print
./pki/issued/rs-laptop.crt
./pki/private/rs-laptop.key
./pki/reqs/rs-laptop.req
merlot:easyrsa3 rs$ 

Lastly, we have to combine into a single file and double click to import it to my login keychain via Keychain Access (on a Mac; other platforms are left as an exercise to the reader).

cat pki/private/rs-laptop.key pki/issued/rs-laptop.crt > rs-laptop.pem