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.