How to Generate a Self-Signed Certificate for Kubernetes

Introduction

In 2020, Google Chrome changed the behavior of SameSite=None cookies to require activation of the Secure option. As a result, testing a Web UI client whose API backend runs in a local Kubernetes cluster now requires HTTPS access.

In this tutorial, you will learn how to obtain HTTPS access by generating a self-signed certificate for Kubernetes using cert-manager, CFSSL, Easy-RSA, and OpenSSL methods.

How to Generate a Self-Signed Certificate for Kubernetes

Prerequisites

Generating Certificates via cert-manager

As the native Kubernetes certificate management controller, the cert-manager add-on is the most common way to generate self-signed certificates.

Step 1: Install cert-manager

To install cert-manager, first create a namespace for it:

kubectl create namespace cert-manager
Creating a namespace for cert-manager using kubectl

Next, use the kubectl apply command and the yaml file available online to install the add-on:

kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.13.1/cert-manager.yaml
Installing cert-manager using the kubectl apply command and the yaml file

Step 2: Create a Certificate Issuer

Create a namespace where you will generate certificates:

kubectl create namespace [namespace]
Creating a namespace for certificate management

Next, define a certificate issuer by typing the following multi-line command into the terminal:

kubectl apply -n [namespace] -f <(echo "
apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: [issuer-name]
spec:
  selfSigned: {}
")

The output confirms the successful issuer creation:

Confirming the successful creation of the certificate issuer using the kubectl command

An issuer created in this way works only for the current namespace. If you want to be able to request certificates from any namespace in a cluster, create a custom Kubernetes resource called ClusterIssuer using the available selfsigned-issuer.yaml file:

kubectl apply -f https://gist.githubusercontent.com/t83714/51440e2ed212991655959f45d8d037cc/raw/7b16949f95e2dd61e522e247749d77bc697fd63c/selfsigned-issuer.yaml

Step 3: Generate a Certificate

Generate a self-signed certificate by typing the following multi-line command into the terminal:

kubectl apply -n [namespace]-f <(echo '
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: [certificate-name]
spec:
  secretName: [secret-name]
  dnsNames:
  - "*.[namespace].svc.cluster.local"
  - "*.[namespace]"
  issuerRef:
    name: [issuer-name]
')

The output confirms the creation was successful:

Generating a self-signed certificate with a kubectl command using cert-manager

To check the certificate you created, type:

kubectl -n [namespace] get certificate
Checking the certificate made in cert-manager using kubectl

To view information about the Secret, use the get secret command:

kubectl -n [namespace] get secret [secret-name]
Using kubectl to view information about the secret

The three keys contained in this secret are ca.crt, tls.crt, and tls.key. For the entire Secret, type:

kubectl -n [namespace] get secret [secret-name] -o yaml

Note: Learn more about Kubernetes secrets, object storing sensitive pieces of data.

Step 4: Test the Certificate

Use the following command to test the validity of the certificate:

openssl x509 -in <(kubectl -n [namespace] get secret \
  first-tls -o jsonpath='{.data.tls\.crt}' | base64 -d) \
  -text -noout
Testing the certificate created with cert-manager

The X509v3 Subject Alternative Name line should contain the dnsNames you provided during the certificate generation.

Generating Certificates via CFSSL

Another common tool for generating and verifying self-signed certificates is CFSSL. The tool consists of four programs:

  • cfssl – a command-line utility for CFSSL package management.
  • multirootca – a certificate authority server.
  • mkbundle – a certificate pool bundle builder.
  • cfssljson – a certificate generator that uses json outputs from cfssl and multirootca.

The steps below show how to generate a self-signed certificate using CFSSL.

Step 1: Install CFSSL using Go

To install CFSSL, first, you need to install the necessary Go language packages. Type the following command:

sudo apt install golang
Installing the Go language packages using apt

Then, use the Go syntax to download cfssl:

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

Next, copy the file from ~/go/bin to the appropriate folder:

sudo cp ~/go/bin/cfssl /usr/local/bin/cfssl

Finally, repeat the process with cfssljson:

go get -u github.com/cloudflare/cfssl/cmd/cfssljson
sudo cp ~/go/bin/cfssljson /usr/local/bin/cfssljson

Step 2: Create a Certificate Authority

After you install the programs, proceed with creating a self-signed certificate authority (CA). The example below creates a file named ca.json.

The file defines the following:

  • CN – Common name for the authority
  • algo – the algorithm used for the certificates
  • size – algorithm size in bits
  • C – Country
  • L – Locality (city)
  • ST – State or province
  • O – Organization
  • OU – Organizational Unit

The example below is for the organization called “Example Company” and its organizational unit “Example Company Root CA” based in New York, NY, United States.

{
  "CN": "Example Company Root CA",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
  {
    "C": "US",
    "L": "New York",
    "ST": "New York",
    "O": "Example Company",
    "OU": "Example Company Root CA"
  }
 ]
}

Create and save the json file in a text editor. Then, use it to generate the ca.pem and ca-key.pem files by typing the following cfssl command:

cfssl gencert -initca ca.json | cfssljson -bare ca
Generating necessary certificate files using a cfssl command

Step 3: Create the Configuration File

To proceed, create the cfssl.json configuration file. The file provides details about the certificate’s expiration date and usage for separate profiles (peer, server, and client).

cfssl.jsonshould look like this:

{
  "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"
      }
    }
  }
}

