Cert-Manager - Part 1
Cert-manager automates the management of certificates within Kubernetes. It can be integrated with existing infrastructure like venafi and vault in enterprise and also can be used with Let's Encrypt which provide free certificates. cert-manager is a sandboxproject in CNCF and more details can be found here.
Following are some of the scenario where we can use cert-manager
- To secure the ingress within Kubernetes
- To secure communication within pods with or without service mesh
We can install cert-manager using helm as shown below.
kubectl create namespace cert-manager helm repo add jetstack https://charts.jetstack.io helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.1.0 --set installCRDs=true
We can verify the installation using the command
kubectl get pods --namespace cert-manager
Following are some of the main CRD's created by cert-manager for creating certificate
- Issuer or ClusterIssuer : These are Kubernetes resources that represent CAs which will generate signed certificates as per the certificate signing requests(CSR). The issuer is a namespaced object whereas the ClusterIssuer is a Cluster level object and can be used across all namespaces
- Certificate: This represent the certificate which will be renewed automatically and is a namespaced object which can reference either Issuer or ClusterIssuer
We will look at Let's Encrypt as the CA for issuing certificate. Let's Encrypt uses the ACME protocol to verify that you control a given domain name to issue you a certificate. To verify the domain name, we have to solve the challenges with either the HTTP or the DNS method and more details can be found here.
Let create a certificate using the DNS Challenge resolver. We need to specify the details of the dns zone in the azure subscription as shown below.
apiVersion: cert-manager.io/v1alpha2 kind: Issuer metadata: name: letsencrypt-pod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: [email protected] # Name of a secret used to store the ACME account private key privateKeySecretRef: name: letsencrypt-pod-key # ACME DNS-01 provider configurations solvers: - dns01: azuredns: clientID: clientid clientSecretSecretRef: name: azuredns-config key: client-secret subscriptionID: subid tenantID: tenantid resourceGroupName: sampleapp hostedZoneName: girishgoudar.com environment: AzurePublicCloud
We also need to create a kubernetes secret which can hold the clientsecret of the service principal as shown.
kubectl create secret generic azuredns-config --from-literal=client-secret=clientidsecret
Note: The Service principal or the client Id should have permission as DNS zone contributor and can be given using the below commands
az network dns zone show --name girishgoudar.com --resource-group sampleapp --query "id" --output tsv az role assignment create --assignee clientId --role "DNS Zone Contributor" --scope zoneId
We can then specify the certificate object by referring the issuer, dnsnames and time to renew before expiry and a secret which will have the certificate details as shown.
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: pod-certificate namespace: default spec: renewBefore: 30m secretName: pod-tls subject: organizations: - girishgoudar.com dnsNames: - pod-service.girishgoudar.com issuerRef: name: letsencrypt-pod kind: Issuer
We can verify the certificate by running the command and make sure the ready state is True
kubectl get certificate
Incase the ready state is not True, we can troubleshoot by describing the objects in order starting with certificate,certificaterequest,order and the challenge.
Next, we take a look at creating the certificate using the HTTP Challenge and use it to secure the ingress object in Kubernetes. The Issuer is created for by specifying the HTTP resolver as shown below.
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-nginx spec: acme: server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-nginx-key solvers: - http01: ingress: class: nginx
Create a certificate object by specifying the Issuer, dnsnames and a secret which will have the certificate details as shown.
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: nginx-certificate spec: secretName: secretdemocert commonName: test.girishgoudar.com dnsNames: - test.girishgoudar.com issuerRef: name: letsencrypt-nginx kind: Issuer
Refer the certificate created above in the ingress using the secret and the host as shown below.
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: myingress annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: tls: - hosts: - test.girishgoudar.com secretName: secretdemocert rules: - host: test.girishgoudar.com http: paths: - path: / backend: serviceName: tripviewer servicePort: 80 - path: /api/poi backend: serviceName: poi servicePort: 80 - path: /api/trips backend: serviceName: trips servicePort: 80
In this article, we looked at two ways of creating certificate and securing the ingress. Next we will look at using the certificates created by cert-manager for pod to pod communication in a service mesh.