DEV Community 👩‍💻👨‍💻

DEV Community 👩‍💻👨‍💻 is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Cert-manager: automate certificate management on kubernetes
Ashok Nagaraj
Ashok Nagaraj

Posted on

Cert-manager: automate certificate management on kubernetes

Secure HTTP communication is popularly achieved through TLS certificates. These certificates can be to validate the server (https://your-bank.com) or both parties involved in the communication (https://amount-sender.com and https://amount-receiver.com) which is commonly known as Mutual TLS (mTLS). mTLS is not common in web browsers but is used in service-to-service communication models.
To keep things secure, these certificates have a life-time and needs renewal upon expiry

In kubernetes for example kublet authenticates with kube-api-server through mTLS. The certificates come from within kubernetes control plane itself and a new one is issued for every new node that joins. For it's internal purposes there is a CertificateSigningRequest object provided, but it is not flexible enough to be used by workloads themselves.

Cert-manager

Cert-manager is a general purpose x509 certificate management tool for Kubernetes.

  • It can be used as a standard Certificate Authority (CA).
  • It can also work with other well known CAs like Hashicorp Vault and LetsEncrypt.
  • It can generate self-signed certificates
  • It can inject certificates into workloads automatically through annotations
  • It can handle certificate rotation
Installation
❯ helm repo add jetstack https://charts.jetstack.io
"jetstack" has been added to your repositories
❯ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "jetstack" chart repository
Update Complete. ⎈Happy Helming!⎈
❯ helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.9.1 \
  --set installCRDs=true
NAME: cert-manager
LAST DEPLOYED: Mon Sep 19 08:45:10 2022
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.9.1 has been deployed successfully!
...

❯ kubectl get all -n cert-manager
NAME                                           READY   STATUS    RESTARTS   AGE
pod/cert-manager-85f68f95f-k9f6q               1/1     Running   0          2m19s
pod/cert-manager-cainjector-7d9668978d-lrtgn   1/1     Running   0          2m19s
pod/cert-manager-webhook-66c8f6c75-hq7lj       1/1     Running   0          2m19s

NAME                           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/cert-manager           ClusterIP   10.96.27.186   <none>        9402/TCP   2m19s
service/cert-manager-webhook   ClusterIP   10.96.27.27    <none>        443/TCP    2m19s

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cert-manager              1/1     1            1           2m19s
deployment.apps/cert-manager-cainjector   1/1     1            1           2m19s
deployment.apps/cert-manager-webhook      1/1     1            1           2m19s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/cert-manager-85f68f95f               1         1         1       2m19s
replicaset.apps/cert-manager-cainjector-7d9668978d   1         1         1       2m19s
replicaset.apps/cert-manager-webhook-66c8f6c75       1         1         1       2m19s
Enter fullscreen mode Exit fullscreen mode
Concepts
  • Issuer Objects representing CAs that generate certificates as requested through Certificate Signing Requests (CSRs). It is a namespace scoped resource - can issue certifcates valid in the operating namespace scope
  • ClusterIssuer Issuer with cluster scope - can issue certificate valid throughout the cluster
  • Certificate an object defining a X.509 certificate. This certificate is issued, kept up-to-date through renewal with cert-manager. A certificate issued through Issuer is namespace scoped, while the one issued through ClusterIssuer is valid through the cluster
  • CertificateRequest a namespaced resource used to request certificate from Issuer. It contains a base-64 encoded CSR sent to Issuer. Upon success, it will return a valid, signed certificate based on the CSR more info

cert-manager supports requesting certificates from ACME servers, including from Let's Encrypt, with use of the ACME Issuer. These certificates are typically trusted on the public Internet by most computers. To successfully request a certificate, cert-manager must solve ACME Challenges which are completed in order to prove that the client owns the DNS addresses that are being requested.

  • Order are resources used by the ACME issuer to manage the lifecycle of an ACME 'order' for a signed TLS certificate. It represents a single CSR.
  • Challenge are resources are used by the ACME issuer to manage the lifecycle of an ACME 'challenge' that must be completed in order to complete an 'authorization' for a single DNS name/identifier. It is created and managed by the challenge-controller more info
  • cainjector helps fetch CA certificates for webhooks and other API services. It populates the caBundle field of four API types: ValidatingWebhookConfiguration, MutatingWebhookConfiguration CustomResourceDefinition and APIService. It copies CA data from one of three sources: a Kubernetes Secret, a cert-manager Certificate, or from the Kubernetes API server CA certificate. Note: If the source is a Kubernetes Secret, that resource MUST also have an cert-manager.io/allow-direct-injection: "true" annotation.
Example with a self-signed certificate
# assumption: cert-manager is installed and configured as described above

# Prepare a namespace
❯ kubectl create ns demo-ns
namespace/demo-ns created

# Prepare an issuer
❯ cat issuer.yaml
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: selfsigned-issuer
  namespace: demo-ns
spec:
  selfSigned: {}

# Create
❯ kubectl create -f issuer.yaml
issuer.cert-manager.io/selfsigned-issuer created

# Verify
❯ kubectl get issuers.cert-manager.io -n demo-ns
NAME                READY   AGE
selfsigned-issuer   True    17s

# Create a Certificate object
❯ cat certificate.yaml
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: sample-certificate
  namespace: demo-ns
spec:
  secretName: sample-certificate
  dnsNames:
  - sample.demo-ns
  issuerRef:
    name: selfsigned-issuer

# Request for certificate
❯ kubectl create -f certificate.yaml
certificate.cert-manager.io/sample-certificate created

# Verify 
❯ kubectl get certificate -n demo-ns
NAME                 READY   SECRET               AGE
sample-certificate   True    sample-certificate   10s

# Describe the secret
❯ kubectl get secrets/sample-certificate -n demo-ns -o yaml | cut -c -80
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lRWjFCcU
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lRWjFCc
  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNEdQT
kind: Secret
metadata:
  annotations:
    cert-manager.io/alt-names: sample.demo-ns
    cert-manager.io/certificate-name: sample-certificate
    cert-manager.io/common-name: ""
    cert-manager.io/ip-sans: ""
    cert-manager.io/issuer-group: ""
    cert-manager.io/issuer-kind: Issuer
    cert-manager.io/issuer-name: selfsigned-issuer
    cert-manager.io/uri-sans: ""
  name: sample-certificate
  namespace: demo-ns
type: kubernetes.io/tls

# Inject secret to a validation webhook
❯ cat val-webhook.yaml
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: test-webhook
  annotations:
    cert-manager.io/inject-ca-from-secret: demo-ns/sample-certificate
webhooks:
- name: test-webhook.example.com
  admissionReviewVersions:
  - v1
  clientConfig:
    service:
      name: test-webhook
      namespace: demo-ns
      path: /validate
      port: 443
  sideEffects: None

# Instantiate assuming test-webhook is a valid service in demo-ns pointing to port 443 to validate on /validate route
❯ kubectl create -f val-webhook.yaml
validatingwebhookconfiguration.admissionregistration.k8s.io/test-webhook created

# Verify 
❯ kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io
NAME                   WEBHOOKS   AGE
cert-manager-webhook   1          137m
test-webhook           1          6s

Enter fullscreen mode Exit fullscreen mode

Top comments (0)

🌚 Browsing with dark mode makes you a better developer.

It's a scientific fact.