Save the file and exit.

Step 4: Create an Intermediate Certificate Authority

Another json file you must create is intermediate-ca.json. It defines the intermediate certificate authority and looks similar to the previously created ca.json:

{
  "CN": " Example Company Intermediate CA",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "New York",
      "ST": "New York",
      "O": "Example Company",
      "OU": "Example Company Intermediate CA"
    }
  ],
  "ca": {
    "expiry": "42720h"
  }
}

Step 5: Sign the Certificate

After creating both files, type the following command to create the intermediate_ca.pem, intermediate_ca.csr and intermediate_ca-key.pem files, and sign the intermediate CA:

cfssl gencert -initca intermediate-ca.json | cfssljson -bare intermediate_ca
Creating the necessary files and signing the intermediate CA using cfssl

Then, sign the certificate using the CA and the cfssl.json configuration file:

cfssl sign -ca ca.pem -ca-key ca-key.pem -config cfssl.json -profile intermediate_ca intermediate_ca.csr | cfssljson -bare intermediate_ca
Signing the certificate using cfssl

Step 6: Generate Host Certificates

To generate host certificates for peer, server, and client profiles, create the host1.json file with the necessary information about the hosts.

{
  "CN": "host.example-company.com",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "New York",
      "O": "Example Company",
      "OU": "Example Company Intermediate CA",
      "ST": "New York"
    }

  ],
  "hosts": [
    "host1.example-company.com",
    "localhost"
  ]
}

Note: Different servers and clients may require different variations of the json file used above. Some require only the common name (CN) and do not check the hosts section. Others need the IP address to be stated in the hosts section.

Now, generate the certificates using the configuration file you created. For the peer certificate that allows communication between servers, type:

cfssl gencert -ca intermediate_ca.pem -ca-key intermediate_ca-key.pem -config cfssl.json -profile=peer host1.json | cfssljson -bare host-1-peer
Generating a host certificate for peers using cfssl

To generate a server certificate, type:

cfssl gencert -ca intermediate_ca.pem -ca-key intermediate_ca-key.pem -config cfssl.json -profile=server host1.json | cfssljson -bare host-1-server
Generating a host certificate for servers using cfssl

The syntax for a client certificate, which is not often required but is supported by some systems, is:

cfssl gencert -ca intermediate_ca.pem -ca-key intermediate_ca-key.pem -config cfssl.json -profile=client host1.json | cfssljson -bare host-1-client
Generating a host certificate for client using cfssl

The respective outputs confirm the successful generation of the certificates.

Generating Certificates via Easy-RSA

Easy-RSA is a popular utility for creating root certificate authorities, requesting and signing certificates.

Step 1: Install Easy-RSA

To download Easy-RSA packages, you need curl. If you do not have curl installed, install it by typing:

sudo apt install curl

Now, type the following curl command:

Curl -LO https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
Installing Easy-RSA using curl

Unpack the archive you downloaded:

tar xzf easy-rsa.tar.gz

Go to the easy-rsa-3.0.1/easyrsa3 directory:

cd easy-rsa-master/easyrsa3

Once you are in the folder, type the following command to finish setting up Easy-RSA:

./easyrsa init-pki
Unpacking the archive and initializing Easy-RSA

Note: Curl is a useful tool to ignore certificate errors in development. Learn how to make curl ignore SSL errors.

Step 2: Create a Self-Signed CA

To initiate the creation of a self-signed CA, use this command:

./easyrsa build-ca
Initiating the creation of a self-signed CA using Easy-RSA

The system asks you to type a PEM passphrase for encrypting the ca.key file. Next, the prompt requires you to enter information about the CA you are creating.

