Setting Up Kubernetes Ingress with TLS: A Comprehensive Guide

Kadir Goksal
6 min readSep 12, 2024

--

In the world of Kubernetes, managing ingress traffic and securing it with TLS can seem like a daunting task. In this guide, we’ll walk through setting up an NGINX Ingress Controller with TLS using Let’s Encrypt, and address potential issues and errors you might encounter along the way.

Introduction

Welcome to our guide on setting up Kubernetes Ingress with TLS! If you’re navigating the world of Kubernetes, securing your applications with TLS might seem a bit overwhelming. Don’t worry; we’re here to break it down for you. This guide will walk you through the entire process of configuring an NGINX Ingress Controller and securing it with a TLS certificate from Let’s Encrypt.

What You’ll Learn

  1. Understanding the Basics:
  • We’ll start by explaining the key differences between ClusterIssuer and Issuer. These are crucial components for managing your TLS certificates in Kubernetes.
  1. Step-by-Step Setup:
  • Installing the NGINX Ingress Controller: Learn how to deploy the Ingress Controller using Helm and handle any installation issues you might encounter.
  • Creating a ClusterIssuer: Discover how to set up a ClusterIssuer to manage certificate issuance across your Kubernetes cluster.
  • Generating a TLS Certificate: Follow the steps to create a Certificate resource and link it to your Ingress Controller.
  • Configuring the Ingress Resource: See how to update your Ingress resource to use the new TLS certificate and route traffic securely.

2. Troubleshooting Common Issues:

  • We’ll cover potential problems like certificate issuance failures, missing Ingress Controller pods, and DNS configuration errors, providing you with practical solutions.

By the end of this guide, you’ll have a solid understanding of how to secure your Kubernetes applications with HTTPS, ensuring both privacy and data integrity.

Let’s dive in!

Understanding ClusterIssuer vs. Issuer

When working with TLS certificates in Kubernetes using cert-manager, it’s important to understand the distinction between ClusterIssuer and Issuer. Both are used to define how certificates are issued, but they differ in scope and application.

Issuer

  • Scope: Issuer is a namespaced resource, meaning it only operates within a specific namespace. It is suitable for situations where you need to issue certificates for resources within a single namespace.
  • Usage: Use Issuer when you have multiple namespaces but want to manage certificate issuance on a per-namespace basis.
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: example-issuer
namespace: example-namespace
spec:
acme:
email: your-email@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: example-issuer-key
solvers:
- http01:
ingress:
class: nginx

ClusterIssuer

  • Scope: ClusterIssuer is a cluster-wide resource, meaning it can be used across all namespaces. This is useful when you want a single issuer to handle certificate requests for multiple namespaces.
  • Usage: Use ClusterIssuer when you need a consistent certificate management strategy across the entire cluster.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: your-email@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx

Choosing Between ClusterIssuer and Issuer

  • Namespace-Specific Needs: If your certificate needs are confined to a specific namespace, an Issuer might be more appropriate. This can simplify management if you have different issuers for different namespaces.
  • Cluster-Wide Needs: If you need a single point of control for issuing certificates across your entire Kubernetes cluster, use ClusterIssuer. This centralizes certificate management and simplifies configuration.

Step-by-Step Setup

1. Install the NGINX Ingress Controller

The first step is to install the NGINX Ingress Controller using Helm. Helm simplifies the process of deploying and managing Kubernetes applications.

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx - namespace ingress-nginx - create-namespace

Note: If you encounter errors indicating that the resources already exist, such as a `ClusterRole`, you might need to clean up old Helm releases or check the ownership metadata of the resources.

2. Create a ClusterIssuer for Let’s Encrypt

A `ClusterIssuer` defines how certificates are issued. For Let’s Encrypt, you need to configure it with the ACME server and provide your email address.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: your-email@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod # Ensure this matches the secret used for the private key
solvers:
- http01:
ingress:
class: nginx # Make sure this matches the class of your Ingress Controller
  • email: This is used for Let's Encrypt notifications. Ensure it is valid.
  • privateKeySecretRef: This secret should contain the private key for Let's Encrypt. Make sure it exists and the name matches.
  • server: This URL should be correct for Let's Encrypt's ACME server.
  • ingress.class: This should match the class of the Ingress Controller you have installed. If using a different controller, update this accordingly.

