If you are working with Kubernetes probably did you faced the situation when you need to use SSL certificates for your ingress domains. Here we take a look at how we can do it for free and automatically.
First of all, we have to install some tools locally:
- Helm 3 - for managing dependencies on your Kubernetes cluster.
- Kubernetes cluster - if you don't have an own cluster I advise you to take a look at my previous post "How to create your own cluster for development?"
- Kubectl - for managing your cluster.
I recommend to create independent Kubernetes namespace where will be running certificate manager:
kubectl create namespace cert-manager
Next, via HELM we will install the tool which is responsible for managing certificates. Let's add the needed Helm Repository:
helm repo add jetstack https://charts.jetstack.io
And now we are ready to install the cert-manager.
helm install certmanager --namespace cert-manager jetstack/cert-manager \ --set ingressShim.defaultIssuerName=issuer-letsencrypt \ --set ingressShim.defaultIssuerKind=ClusterIssuer
helm list -n cert-manager NAME NAMESPACE STATUS CHART APP VERSION certmanager cert-manager deployed cert-manager-v0.12.0 v0.12.0
cert-manager is a Kubernetes add-on to automate the management and issuance of TLS certificates. By simple words, cert-manager will manage all certificates automatically for all of our domain names.
Above, we installed cert-manager to cert-manager namespace using two custom parameters:
ingressShim.defaultIssuerName = issuer-letsencrypt - it defines the name of an issuer for managing certificates automatically, later we will look for a more detail sample.
ingressShim.defaultIssuerKind = ClusterIssuer - defines a kind of issuer.
There are two types of IssuerKind:
Issuer- manages certain namespace where it was created. It is not possible to issue certificates from an Issuer in a different namespace.
ClusterIssuer- manages a whole cluster independent of the namespace. For getting a certificate we just need to add an annotation to the Ingress and cert-manager automatically issues the certificate.
First of all, we have to create an issuer which was defined above as
ingressShim.defaultIssuerName with name issuer-letsencrypt:
If we want to manage the whole cluster through one issuer. Here we have to use a kind ClusterIssuer and store it to cert-manager kubernetes namespace.
apiVersion: cert-manager.io/v1alpha2 kind: ClusterIssuer metadata: name: issuer-letsencrypt namespace: cert-manager spec: acme: email: [your email address here] server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: issuer-letsencrypt solvers: - http01: ingress: class: nginx
If we want to manage certain namespace. Here we have to use a kind Issuer and store it to the same namespace that your ingresses use (for instance: staging).
apiVersion: cert-manager.io/v1alpha2 kind: Issuer metadata: name: issuer-letsencrypt namespace: staging spec: acme: email: [your email address here] server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: # Secret resource used to store the account's private key. name: issuer-letsencrypt # Add a single challenge solver, HTTP01 using nginx solvers: - http01: ingress: class: nginx
Two of these use cases have the same structure:
metadata.name = issuer-letsencrypt- name which was defined as
spec.acme.email- uses for issuing certificates.
spec.acme.server- there are two servers production and staging:
We highly recommend testing against our staging environment before using our production environment. This will allow you to get things right before issuing trusted certificates and reduce the chance of your running up against rate limits.
You could read more detail documentation about Cert-Manager setup ACME guide here.
Bellow a real sample of using Issuer was an important term to use an annotation:
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: issuer-letsencrypt name: [some-ingress-name] namespace: staging spec: rules: - host: example.com http: paths: - backend: serviceName: [some-service-name] servicePort: 8080 path: / tls: - hosts: - example.com secretName: [tls secret name]
But for clarity, I described the same thing, but without additional information, and left that really make sense:
metadata: annotations: cert-manager.io/cluster-issuer: issuer-letsencrypt # OR in case when we are using kind Issuer cert-manager.io/issuer: issuer-letsencrypt spec: tls: - hosts: - example.com secretName: [TLS secret name]
Defined an annotation of issuer kind, and provided information of TLS host based on that will generate certificate and store to secret with name
[TLS secret name].
Will see in the next post 👋