cert-manager is the most used certificate operator for kubernetes. It can issue certificates from several sources, especially from letsencrypt but at this post, I am going to learn you how to use a personal CA certification authority to allow you to generate certificates on your LAB’s.
First we need to install cert-manager on your kubernetes cluster
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager.yaml
Now we are going to verify the cert-manager is running
root@zbox:~# kubectl -n cert-manager get po
NAME READY STATUS RESTARTS AGE
cert-manager-webhook-578954cdd-wwzgg 1/1 Running 0 14d
cert-manager-86548b886-cflh5 1/1 Running 1 14d
cert-manager-cainjector-6d59c8d4f7-lgtv4 1/1 Running 1 14d
Now that cert-manager is running we need to define an issuer, that for this example is going to be a local CA issuer using mkcert, that is a simple zero-config tool to make locally trusted development certificates with any names you’d like.
Download your version at https://github.com/FiloSottile/mkcert/releases and create a directory to allocate your private key and public CA certificate.
mkdir internalCA && cd internalCA
wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1.4.3-linux-amd64
chmod +x mkcert-v1.4.3-linux-amd64
CAROOT=. ./mkcert-v1.4.3-linux-amd64 -install
Now you have the certificate and key of your new CA, also is installed at /usr/local/share/ca-certificates/
so every certificate signed by this CA is trusted by your browsers ( Chrome and Firefox work fine)
root@zbox:/tmp/internalCA# ls -l
total 4700
-rwxr-xr-x 1 root root 4803796 Nov 25 14:17 mkcert-v1.4.3-linux-amd64
-r-------- 1 root root 2484 Dec 26 00:54 rootCA-key.pem
-rw-r--r-- 1 root root 1594 Dec 26 00:54 rootCA.pem
root@zbox:/tmp/internalCA# ls -l /usr/local/share/ca-certificates/
total 4
-rw-r--r-- 1 root root 1594 Dec 26 00:48 mkcert_development_CA_75165785500873602433925991678959123844.crt
At this point your need to upload either the certificate and the key to the cert-manager namespace of your kubernetes as a tls secret, to allow cert-manager the use of it to sign your certificates.
kubectl create secret tls ca-key-pair \
--cert=rootCA.pem \
--key=rootCA-key.pem \
--namespace=cert-manager
Now verify the secret
root@zbox:/tmp/internalCA# kubectl -n cert-manager describe secret ca-key-pair
Name: ca-key-pair
Namespace: cert-manager
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1688 bytes
tls.key: 2488 bytes
Cert-manager works with issuers or ClusterIssuers, one is limited to the namespace where it is created and the other is for the whole cluster, at this case I’m going to use a ClusterIssuer because is more flexible. So write a localCAissuer.yaml file pointing the secretName to the previously created secret. As you can see the ClusterIssuer does not have the namespace metadata.
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: ca-issuer
spec:
ca:
secretName: ca-key-pair
Now verify the new ClusterIssuer with kubectl describe clusterissuers.cert-manager.io ca-issuer
Name: ca-issuer
Namespace:
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: ClusterIssuer
Metadata:
Creation Timestamp: 2020-11-29T19:01:59Z
Generation: 1
Managed Fields:
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
f:conditions:
Manager: controller
Operation: Update
Time: 2020-11-29T19:01:59Z
API Version: cert-manager.io/v1alpha2
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:ca:
.:
f:secretName:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2020-11-29T19:01:59Z
Resource Version: 1072
Self Link: /apis/cert-manager.io/v1/clusterissuers/ca-issuer
UID: 4c8396be-a038-4170-b754-3107cb39425c
Spec:
Ca:
Secret Name: ca-key-pair
Status:
Conditions:
Last Transition Time: 2020-11-29T19:01:59Z
Message: Signing CA verified
Reason: KeyPairVerified
Status: True
Type: Ready
Events: <none>
Now we have our certificate authority working, so is time to create our first certificate, so create a testcert.yaml file with this data:
- kind: Certificate
- namespace: default
- issuer: ClusterIssuer ca-issuer
- dnsNames: vmalaga.192.168.1.222.xip.io
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: test-cert
namespace: default
spec:
secretName: test-cert-tls
issuerRef:
name: ca-issuer
kind: ClusterIssuer
commonName: test.192.168.1.222.xip.io
organization:
- ZBOX CA
dnsNames:
- test.192.168.1.222.xip.io
And apply that to your kubernetes with: kubectl apply -f testcert.yaml
. If every works fine, you can see your certificate.
root@zbox:/tmp/internalCA# kubectl get certificate test-cert
NAME READY SECRET AGE
test-cert True test-cert-tls 6d
Now you can verify the tls secret test-cert-tls
root@zbox:/tmp/internalCA# kubectl describe secret test-cert-tls
Name: test-cert-tls
Namespace: default
Labels: <none>
Annotations: cert-manager.io/alt-names: test.192.168.1.222.xip.io
cert-manager.io/certificate-name: test-cert
cert-manager.io/common-name: test.192.168.1.222.xip.io
cert-manager.io/ip-sans:
cert-manager.io/issuer-group:
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: ca-issuer
cert-manager.io/uri-sans:
Type: kubernetes.io/tls
Data
====
ca.crt: 1688 bytes
tls.crt: 1489 bytes
tls.key: 1679 bytes
As you can see, cert-manager has created a certificate using the CA certificate generated with mkcert and it includes the entire chain, the ca.crt, tls.crt and tls.key
Now you can use this certificate with for example traefik to server SSL valid websites at your local deployment environment.