Apply the configuration:

kubectl apply -f clusterissuer.yaml

3. Create a Certificate Resource

With the `ClusterIssuer` in place, you can create a `Certificate` resource that specifies the domain you want to secure.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: your-tls
namespace: your-portfolio # Ensure this matches the namespace where you want to store the certificate
spec:
secretName: your-tls # This should be the name of the secret where the certificate will be stored
issuerRef:
name: letsencrypt-prod # Must match the name of your ClusterIssuer
kind: ClusterIssuer
commonName: example.com # The domain you are securing
dnsNames:
- example.com # List of domains to be covered by the certificate
  • namespace: This should be the namespace where the certificate secret will be stored. Ensure it is correctly specified.
  • secretName: This is the name of the secret that will hold the certificate. Ensure it matches what you reference in the Ingress resource.
  • issuerRef: This should match the name of your ClusterIssuer.
  • commonName and dnsNames: These should be accurate and reflect the domains you intend to secure with this certificate.

Apply the configuration:

kubectl apply -f certificate.yaml

4. Configure Your Ingress Resource

Finally, configure your Ingress resource to use the TLS certificate and route traffic to your services.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: your-ingress
namespace: your-portfolio # Ensure this is the namespace where your services and Ingress are defined
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" # Should match the name of your ClusterIssuer
ingressClassName: nginx # Ensure this matches the class name of your Ingress Controller
spec:
tls:
- hosts:
- example.com # The domain for which you want to use TLS
secretName: your-tls # Must match the secret name defined in the Certificate resource
rules:
- host: example.com # The domain to route traffic to
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress # Ensure this matches the name of your service
port:
number: 3000 # Ensure this matches the port your service listens on
  • namespace: The namespace should be consistent with where the services and Ingress are deployed.
  • annotations: The annotation cert-manager.io/cluster-issuer must match the name of your ClusterIssuer.
  • ingressClassName: This should be the class name of the Ingress Controller you are using.
  • tls.secretName: This must correspond to the secretName in your Certificate resource.
  • rules: Ensure the host, service.name, and service.port.number match your actual setup.

Apply the configuration:

kubectl apply -f ingress.yaml

Potential Issues and Errors

1. Certificate Issuance Issues

Error: Certificate Secret Not Found

If the certificate secret `your-tls` is not found, ensure that your `Certificate` resource is correctly configured and that the `ClusterIssuer` is ready. Check the logs for `cert-manager` for detailed error messages.

kubectl describe certificate your-tls -n your-namespace
kubectl logs -n cert-manager -l app=cert-manager

Common Fixes:

  • Verify the email address and ACME server URL in the `ClusterIssuer`.
  • Check for network issues or DNS resolution problems that might affect certificate issuance.

2. Ingress Controller Issues

Error: No Ingress Controller Pods

If no pods are found in the `ingress-nginx` namespace, ensure that the Ingress Controller is installed correctly and running.

kubectl get pods -n kube-system
kubectl logs -n kube-system -l app.kubernetes.io/name=ingress-nginx

Common Fixes:

  • Ensure the Ingress Controller Helm chart was installed without errors.
  • Check for any existing conflicting resources.

3. DNS and External Access

Error: 404 Not Found or TLS Handshake Errors

Ensure that DNS records for `example.com` point to the external IP of the Ingress Controller. Also, verify that the Ingress Controller’s service is correctly exposing the required ports.

dig example.com
kubectl get svc -n kube-system

Common Fixes:

  • Update DNS records to match the Ingress Controller’s external IP.
  • Check firewall and security group rules to ensure the correct ports are open.

Conclusion

Setting up an Ingress Controller with TLS in Kubernetes involves several steps, from installing the controller to configuring certificates and Ingress resources. By carefully following the steps and troubleshooting common issues, you can successfully secure your Kubernetes applications with HTTPS.

For more detailed documentation;

--

--