You can support us by downloading this article as PDF from the Link below. Download the guide as PDF

CloudFlare’s PKI/TLS toolkit

Adapted from CFSSL GitHub page, CFSSL is CloudFlare’s open source PKI/TLS swiss army knife. It is both a command line tool and an HTTP API server for signing, verifying, and bundling TLS certificates. Getting the correct bundle together is a black art, and can quickly become a debugging nightmare if it’s not done correctly. CloudFlare wrote CFSSL to make bundling easier. By picking the right chain of certificates, CFSSL solves the balancing act between performance, security, and compatibility.

CFSSL Public Key Infrastructure is not only a tool for bundling a certificate, but it can also be used as a CA. This is possible because it covers the basic features of certificate creation including creating a private key, building a certificate signature request, and signing certificates.

A brief explanation of SSL Certificates and TLS

It is widely known that the internet is a very unsafe place to be and every url you click or every site you visit does not necessarily guarantee that it is what it sells. Due to the nature of unsafe websites in the massive world wide web, SSL Certificates have come into play to mitigate some of these security concerns. SSL certificates bind domain names to server names, and company names to locations thus forming the core of trust on the web by assuring the identity of websites. In other words, the certificate contains the server name, the trusted certificate authority (CA) that vouches for the authenticity of the certificate, and the server’s public encryption key.

If you are running a company and you would wish to offer services online, the only way people out there will verify the identity of your domain name is through the SSL Certificates you will be issued with by trusted Certificate Authorities such as GlobalSign and DigiCert. SSL Certificates work hand in hand with Transport Layer Security (TLS). Without an SSL certificate, a website’s traffic cannot be encrypted with TLS. TLS ensures that connections between a client (a browser) and a server ( for example your webserver) is:

  • Private (or secure) because symmetric cryptography is used to encrypt the data transmitted
  • Reliable because each message transmitted includes a message integrity check to prevent undetected loss or alteration of the data during transmission
  • Known because the server usually then provides identification from its SSL Certificate (contains the server name, the trusted certificate authority (CA) and the server’s public encryption key).

It should be known that anyone can create a certificate (self-signed certificates), but browsers only trust certificates that come from an organization on their list of trusted CAs. A certificate authority or certification authority (CA) is an entity that has undergone rigorous security audits and is therefore allowed to issue trusted digital certificates which in turn confirm that the website owner is who they say they are. A certificate that is issued by a CA to itself is referred to as a trusted root certificate because it is intended to establish a point of ultimate trust for a CA hierarchy.

In most cases, you will not be issued with a certificate directly from the root CA but from intermediate CAs. An intermediate CA certificate is a subordinate certificate issued by the trusted root specifically to issue end-entity server certificates. The result is a trust-chain that begins at the trusted root CA, through the intermediate and finally ending with the SSL certificate issued to you. The usage of an intermediate certificate thus provides an added level of security as the CA does not need to issue certificates directly from the CA root certificate. Source:Digicert KB.

Now that we are not that bad about SSL Certificates, TLS, and Certificate Authority, it is a good time to explore this CFSSL tool we have at hand.

CFSSL consists of:

  • A set of packages useful for building custom TLS PKI tools
  • The cfssl program, which is the canonical command line utility using the CFSSL packages.
  • The multirootca program, which is a certificate authority server that can use multiple signing keys.
  • The mkbundle program is used to build certificate pool bundles.
  • The cfssljson program, which takes the JSON output from the cfssl and multirootca programs and writes certificates, keys, CSRs, and bundles to disk.

Installing CFSSL on Linux

Am on Ubuntu 20.04 in this installation process. Installation of cfssl and other tools (mkbundle, cfssljson, multirootca) requires a working Go 1.12+ installation if you’re building them from source.

Getting Go installed

Before anything, prepare your Server, I am on Ubuntu 20.04, update and get gcc installed as shown below.

sudo apt update

Install the build-essential package

sudo apt install build-essential

The command above command installs new packages including gcc, g++ and make.

To install Go in CentOS, Ubuntu and Linux Mint follow the link below then proceed with the installation of cfssl.

