In today's digital landscape, securing your web applications with HTTPS is non-negotiable. It ensures data privacy, builds user trust, and aligns with modern security standards. If you're running a Kubernetes cluster and want to enable HTTPS for your ingress using Let's Encrypt SSL certificates, cert-manager is your go-to tool for automating certificate management.
This blog post provides a comprehensive, step-by-step guide to configuring HTTPS on a Kubernetes cluster with cert-manager and Let's Encrypt. We'll walk through the entire process, from verifying your setup to troubleshooting common issues, ensuring your domain (e.g., platform-dev.example.ai) is secured with a valid SSL certificate.
Overview: What We're Building
This guide outlines how to set up HTTPS for a Kubernetes ingress using cert-manager, a powerful Kubernetes add-on that automates the issuance and renewal of SSL certificates from Let's Encrypt. By the end of this tutorial, you'll have:
- A Kubernetes cluster with an nginx ingress controller.
- A domain (e.g., platform-dev.example.ai) mapped to your cluster's external IP (e.g., 34.75.54.5).
- An ingress configured for HTTPS with automatic SSL certificate management.
Initial Setup Status
Before diving in, let's clarify the starting point:
- Cluster: A Kubernetes cluster with an nginx ingress controller already deployed.
- Domain: A domain (e.g., platform-dev.example.ai) mapped to the external IP 34.75.54.5.
- Ingress: An existing ingress with a TLS section, but the certificate isn't functioning correctly.
- Goal: Enable HTTPS with automated SSL certificate issuance and renewal using cert-manager and Let's Encrypt.
Prerequisites
To follow this guide, ensure you have:
- A Kubernetes cluster with an nginx ingress controller installed.
- A registered domain name pointing to your cluster's external IP.
-
kubectl
configured with access to your cluster.
Let’s get started with the setup process.
Step 1: Verify cert-manager Installation
The first step is to confirm whether cert-manager is installed in your Kubernetes cluster. cert-manager is a Kubernetes-native tool that simplifies certificate management by automating the process of obtaining, renewing, and managing SSL certificates.
Run the following command to check for existing cert-manager pods:
kubectl get pods -n cert-manager
If cert-manager is installed, you should see three running pods:
cert-manager-xxxxx
cert-manager-cainjector-xxxxx
cert-manager-webhook-xxxxx
If these pods are not present, you need to install cert-manager. Use the following command to deploy the latest stable version (v1.13.0 at the time of writing):
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
After applying the manifest, re-run the kubectl get pods -n cert-manager
command to verify that the three cert-manager pods are running. This ensures cert-manager is ready to manage certificates for your cluster.
Step 2: Create a ClusterIssuer for Let's Encrypt
A ClusterIssuer
is a Kubernetes resource that defines how cert-manager should obtain certificates. In this case, we'll configure a ClusterIssuer
to communicate with Let's Encrypt's production ACME server for issuing valid SSL certificates.
First, check if a ClusterIssuer
named letsencrypt-prod
already exists:
kubectl get clusterissuer letsencrypt-prod
If it doesn't exist or isn't configured correctly, create one with the correct ACME server URL. Important: Many tutorials mistakenly use an incorrect ACME server URL. The correct URL is:
- ✅ Correct:
https://acme-v02.api.letsencrypt.org/directory
- ❌ Incorrect:
https://acme-v2.api.letsencrypt.org/directory
To create the ClusterIssuer
, apply the following configuration, replacing your-email@company.com
with your actual email address (used for Let's Encrypt notifications):
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@company.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
EOF
After applying, verify that the ClusterIssuer
is ready:
kubectl get clusterissuer letsencrypt-prod
The output should show READY: True
. If it’s not ready, we'll cover troubleshooting in Step 5.
Step 3: Configure the Ingress for HTTPS
Your Kubernetes ingress resource needs specific annotations and configurations to work with cert-manager and enable HTTPS. Below is the complete ingress configuration for your domain (e.g., platform-dev.example.ai), which routes traffic to two services: platform-ui
and platform-api
.
Apply the following ingress configuration:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/enable-rewrite-log: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
name: example-ingress
namespace: platform-namespace
spec:
ingressClassName: nginx
rules:
- host: platform-dev.example.ai
http:
paths:
- backend:
service:
name: platform-ui
port:
number: 80
path: /
pathType: Prefix
- backend:
service:
name: platform-api
port:
number: 80
path: /api
pathType: Prefix
tls:
- hosts:
- platform-dev.example.ai
secretName: example-tls
Key Points in the Configuration:
-
Annotation:
cert-manager.io/cluster-issuer: letsencrypt-prod
tells cert-manager to use theletsencrypt-prod
ClusterIssuer to issue a certificate. -
TLS Section: Specifies the domain (
platform-dev.example.ai
) and the secret (example-tls
) where cert-manager will store the SSL certificate. -
Paths: Routes
/
to theplatform-ui
service and/api
to theplatform-api
service, both on port 80. -
Namespace: Ensure the ingress is created in the correct namespace (
platform-namespace
).
This configuration triggers cert-manager to request a certificate from Let's Encrypt and store it in the example-tls
secret.
Step 4: Verify Certificate Creation
Once the ingress is configured, cert-manager will automatically request a certificate from Let's Encrypt. To monitor the certificate creation process, use the following commands:
# Check certificate status
kubectl get certificate -n platform-namespace
# Get detailed certificate information
kubectl describe certificate example-tls -n platform-namespace
# Check certificate requests (for troubleshooting)
kubectl get certificaterequest -n platform-namespace
For a successful certificate, the output of kubectl get certificate
should look like:
NAME READY SECRET AGE
example-tls True example-tls 5m
The READY: True
status indicates that the certificate was issued successfully and is stored in the example-tls
secret.
Step 5: Troubleshooting Common Issues
If something goes wrong, here are common issues and their solutions:
1. ClusterIssuer Not Ready
If the ClusterIssuer
status is not READY: True
, run:
kubectl describe clusterissuer letsencrypt-prod
Check the events or status for errors. The most common issue is an incorrect ACME server URL (e.g., using acme-v2
instead of acme-v02
). Ensure the URL is https://acme-v02.api.letsencrypt.org/directory
.
2. Certificate Stuck in Pending
If the certificate status shows as pending, investigate with:
kubectl describe certificate example-tls -n platform-namespace
kubectl logs -n cert-manager deployment/cert-manager
Look for errors related to the ACME challenge process, such as HTTP-01 challenge failures.
3. DNS Issues
Ensure your domain resolves correctly to your cluster's external IP. Test DNS resolution from within the cluster:
kubectl run test-dns --rm -it --restart=Never --image=busybox -- nslookup platform-dev.example.ai
Verify connectivity to the Let's Encrypt ACME server:
kubectl run test-connectivity --rm -it --restart=Never --image=curlimages/curl -- curl -I https://acme-v02.api.letsencrypt.org/directory
Step 6: Verify HTTPS is Working
Once the certificate is issued, test your HTTPS endpoint to confirm it’s working:
# Test HTTPS response
curl -I https://platform-dev.example.ai
# Check certificate details
openssl s_client -connect platform-dev.example.ai:443 -servername platform-dev.example.ai
Key Success Indicators
Your setup is successful if:
- ✅ Certificate status is
READY: True
. - ✅ ClusterIssuer status is
READY: True
. - ✅ Ingress shows both ports 80 and 443.
- ✅ The
example-tls
secret exists with certificate data. - ✅ The site is accessible via HTTPS.
Certificate Lifecycle
- Validity: Let's Encrypt certificates are valid for 90 days.
- Auto-Renewal: cert-manager automatically renews certificates 30 days before expiration.
-
Monitoring: Check the certificate’s renewal time in its status with
kubectl describe certificate example-tls -n platform-namespace
.
Security Best Practices
To ensure a secure and reliable setup:
- Email Configuration: Use a monitored email address for Let's Encrypt notifications to stay informed about certificate issues or renewals.
- Secret Management: cert-manager automatically manages TLS secrets, so avoid manual modifications.
- HTTP to HTTPS Redirect: Add the following annotation to your ingress to enforce HTTPS:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
Final Configuration Summary
For a successful HTTPS setup, ensure:
- cert-manager is installed and running.
- The
ClusterIssuer
uses the correct ACME server URL. - The ingress includes the cert-manager annotation and TLS section.
- DNS is properly configured to point to your cluster’s external IP.
- Domain validation completes successfully.
Troubleshooting Commands Reference
For quick diagnostics, use these commands:
# Check cert-manager components
kubectl get pods -n cert-manager
kubectl logs -n cert-manager deployment/cert-manager
# Check certificates
kubectl get certificate -A
kubectl describe certificate example-tls -n platform-namespace
# Check ClusterIssuer
kubectl get clusterissuer
kubectl describe clusterissuer letsencrypt-prod
# Check ingress
kubectl get ingress -A
kubectl describe ingress example-ingress -n platform-namespace
# Check secrets
kubectl get secret example-tls -n platform-namespace -o yaml
Conclusion
By following this guide, you’ve successfully configured HTTPS for your Kubernetes ingress using cert-manager and Let's Encrypt.
Your domain (e.g., platform-dev.example.ai) is now secured with an automatically managed SSL certificate, ensuring secure communication for your users. With cert-manager handling renewals, you can focus on building your application while maintaining robust security.
If you encounter any issues, refer to the troubleshooting commands or reach out to the Kubernetes or cert-manager community for support. Happy securing!
Top comments (0)