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
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 throughClusterIssuer
is valid through the cluster -
CertificateRequest
a namespaced resource used to request certificate from
Issuer
. It contains a base-64 encoded CSR sent toIssuer
. 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
andAPIService
. It copies CA data from one of three sources: a KubernetesSecret
, a cert-managerCertificate
, or from the Kubernetes API server CA certificate. Note: If the source is a KubernetesSecret
, that resource MUST also have ancert-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
Top comments (0)