Install Go (Golang) on Ubuntu / CentOS

The command below will download, build, and install all of the utility programs (including cfssl, cfssljson, and mkbundle among others).

go get -u github.com/cloudflare/cfssl/cmd/...

The binary packages will be available in your Go home directory:

$ ls ~/go/bin/
cfssl  cfssl-bundle  cfssl-certinfo  cfssljson  cfssl-newkey  cfssl-scan  mkbundle  multirootca

Note that if you only need to install cfssl alone, simply run

go get -u github.com/cloudflare/cfssl/cmd/cfssl

How To Use CFSSL

Now that cfssl is installed, we can proceed to use it in our environment.

Initialize a certificate authority (CA)

We re going to initialize a Root CA for our environment. First of all we have to save default cfssl options for future substitutions and usage.

mkdir ~/cfssl
cd ~/cfssl
cfssl print-defaults config > ca-config.json
cfssl print-defaults csr > ca-csr.json

Edit the files generated to fit your environment

$ vim ca-csr.json

{
    "CN": "Computingforgeeks CA",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "KE",
            "ST": "NB",
            "L": "Kenya",
            "O": "Computingforgeeks",
            "OU": "IT"
        }
    ]
}

I intend to create intermediate certificates and thus added it among the profiles in the configuration file below which we shall use in subsequent steps to create the respective profiles. You will note that the intermediate_ca profile has capabilities(usages) such as signing, client authentication, server authentication, certificate signing, key encipherment and more which is good for our intermediate CA to have.

$ vim ca-config.json

{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "intermediate_ca": {
        "usages": [
            "signing",
            "digital signature",
            "key encipherment",
            "cert sign",
            "crl sign",
            "server auth",
            "client auth"
        ],
        "expiry": "8760h",
        "ca_constraint": {
            "is_ca": true,
            "max_path_len": 0, 
            "max_path_len_zero": true
        }
      },
      "peer": {
        "usages": [
            "signing",
            "digital signature",
            "key encipherment", 
            "client auth",
            "server auth"
        ],
        "expiry": "8760h"
      },
      "server": {
        "usages": [
          "signing",
          "digital signing",
          "key encipherment",
          "server auth"
        ],
        "expiry": "8760h"
      },
      "client": {
        "usages": [
          "signing",
          "digital signature",
          "key encipherment", 
          "client auth"
        ],
        "expiry": "8760h"
      }
    }
  }
}

Generate CA with the specified options

$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

 [INFO] generating a new CA key and certificate from CSR
 [INFO] generate received request
 [INFO] received CSR
 [INFO] generating key: rsa-2048
 [INFO] encoded CSR
 [INFO] signed certificate with serial number 575514558967771581279537545623874943296973655847

The files below will be generated in the directory you ran the command in. It comprises of the root CA public key (ca.pem), private key(ca-key.pem), and certificate signing request (ca.csr). You should keep the private key as safely as possible.

  • ca-key.pem
  • ca.csr
  • ca.pem

Now we have our root CA which is the most important file. The root CA will allow us to generate intermediate certificates. Intermediate certificates can be used just like the CA to generate other intermediate certificates or to directly sign certificates and keys.

We are going to create an intermediate CA. First, let us create a new directory that will hold our intermediate files:

$ mkdir ~/cfssl/intermediate && cd ~/cfssl/intermediate
$ nano intermediate.json

{
  "CN": "Computingforgeeks Servers Intermediate CA",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C":  "KE",
      "L":  "Nairobi",
      "O":  "Geeks Servers",
      "OU": "Servers Intermediate CA",
      "ST": "Kileleshwa"
    }
  ],
  "ca": {
    "expiry": "42720h"
  }
}

After the config file has been created, let us create our intermediate public and private keys together with the intermediate signing request.

$ cfssl gencert -initca intermediate.json | cfssljson -bare intermediate_ca

 [INFO] generating a new CA key and certificate from CSR
 [INFO] generate received request
 [INFO] received CSR
 [INFO] generating key: rsa-2048
 [INFO] encoded CSR
 [INFO] signed certificate with serial number 49317059847143524717036065772346603828701272228


