Home RSS icon My CV icon

Generating A Self-Signed Certificate Using CFSSL
How to Use Cloudflare's Toolkit for SSL

In my homelab, which serves both as a learning environment and as a platform for developing Proof of Concepts (POCs) for work, I frequently need to manage a variety of services. This requires the issuance of multiple SSL certificates.

Previously, I relied on OpenSSL for generating a Certificate Authority (CA), which I then used to issue certificates for my services

Altought I love openssl, I find its usage to be notably cumbersome.

To streamline the process, I created a Bash script that could read a configuration-like file, but this script kept growing and changing and sometimes fail according to the new situations that I find myself in during the learning process.

Recently, I had the opportunity to explore cfssl toolkit from Cloudflare and I must say, it's quite impressive.

it's significatly simplified the process of managing my SSL certificates.

1 Generating our Certificate authority

To get started with cfssl, we need to generate some configuration files. These are files contain all the necessary information we need for our Certificate Authority (CA)

First, The certificate signing request, we will keep it simple.

This file will be used to generate the CA certificate itself. Here I specified cryptographic algorithm used for our CA and additional metadata.

cat ca-csr.json
{
  "CN": "Homelab CA",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "DZ",
      "ST": "Algiers",
      "L": "Kouba",
      "O": "Homelab",
      "OU": "Homelab Root CA"
    }
  ]
}

Next, let's create another configuration file, we will use this configuratoin files when we try to generate our hosts certificates. This file include default settings, such as the CA's validity period, and various profiles to the specific server types for which we're issuing certificates.

cat config.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "server": {
        "usages": ["signing", "key encipherment", "digital signature", "server auth"],
        "expiry": "8760h"
      },
      "client": {
        "usages": ["signing", "digital signature", "client auth"],
        "expiry": "8760h"
      }
    }
  }
}

Here I defined two profiles for both my servers and clients instances, and default configuration that sets the expiration of my Certificate Authority to 10 years

Now let's generate our files

cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2024/03/23 12:55:08 [INFO] generating a new CA key and certificate from CSR
2024/03/23 12:55:08 [INFO] generate received request
2024/03/23 12:55:08 [INFO] received CSR
2024/03/23 12:55:08 [INFO] generating key: rsa-2048
2024/03/23 12:55:08 [INFO] encoded CSR
2024/03/23 12:55:08 [INFO] signed certificate with serial number 504812531643523101727480645621690514375630374616

You can use -I to ignore certain files, or a pattern of files from the ls output

ls -lh -I "*.json"
total 24K
-rw-r--r--. 1 admin admin 1017 Mar 23 12:55 ca.csr
-rw-------. 1 admin admin 1.7K Mar 23 12:55 ca-key.pem
-rw-r--r--. 1 admin admin 1.4K Mar 23 12:55 ca.pem

You can use openssl to consult our new generated files

openssl x509 -noout -text -in ca.pem | grep "CA:"
CA:TRUE

2 Hosts certificates

Certificate signing requests are essentially certificates sent to the Certificate Authority (CA) for it to sign and issue a certificate for our instance,
thereby authenticating and securing its identity.

Now, I'm ready to generate my host certificates, which also requires creating certificate signing requests (CSRs) as well.

Below is how I created a certificate for my GitLab instance.

cat git-csr.json
{
  "CN": "git.hl.test",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "DZ",
      "ST": "Algiers",
      "L": "Draria",
      "O": "Homelab",
      "OU": "Homelab Root CA"
    }
  ],
  "hosts": [
    "*.hl.test",
    "git.hl.test",
    "registry.git.hl.test"
  ]
}

Just like before, I specified the necessary information for the instance, with a notable addition which is the hosts section, where we can speicify the targeted hostnames and URLs requiring certificate recognition.

For this example, here I need certificates for two services: the GitLab instance and its container registry.

Now, let's proceed and generate the certificates. This process will produce both the certificate for GitLab and its associated private key.

In this step, I utilize the -profile option to specify the server profile created earlier in the certificate signing request configuration file.
This ensures that the certificate is generated according to the specific requirements and settings defined for server instances.

cfssl gencert -ca ca.pem -ca-key ca-key.pem -config config.json -profile server git-csr.json | cfssljson -bare git 2>&1
2024/03/30 08:02:28 [INFO] generate received request
2024/03/30 08:02:28 [INFO] received CSR
2024/03/30 08:02:28 [INFO] generating key: rsa-2048
2024/03/30 08:02:29 [INFO] encoded CSR
2024/03/30 08:02:29 [INFO] signed certificate with serial number 30822132129223949217507870862884321398589294425
ls -lh git*
-rw-r--r--. 1 admin admin 1.1K Mar 30 08:02 git.csr
-rw-r--r--. 1 admin admin  302 Mar 30 07:58 git-csr.json
-rw-------. 1 admin admin 1.7K Mar 30 08:02 git-key.pem
-rw-r--r--. 1 admin admin 1.5K Mar 30 08:02 git.pem

3 Check the certification

Finally, to confirm the validity and proper relationship between the GitLab certificate and the CA's certificate, we use the following OpenSSL command:

openssl verify -CAfile ca.pem git.pem
git.pem: OK

This indicates that the GitLab certificate has been correctly signed by our CA, establishing a trustworthy connection based on the CA's authority.

Creative Commons License

Copyright © 2023 Zakaria Kebairia
Content licensed CC-BY-SA 4.0 unless otherwise noted.