Build your own PKI Server
In this post, i'm going to walk you through setting up your own PKI (Private Key Infrastructure) servers that will include both a Root CA, and an Intermediate CA. For this build, i've deployed 2 Centos Stream 9 VMs. Both are a very small build with a single vCPU, 2GB of RAM and a 20GB HDD because all these guys are going to do is certificates. The reason i created two, was because once I've signed the ICA certificate with my Root CA, I'm going to disable the network on it so that it's not reachable in order to keep it secure. So let's get started.
Once you've deployed your Centos server, first things first, run a yum -y update or a dnf -y update to ensure all packages are up to date.
dnf -y update
Once all of your server packages are up to date, let's get started on our PKI build. I'm going to create a separate user for everything pki called pkiadmin so first step is to create your user. The reason for this is that the CA and ICA ssl configurations will be done within that user. If you only have a single server to do this on, you can use the pkiadmin users homedir for both by creating a subdir called ca and another called ica for your root CA build, and ICA build.
useradd pkiadmin
passwd pkiadmin
usermod -aG wheel pkiadmin
With your pki user created and a password set, make sure that openssl is installed (which it should be) by running
dnf install openssl
Configure your Root CA
With all of the required packages and users created, let's get started by configuring our Root CA. To start, let's create the required directory structure and necessary files under the pkiadmin user home dir. SSH to your PKI server and login with the pkiadmin credentials and run the following commands.
cd ~/
mkdir ca
cd ./ca
mkdir newcerts certs crl private requests
touch index.txt
touch index.txt.attr
These folders/files are used as follows:
- newcerts - This is where all historically created certs are stored.
- certs - This will be used to store the certificates and also the .pfx files that you create.
- crl - Will store the Certificate Revocation List (CRL) file when created.
- private - This is where all the private keys for the certificates will be stored.
- requests - This is where all the CSR requests will be stored.
- index.txt - This is the "database" for your certificates used by openssl to manage the CA.
Next, ensure that only the pkiadmin user can access the CA folders.
chmod 700 /home/pkiadmin/ca
Create the CA certificate
Now that you have your directory structure setup, it's time to create your Root CA Certificate. This is the certificate that you will use to sign your ICA certificates with. To do that, you will need to create an openssl.cnf file within the CA directory under your pkiadmin user. I've attached the CA file that i'm using here. This openssl file will sign certificates with a default of 2200 days which is fine for an ICA. Given this is our Root CA certificate, we want it to last a long time. If you wish to use the same configuration file as I am, you should only need to change the sections within the cnf file marked #CHANGEME.
[ CA_default ]
# Directory and file locations.
dir = /home/pkiadmin/ca # CHANGEME
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/private/ca.key # CHANGEME
certificate = $dir/certs/ca.crt # CHANGEME
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl # CHANGEME
crl_extensions = crl_ext
default_crl_days = 30
...... excluded for brevity ......
[ req_distinguished_name ]
countryName = AU # CHANGEME
localityName = Queensland # CHANGEME
0.organizationName = COMPANY NAME # CHANGEME
commonName = COMPANY-NAME-CA # CHANGEME
emailAddress = email@company.com # CHANGEME
Now that you have your openssl.cnf file, it's time to generate the Root CA Key file. Use the command openssl genrsa from your pkiadmin ca directory.
sudo openssl genrsa -aes256 -out private/ca.key
This will prompt you to enter a password, make sure that you use a secure password and one that you will remember as this is required to sign the ICA certificate.
[pkiadmin@wrmempki01 ca]$ sudo openssl genrsa -aes256 -out private/ca.key
[sudo] password for pkiadmin:
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
[pkiadmin@wrmempki01 ca]$
With the keyfile created, it's time to create the Root CA Certificate. To do this, use the openssl req command.
[pkiadmin@wrmempki01 ca]$ sudo openssl req -config openssl.cnf -new -x509 -extensions v3_ca -key private/ca.key -out ca.crt -days 9125
Enter pass phrase for private/ca.key:
[pkiadmin@wrmempki01 ca]$
That's it, you now have a fully functioning Root CA. You can either stop there, or if you want to deploy an Intermediate CA as well, keep reading.
Configure your ICA
As with the CA configuration, the first step for the ICA, is to create the required folder structure. I've done this on a second server, but you can also use the same server that the Root CA is on. If you're using 2 servers, SSH into the second server, and use the same commands in the Root CA build to create the pkiadmin user. Once you've done that, log in as the pkiadmin user and create the following directory structure and set the required permissions.
cd ~/
mkdir ica
cd ./ica
mkdir newcerts certs crl private requests
touch index.txt
touch index.txt.attr
chmod 700 /home/pkiadmin/ica
Once again, you will need to create an openssl.cnf file for your ICA server. Again, you can download and use the same openssl.cnf file I am using here. Once again, you only need to change the bits marked # CHANGEME. The following are the relevent sections of the configuration file.
[ CA_default ]
# Directory and file locations.
dir = /home/pkiadmin/ica # CHANGEME
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/private/ica.key # CHANGEME
certificate = $dir/certs/ica.crt # CHANGEME
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ica.crl # CHANGEME
crl_extensions = crl_ext
default_crl_days = 30
..... excluded for brevity ...
[ req_distinguished_name ]
countryName = AU # CHANGEME
localityName = Queensland # CHANGEME
0.organizationName = COMPANY NAME # CHANGEME
commonName = COMPANY-NAME-CA # CHANGEME
emailAddress = email@company.com # CHANGEME
Once you have created the ICA openssl.cnf file, it's time to create the ica key using the openssl genrsa command. Once again, you will be prompted for a password so make sure it's a secure one, and that you remember it as this is required when signing server and user certificates.
[pkiadmin@wrmempki02 ica]$ sudo openssl genrsa -aes256 -out private/ica.key
[sudo] password for pkiadmin:
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
[pkiadmin@wrmempki02 ica]$
Create the ICA CSR
With the key file created, you now need to create a CSR for the root CA to sign. As i mentioned earlier, my openssl.cnf files have a default setting of 2200 days. This is long for a server certificate and it's usually less than a year but this is for a LAB environment so I've made it longer.
[pkiadmin@wrmempki02 ica]$ sudo openssl req -config openssl.cnf -new -key private/ica.key -out requests/ica.csr
Enter pass phrase for private/ica.key:
[pkiadmin@wrmempki02 ica]$
Note that if you are using a single server and have created the ca and ica on the same pkiadmin user, use the following command to create the CSR.
sudo openssl req -config openssl.cnf -new -key private/ica.key -out ../ca/requests/ica.csr
Now that you've created your CSR, you will need to sign if using your Root CA certificate. If you've created multiple servers, scp the csr to your CA pkiadmin requests directory then SSH into your CA server as your pkiadmin user.
scp ./requests/ica.csr pkiadmin@pki01:/home/pkiadmin/ca/requests/
With the CSR on the CA, it's time to sign the ICA certificate. As this is an ICA certificiate, you need to use the openssl ca command. For my build, I also decided to use a random hex value for the certificate number, you don't need to do this, but I chose to because why not. After you enter the openssl ca command, you will be prompted for the CA certificate password. Enter this, then confirm that the certificate details are correct. If they are, press y and hit enter to confirm.
[pkiadmin@wrmempki01 ca]$ sudo openssl rand -out serial -hex 20
[pkiadmin@wrmempki01 ca]$ sudo openssl ca -config openssl.cnf -extensions v3_intermediate_ca -notext -in requests/ica.csr -out certs/ica.crt
Using configuration from openssl.cnf
Enter pass phrase for /home/pkiadmin/ca/private/ca.key:
80BBB71E697F0000:error:0700006C:configuration file routines:NCONF_get_string:no value:crypto/conf/conf_lib.c:315:group=<NULL> name=unique_subject
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number:
68:4b:38:b5:23:5e:d4:a0:f4:ce:82:92:2e:20:da:09:0a:30:1f:d7
Validity
Not Before: Jan 11 06:07:16 2024 GMT
Not After : Jan 19 06:07:16 2030 GMT
Subject:
countryName = AU
localityName = Queensland
organizationName = WRMEM
commonName = WRMEM-ICA
emailAddress = webadmin@wr-mem.net
X509v3 extensions:
X509v3 Subject Key Identifier:
94:96:67:C0:84:87:07:95:C6:DD:68:2E:08:ED:AC:DE:82:CA:E6:69
X509v3 Authority Key Identifier:
93:39:AE:51:64:11:E0:81:2A:A8:6A:F2:3D:F2:1A:79:4D:FE:60:C2
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Certificate is to be certified until Jan 19 06:07:16 2030 GMT (2200 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
That's it. We now have a signed ICA certificate. The next thing to do is to create a certificate chain, and then copy these certificates back to your ICA server. A certificate chain is just as it sounds, its a file that contains the details of the Root and Intermediate CA. To combine the certificates together, use the following commands.
[pkiadmin@wrmempki01 ca]$ cp certs/ica.crt certs/ica.chain.crt
[pkiadmin@wrmempki01 ca]$ cat certs/ca.crt >> certs/ica.chain.crt
[pkiadmin@wrmempki01 ca]$ ls -la certs/
total 16
drwxr-xr-x 2 pkiadmin pkiadmin 56 Jan 11 16:10 .
drwxr-xr-x 7 pkiadmin pkiadmin 4096 Jan 11 16:07 ..
-rw-r--r-- 1 pkiadmin pkiadmin 1363 Jan 11 15:36 ca.crt
-rw-r--r-- 1 pkiadmin pkiadmin 2730 Jan 11 16:10 ica.chain.crt
-rw-r--r-- 1 pkiadmin pkiadmin 1367 Jan 11 16:07 ica.crt
Doing this creates a chain in the following format
-----BEGIN CERTIFICATE-----
ICA Cert
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
CA Cert
-----END CERTIFICATE-----
With all certificates created, you now need to copy the ica.crt and ica.chain.crt file back to your ICA server (Or ICA folder if you're using one server).
scp certs/ica.crt pkiadmin@pki02:/home/pkiadmin/ica/certs/
scp certs/ica.chain.crt pkiadmin@pki02:/home/pkiadmin/ica/certs/
You now have a fully functioning ICA server and you can turn off/disconnect the network to your Root CA server.
Create a CRL
The last step is to create a CRL file. A CRL is used to ensure that certificates that have expired or that you have revoked, are not accepted when authenticating. This is done on the ICA server (And the CA server to ensure that ICA certificates are accurate) but for now, I'm only going to show you the ICA configuration. The first step is to SSH into your ICA server using your pkiadmin user, and creating a crlnumber file that contains a random value. I've started at 1000.
[pkiadmin@wrmempki02 ica]$ cd /home/pkiadmin/ica
[pkiadmin@wrmempki02 ica]$ echo 1000 > crlnumber
Now you need to create the CRL certificate. To do that use the following openssl ca command.
[pkiadmin@wrmempki02 ica]$ sudo openssl ca -config openssl.cnf -gencrl -out crl/ica.crl.pem
[sudo] password for pkiadmin:
Using configuration from openssl.cnf
Enter pass phrase for /home/pkiadmin/ica/private/ica.key:
[pkiadmin@wrmempki02 ica]$
With the CRL certificate created, in order to publish it, you will need a webserver and a FQDN for the crl file. I have created a DNS entry for crl.wr-mem.net and copied my crl.pem file to the web server. The next step is to edit your openssl.cnf configuration file to include the crlDistributionPoints and the specific crl url.
crlDistributionPoints = URI:http://crl.wr-mem.net/ica.crl.pem
Now copy the ica.crl.pem file to your webserver crl directory and you're done. That's it for this blog. I'll post another one in the future that outlines some of the steps for managing certificates etc.
Add new comment