$ cfssl sign -ca ~/cfssl/ca.pem \
  -ca-key ~/cfssl/ca-key.pem \
  -config ~/cfssl/ca-config.json \
  -profile intermediate_ca intermediate_ca.csr | cfssljson -bare intermediate_ca

 [INFO] signed certificate with serial number 557857085402097518963872901169945507335721839653

You will note that we are using ca-config.json file we created earlier which contains the corresponding profiles such as intermediate_ca, peer, server, and client. Also, note that we are using the intermediate_ca profile here. Moreover, we are also using the root public and private keys to sign our intermediate private and public keys. After that, our intermediate CA and keys will be ready to be used. At that juncture, you can encrypt and hide your root CA private key in a very secure place.

Use case for the Certificates

Let us assume you would wish to get a certificate for your web server with a domain name such as computingexample.com. The first thing you should do is generate a Certificate Signing Request (CSR) for your server similar to the one shown below in JSON.

$ nano geekscsr.json

{
  "CN": "server.computingexample.com",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
  {
    "C": "KE",
    "L": "Nairobi",
    "O": "IT Servers",
    "OU": "Computing Webserver1",
    "ST": "Kileleshwa"
  }
  ],
  "hosts": [
    "server1.computingexample.com",
    "localhost"
  ]
}

To generate server certificates with the above config simply do:

$ cfssl gencert -ca intermediate_ca.pem -ca-key intermediate_ca-key.pem -config ~/cfssl/ca-config.json -profile=server geekscsr.json | cfssljson -bare web-server1

 [INFO] generate received request
 [INFO] received CSR
 [INFO] generating key: rsa-2048 
 [INFO] encoded CSR
 [INFO] signed certificate with serial number 548472281222429688545698573045498525083615863345

Make sure intermediate_ca.pem geekscsr.json and intermediate_ca-key.pem files are in the directory you are running the command in.

The command above will produce the following certificate files:

  • web-server1.csr
  • web-server1-key.pem
  • web-server1.pem

Bundling Certificates

mkbundle is used to build the root and intermediate bundles used in verifying certificates. It basically chains the end certificate with the intermediate CA and Root CA public keys. If you had decided not to install everything in the beginning, mkbundle can be installed with:

go get -u github.com/cloudflare/cfssl/cmd/mkbundle

It takes a collection of certificates, checks for CRL revocation (OCSP support is planned for the next release) and expired certificates, and bundles them into one file. It takes directories of certificates and certificate files (which may contain multiple certificates). For example, if the directory intermediates contain a number of intermediate certificates, run:

mkbundle -f bundle.crt intermediates

In order to bundle our certificates, ensure that the Root CA public key (ca.pem) and the intermediate public keys are in the same directory. All of mine will be copied into the intermediate directory. Let us follow the convention above to bundle our generated certificates.

##Copy Root CA Public and Intermediate CA public keys into the intermediate directory
$ cp ~/cfssl/ca.pem ~/cfssl/intermediate
$ cd ~/cfssl
$ mkbundle -f web-server1.crt intermediate

 [INFO] Found intermediate
 [INFO] Found intermediate/ca.pem
 [INFO] Loading intermediate/ca.pem
 [INFO] Validating CN=Computingforgeeks CA,OU=IT,O=Computingforgeeks,L=Kenya,ST=NB,C=KE
 [INFO] Found intermediate/intermediate_ca-key.pem
 [INFO] Loading intermediate/intermediate.json
 Loading intermediate/intermediate_ca-key.pem
 Skipping non-certificate
 [INFO] Found intermediate/intermediate_ca.csr
 [INFO] Found intermediate/intermediate_ca.pem
 [INFO] Loading intermediate/intermediate_ca.csr
 [INFO] Skipping non-certificate
 [INFO] Loading intermediate/intermediate_ca.pem
 [INFO] Validating CN=Computingforgeeks Servers Intermediate CA,OU=Servers Intermediate CA,O=Geeks Servers,L=Nairobi,ST=Kileleshwa,C=KE
 [INFO] Found intermediate/web-server1-key.pem
 [INFO] Found intermediate/web-server1.csr
 [INFO] Found intermediate/web-server1.pem
 [INFO] Loading intermediate/web-server1-key.pem
 [INFO] Skipping non-certificate
 [INFO] Loading intermediate/web-server1.csr
 [INFO] Skipping non-certificate
 [INFO] Loading intermediate/web-server1.pem
 [INFO] Validating CN=server.computingexample.com,OU=Computing Webserver1,O=IT Servers,L=Nairobi,ST=Kileleshwa,C=KE
 [INFO] Wrote 3 certificates.

