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.
Prerequisites
- A Kubernetes cluster (you can create it by using minikube)
- kubectl command-line tool installed
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
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
Step 2: Create a Certificate Issuer
Create a namespace where you will generate certificates:
kubectl create namespace [namespace]
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:
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:
To check the certificate you created, type:
kubectl -n [namespace] get certificate
To view information about the Secret, use the get secret
command:
kubectl -n [namespace] get secret [secret-name]
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
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 usesjson
outputs fromcfssl
andmultirootca
.
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
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 authorityalgo
– the algorithm used for the certificatessize
– algorithm size in bitsC
– CountryL
– Locality (city)ST
– State or provinceO
– OrganizationOU
– 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
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.json
should 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
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
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
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
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
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
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
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
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
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:
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
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
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:
To view the certificate you created, type:
openssl x509 -noout -text -in ./server.crt
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.