In line with my previous article regarding external-dns
component in a kubernetes cluster : https://yodamad.hashnode.dev/set-up-external-dns-on-a-kubernetes-cluster, here is a quick one explaining how to secure your nginx ingresses
with a certificate to enable security in your environment.
This article is covering how to set up & configure the different elements to automatically generate a certificate provided by let's encrypt organism when deploying a new ingress in our cluster. Once it's done, every time an ingress will be deployed, with the right annotations, automatically a certificate will be generated to secure with TLS the HTTP endpoint.
Prerequisites for this article are :
A Kubernetes cluster running with an
nginx ingress controller
(and, optionally,external-dns
) installedkubectl
installed on your laptophelm
installed, optionally
First, we have to install cert-manager
component. This component is in charge to manage certificates in a cluster. A complete description is available here
# Install it with helm
$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.11.0 \
--set installCRDs=true
# or install it kubectl
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml
We can control that everything goes well by checking that the new components related to cert-manager
are known by the cluster
$ kubectl get crd | grep cert-manager
certificaterequests.cert-manager.io
certificates.cert-manager.io
challenges.acme.cert-manager.io
clusterissuers.cert-manager.io
issuers.cert-manager.io
orders.acme.cert-manager.io
$ kubectl explain Certificate
$ kubectl explain CertificateRequest
$ kubectl explain Challenge
Now, we need to create the component that will do the process to claim and generate a certificate regarding a certificate provider such as let's encrypt. This is done by creating a ClusterIssuer
component. This will cover the whole cluster. NB: If you want to restrict this feature to a dedicated namespace, you can use an Issuer
instead.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <your_email_to_receive_notifications>
privateKeySecretRef:
name: letsencrypt-production
solvers:
- http01:
ingress:
class: nginx
Here, each ingress will be detected and a certificate will be generated to secure them if TLS
is configured. You can fine-grain the ingresses to handle using ingressTemplate
solver approach describes in the official documentation. Now, let's modify the Ingress
defined in the previous article:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hashnode
annotations:
kubernetes.io/ingress.class: nginx
# Add this for detection
# Replace cluster-issuer by issuer if you define an Issuer rather than a ClusterIssuer
cert-manager.io/cluster-issuer: letsencrypt-production
spec:
rules:
- host: demo.hashnode.mydns.fr
http:
paths:
- backend:
service:
name: hashnode
port:
number: 80
pathType: Prefix
path: /
# Add this part to enable TLS
tls:
- hosts:
- demo.hashnode.mydns.fr
secretName: nginx-demo-tls
kubectl apply -f hashnode-demo.yaml -n hashnode
Once applied, we can see that
ingress controller is exposing
443
porta certificate has been generated
$ kubectl get svc --all-namespaces | grep ingress-nginx-controller
ingress-nginx ingress-nginx-controller LoadBalancer 10.3.106.101 57.128.40.102 80:30542/TCP,443:30552/TCP 2d11h
$ kubectl get certificates -A
NAMESPACE NAME READY SECRET AGE
hashnode nginx-demo-tls True nginx-demo-tls 81m
Now we can check that our website is secured with a valid certificate
And we can have a quick look at the certificate
So, in conclusion, with a few steps, we are now able to secure our endpoints for valid certificates generated by an official organism.
All sources are still available in my GitLab repository.