The command above will generate web-server1.crt file in the directory we are currently at. We can now copy our certificates and bundle to known certificate directories in our server.

cd ~/cfssl/
sudo cp web-server1.crt /etc/ssl/certs/
cd ~/cfssl/intermediate
sudo cp web-server1-key.pem web-server1.pem /etc/ssl/certs/

Testing our Certificates

To test our generated certificates, let us install Apache and add the certificate paths to its configuration files.

sudo apt install apache2

##Enable ssl

sudo a2enmod ssl

Configure our server with the ssl certificates

Create configuration file.

$ sudo vim /etc/apache2/sites-enabled/server1_computingexample_com.conf

<IfModule mod_ssl.c>
        <VirtualHost _default_:443>
                ServerAdmin [email protected]
                ServerName server1.computingexample.com

                DocumentRoot /var/www/html
                ErrorLog ${APACHE_LOG_DIR}/error.log
                CustomLog ${APACHE_LOG_DIR}/access.log combined
                SSLEngine on

                ## HERE ARE OUR GENERATED CERTS!!
                SSLCertificateFile      /etc/ssl/certs/web-server1.pem  
                SSLCertificateKeyFile /etc/ssl/certs/web-server1-key.pem
                SSLCertificateChainFile /etc/ssl/certs/web-server1.crt
                <FilesMatch "\.(cgi|shtml|phtml|php)$">
                                SSLOptions +StdEnvVars
                </FilesMatch>
                <Directory /usr/lib/cgi-bin>
                                SSLOptions +StdEnvVars
                </Directory>
        </VirtualHost>
</IfModule>

Add sample index.html file in DocumentRoot /var/www/html/

cd /var/www/html/
sudo vim index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="https://ead.sbpt.org.br/?page=<%= BASE_URL %>favicon.ico">
 <style>
  h1 {text-align: center;}
  p {text-align: center;}
  div {text-align: center;}
 </style>
    <title>Test SSL</title>
  </head>
  <body>

    <div id="app"><h2>Our Test Page has Loaded</h2></div>

  </body>
</html>

Restart Apache and check if the page loads using https protocol

sudo systemctl restart apache2

Accessing our webserver

If you have DNS, you can map the FQDN to the IP and load it straight from the browser using its domain name. For me, I will load it using the IP with https protocol

https://IP/

As you can confirm from the screenshot above, the issuer of the certificate is the Intermediate CA we configured earlier in the tutorial and the Root CA is the very first certificate we created. In order for the Root CA certificate to be trusted in your environment, you can add it to Trusted Keys in Windows or in whichever platform you use.

Best courses to learn security:

$14.14
$88.38
in stock
Udemy.com
$14.14
$141.41
in stock
Udemy.com
(76828)
$16.50
$176.76
in stock
Udemy.com

Conclusion

There we have it guys, our PKI using CFSSL is working nicely. You can adapt it and use it to set up a full PKI especially if you are in a Kubernetes cluster. Otherwise, thank you for following through even as you continue to keep safe.

Other Interesting guides:

Setup Docker Container Registry with Podman & Let’s Encrypt SSL

Install Mastodon on Ubuntu 20.04/18.04 With Let’s Encrypt SSL Certificate

How To Install SSL Certificate on IIS Web Server

How To Check SSL Certificate Expiration with OpenSSL

You can support us by downloading this article as PDF from the Link below. Download the guide as PDF