Note: The system may ask you for more details than you see in the screenshot above. If you are asked about the organizational unit (OU), make sure to replace the default value (IT) with ROOT-CA.

Step 3: Generate Server Certificate and Key

The next step is to generate a server certificate and key using a multi-line command shown below. The --subject-alt-name option sets the IP addresses and DNS names for accessing the API server.

The --days option controls the length of the certificate validity.

cluster.local is the default DNS domain name.

./easyrsa --subject-alt-name="IP:[master-IP-address]," \
"IP:[master-cluster-IP-address]," \
"DNS:kubernetes," \
"DNS:kubernetes.default," \
"DNS:kubernetes.default.svc," \
"DNS:kubernetes.default.svc.cluster," \
"DNS:kubernetes.default.svc.cluster.local" \ 
--days=10000 \
build-server-full server nopass
Generating server certificate and key using Easy-RSA

The system asks you to repeat the passphrase you created in the previous step. Then, the output confirms the database was updated with a new entry. Copy the pki/ca.crt, pki/issued/server.crt and pki/private/server.key files to your directory.

Generating Certificates via OpenSSL

OpenSSL allows you to generate TLS certificates manually. The following steps show how to use OpenSSL to generate keys and certificates for your cluster.

Step 1: Install OpenSSL

The OpenSSL tool is commonly pre-installed on Linux systems. Check if you have it installed by typing:

openssl version -a

The output looks like this:

Checking the OpenSSL version installed on the system

If you get a message saying you do not have OpenSSL on your system, install the tool with your distribution’s package manager.

For example:

sudo apt install openssl

Step 2: Generate the Certificate Files

Use the following command to produce a 2048-bit RSA encrypted key for certificate signing:

openssl genrsa -out ca.key 2048
Generating an encrypted key for certificate signing using OpenSSL

Now, use the ca.key to generate ca.crt. Use the -days option to set the length of the certificate validity:

openssl req -x509 -new -nodes -key ca.key -subj "/CN=[master-ip-address]" -days [number] -out ca.crt

If no errors occurr, the command produces no output.

Finally, generate the server.key file with 2048-bit RSA encryption:

openssl genrsa -out server.key 2048
Generating an encrypted server key for certificate signing using OpenSSL

Step 3: Create the Certificate Configuration File

Create a csr.conf configuration file for generating a Certificate Signing Request (CSR). The example file below also assumes that you are using cluster.local as the default DNS domain name.

[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = [country]
ST = [state]
L = [city]
O = [company]
OU = [organization-unit]
CN = [common-name]

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
IP.1 = [MASTER_IP]
IP.2 = [MASTER_CLUSTER_IP]

[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names

Make sure you replace the explanations in the square brackets with the actual values. Save the file and use it to generate a certificate signing request:

openssl req -new -key server.key -out server.csr -config csr.conf

The command produces no output, but it creates the server.csr file.

Step 4: Generate the Certificate

Use the file you generated in the previous step together with ca.key and ca.crt to create a server certificate:

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 10000 \
-extensions v3_ext -extfile csr.conf

The output of this multi-line command confirms the creation of the certificate and lists the data you from the configuration file:

Generating a certificate in OpenSSL

To view the certificate you created, type:

openssl x509 -noout -text -in ./server.crt
Viewing the certificate created with OpenSSL

Conclusion

The article listed the steps necessary to generate self-signed certificates for Kubernetes using four methods: cert-manager, CFSSL, Easy-RSA, and OpenSSL.

While the self-signed certificates should not be used in production, they provide an easy way to test the Web UI apps you deploy with Kubernetes.

Was this article helpful?
YesNo
Marko Aleksic
Marko Aleksić is a Technical Writer at phoenixNAP. His innate curiosity regarding all things IT, combined with over a decade long background in writing, teaching and working in IT-related fields, led him to technical writing, where he has an opportunity to employ his skills and make technology less daunting to everyone.
Next you should read
List of kubectl Commands with Examples
December 24, 2020

The Kubernetes command-line tool, kubectl, allows you to control Kubernetes by carrying out HTTP requests to...
Read more
How to do Canary Deployments on Kubernetes
December 1, 2020

A canary deployment is used to test out new features and upgrades, to see how they handle...
Read more
19 Kubernetes Best Practices for Building Efficient Clusters
September 23, 2020

Kubernetes is a feature-rich orchestration tool. The best practices outlined in this article are going to...
Read more
Ultimate Guide to Types of SSL Certificates
August 20, 2020

While they all encrypt data, not all SSL certificates provide the same features to their users. Learn about...
Read more