Setting Up and Securing Your Web Service in Kubernetes
Discover how to make your web services secure and accessible using Kubernetes in our latest blog post. From setting up Ingress resources to using Let’s Encrypt certificates, this guide provides a comprehensive overview.
Kubernetes is a popular method for hosting websites and other services, benefiting from its reliability and scalability. As more websites handle sensitive data like personal information or passwords, browsers now require all sites to use TLS to secure their traffic. Managing all the necessary components to host a TLS-based website can be challenging, from obtaining TLS certificates to renewing them on time and configuring your server to use them.
Fortunately, you can run services in your Kubernetes cluster to handle much of this complexity for you. Traefik Proxy (pronounced “Traffic”) can be used as a network proxy alongside cert-manager, a service that acquires and manages secure certificates. Using these services with Let’s Encrypt, a provider of free, automated secure certificates, reduces the burden of certificate management, typically to the point where only initial setup is needed.
In this tutorial, you will set up cert-manager, Traefik, and Let’s Encrypt in your Kubernetes cluster, along with an example website service, to automatically obtain, renew, and use secure certificates for your website.
If you’re looking for a managed Kubernetes hosting service, check out our simple, managed Kubernetes service designed for growth.
Prerequisites
- A Kubernetes cluster accessible via kubectl
- A current version of kubectl to interact with your cluster
- A ccenter account
- Helm version 3 or higher
- Experience working with a Kubernetes cluster using kubectl
- A registered domain name. In this tutorial, your_domain will be used. You can purchase a domain name from Namecheap, get one for free with Freenom, or use your preferred domain registrar.
- DNS setup for your domain name, including a personal access token with read and write access
Step 1: Setting Up cert-manager in Your Cluster
Traditionally, setting up secure certificates for a website would require creating a certificate request, paying a trusted certificate authority to create a certificate for you, configuring your web server to use that certificate, and remembering to repeat the process each year to keep your certificates current.
With the founding of Let’s Encrypt in 2014, it became possible to obtain free certificates through an automated process. However, these certificates are only valid for a few months rather than a year, so an automated renewal system is required. To handle this, use cert-manager, a service designed to run in Kubernetes and automatically manage the lifecycle of your certificates.
In this section, you will set up cert-manager to run in its own namespace in your cluster.
First, install cert-manager using kubectl with the cert-manager release file:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
By default, cert-manager installs in its own namespace called cert-manager. When this file is applied, several resources will be created in your cluster.
Step 2: Configuring the Let’s Encrypt Certificate Issuer
Using a secure certificate for your website signals to your users that they can trust the site they’re viewing is served by your servers. The certificate authority needs to verify you own the domain for which the certificate is issued. Let’s Encrypt uses a standard called ACME, which uses challenges to prove you own the domain for which you’re creating a certificate. cert-manager supports both DNS and HTTP challenges for various providers.
In this section, you’ll create a ClusterIssuer for your cluster, telling cert-manager how to issue certificates from Let’s Encrypt and which credentials to use to access your DNS provider.
Save the following YAML configuration details in a file named clusterissuer.yaml:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns
spec:
acme:
# Ensure the server points to Let’s Encrypt’s production environment
server: https://acme-v02.api.letsencrypt.org/directory
# Use an email address that Let’s Encrypt can contact in case of issues
email: your_email@your_domain
# We use DNS-01 challenge since it’s the only way to perform challenges in zones that only support DNS
solvers:
– dns01:
centron:
# Obtain your centron API token from the environment variable
tokenSecretRef:
name: centron-dns
key: access-token
Replace your_email@your_domain with your own email address. Let’s Encrypt will use this to notify you if there are any issues with your certificate. You can also use an alias email address if you prefer.
Step 3: Configuring the centron Access Token
For cert-manager to perform DNS-01 challenges on your DNS provider, it needs access to your ccenter account. This is done using an API token stored as a Kubernetes secret in your cluster.
In this section, you’ll create a Kubernetes secret with your centron access token.
First, store your centron access token in an environment variable:
export CENTRON_ACCESS_TOKEN=your_centron_access_token
Replace your_centron_access_token with your own access token.
Then create a Kubernetes secret with your access token:
kubectl create secret generic centron-dns –from-literal=access-token=$CENTRON_ACCESS_TOKEN
Step 4: Creating an Ingress Resource Object
In Kubernetes, an Ingress resource is an object that manages HTTP and HTTPS routes from outside the cluster to services within the cluster. Traefik can use Ingress resources to automatically obtain SSL/TLS certificates from cert-manager and use them to secure traffic to your services.
Create an Ingress resource for your website service with the following configuration:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: “letsencrypt-dns”
# Enable TLS certificates for this Ingress
traefik.ingress.kubernetes.io/router.tls: “true”
spec:
rules:
– host: your_domain
http:
paths:
– pathType: Prefix
path: “/”
backend:
service:
name: example-service
port:
number: 80
tls:
– hosts:
– your_domain
# Let Let’s Encrypt manage the certificate
secretName: example-tls
Replace your_domain with your own domain and example-service with the name of the service you want to secure.
Step 5: Creating the Example Website Service
To demonstrate how Traefik, cert-manager, and Let’s Encrypt work together, create a simple example website service secured by Traefik.
First, create an example website file named index.html:
Hello, world!
This is an example website secured with Traefik, cert-manager, and Let’s Encrypt.
Save the file on your local computer.
Then create a ConfigMap resource from the index.html file:
kubectl create configmap example-website –from-file=index.html
Next, create a Deployment resource for your example website service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-deployment
spec:
replicas: 1
selector:
matchLabels:
app: example
template:
metadata:
labels:
app: example
spec:
containers:
– name: example-container
image: nginx:latest
ports:
– containerPort: 80
volumeMounts:
– name: example-website
mountPath: /usr/share/nginx/html
volumes:
– name: example-website
configMap:
name: example-website
Finally, create a Service resource for your example website service:
apiVersion: v1
kind: Service
metadata:
name: example-service
spec:
selector:
app: example
ports:
– protocol: TCP
port: 80
targetPort: 80
After applying these configurations, your service should be accessible on your domain with a valid TLS certificate! You can check your progress by running kubectl get ingress –watch and waiting for the IP address to be assigned. Then, open your domain in a web browser to see your secure website.
Step 6 — Making Your Web Service Accessible and Secure
Though all individual services are running in your cluster, they act relatively independently of each other. cert-manager is simply present, Traefik is unaware of the sites it should serve, and your Nginx site is only accessible if you port-forward into the cluster. In this section, you’ll create an Ingress resource to connect all your services.
First, reopen the file tutorial-service.yaml:
nano tutorial-service.yaml
At the end of the file, after the tutorial-service service you added earlier, add an Ingress resource. Be sure to update the configuration with your own domain name and include — at the beginning to separate your Ingress resource from the Service resource above:
…
—
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tutorial-service-ingress
namespace: tutorial
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: “true”
cert-manager.io/cluster-issuer: letsencrypt-issuer
spec:
rules:
– host: tutorial-service.your_domain
http:
paths:
– path: /
pathType: Prefix
backend:
service:
name: tutorial-service
port:
number: 80
tls:
– secretName: tutorial-service-cert
hosts:
– tutorial-service.your_domain
These lines contain the rules and annotations to link everything together. The Ingress resource includes references to Traefik, cert-manager, and your tutorial-service. The annotations section includes some different but important annotations.
The annotation traefik.ingress.kubernetes.io/router.entrypoints tells Traefik that traffic for this Ingress should be available over the websecure entry point. This is an entry point that the Helm chart configures by default to handle HTTPS traffic and listens on port 443, the standard for HTTPS.
The next annotation, traefik.ingress.kubernetes.io/router.tls, is set to true to tell Traefik to respond only to HTTPS traffic and not HTTP traffic. Since your website needs to be secure for handling sensitive data, you don’t want users to accidentally use an insecure version.
The last annotation, cert-manager.io/cluster-issuer, is set to letsencrypt-issuer to tell cert-manager which issuer to use when issuing secure certificates for this Ingress. At this point, letsencrypt-issuer is the only issuer you’ve configured, but you could add more later and use different ones for different sites.
In the spec.rules section of the Ingress, you specify a rule for the routes of traffic sent to the Ingress. It states that for the host named tutorial-service.your_domain, use HTTP for the specified paths. The only path included is the root /path with a path type of Prefix, meaning that any traffic sent should be forwarded to the provided backend. The backend section specifies it’s a service, that the traffic should be sent to the tutorial-service service you created earlier, and that traffic should be sent to port 80 of the service.
The spec.tls section of the Ingress contains the information cert-manager needs to request and issue your secure certificates, as well as the information Traefik needs to use those certificates. The secretName is the Kubernetes Secret where cert-manager will place the issued secure certificate, and the Secret that Traefik will use to load the issued certificate. The hosts section lists the hostnames for which cert-manager will request certificates. In this case, it will be only the hostname tutorial-service.your_domain, but you could add others you own if you want the site to respond to multiple hostnames.
Once you’ve saved the created Ingress, apply kubectl apply again to apply the new resource to your cluster:
kubectl apply -f tutorial-service.yaml
The Ingress will be created, and the other resources will remain unchanged:
Output
namespace/tutorial unchanged
deployment.apps/tutorial-service unchanged
service/tutorial-service unchanged
ingress.networking.k8s.io/tutorial-service-ingress created
Once the Ingress is created, Traefik will begin configuring itself, and cert-manager will start the challenge/response process to issue the certificate. This may take a few minutes, so you can check if the certificate is issued by checking the certificates in your tutorial namespace:
kubectl get -n tutorial certificates
You will see output similar to the following:
Output
NAME READY SECRET AGE
tutorial-service-cert False tutorial-service-cert 12m
If the READY field is False, the certificate has not yet been issued. You can continue running the same command to check if it turns True. It might take some time to be issued, but if it takes longer than a few minutes, it could indicate a problem with your configuration.
Note: If your certificate isn’t issued after 10-15 minutes, viewing the log messages for cert-manager may help to see if there are any issues requesting the certificate. To view these logs, you can use the following command to observe the logs and stop following them with CONTRL+C:
kubectl logs -n cert-manager deployment/cert-manager –tail
=10 -f
Once your certificate is ready, you can make an HTTPS request against your cluster using curl:
curl https://tutorial-service.your_domain
Note: Depending on how long ago you updated your DNS records and how long it takes for the DNS records to propagate through the Internet’s DNS servers, you might see an error saying your domain couldn’t be found or points to the wrong place. If this happens, you can use a curl workaround to temporarily skip DNS checking by running the following command:
curl https://tutorial-service.your_domain –resolve ‘tutorial-service.your_domain:443:traefik_ip_address’
This command tells the curl command to use the –resolve option to override any DNS resolution for tutorial-service.your_domain on port 443 with traefik_ip_address. Since the DNS result that curl receives is incorrect, you can still connect to Traefik in your cluster until DNS fully updates.
Your output will contain the same Nginx “Welcome!” page as before with port-forwarding, but this time it’s accessible over the Internet:
However, if you try requesting the HTTP version of your site, you’ll receive no response:
curl http://tutorial-service.your_domain
Instead, a 404 error page loads:
Output
404 page not found
Since you configured your site in Ingress not to respond to HTTP traffic, Traefik never set up a site at that address and returns a 404 error. This may confuse users if they expect to see a site. Many administrators configure their servers to automatically redirect HTTP traffic to the HTTPS site. Traefik allows you to do this by updating Traefik to tell it to redirect all web traffic to the websecure port:
helm upgrade –namespace=traefik traefik traefik/traefik –set ‘ports.web.redirectTo=websecure’
The –set ‘ports.web.redirectTo=websecure’ option tells Traefik to reconfigure itself to perform the redirect automatically.
You should see a message like the following, confirming the Traefik installation has been “upgraded”:
Output
Release “traefik” has been upgraded. Happy Helming!
NAME: traefik
LAST DEPLOYED: Sun Oct 2 19:17:34 2022
NAMESPACE: traefik
STATUS: deployed
REVISION: 2
TEST SUITE: None
Now, if you make a request to your HTTP site, you’ll receive output saying the site has moved:
curl http://tutorial-service.your_domain
This response is expected:
Output
Moved Permanently
Since you want all your traffic going to your HTTPS site, Traefik now returns an automatic redirect from the HTTP site to the HTTPS site. Web browsers will automatically perform this redirect, but Curl needs an additional -L option to tell it to follow redirects. Update your Curl command with the -L option to follow redirects:
curl -L http://tutorial-service.your_domain
The output includes the Nginx welcome page from your HTTPS site:
This output confirms that the redirect is working as expected.
In this section, you connected cert-manager, Traefik, and your Nginx website using a Kubernetes Ingress resource. You also updated your Traefik configuration to redirect HTTP traffic to HTTPS, ensuring that users find your site securely.
Conclusion
In this tutorial, you installed several services in your Kubernetes cluster to make it easier to run a website with secure certificates. You installed the cert-manager service to manage the lifecycle of TLS certificates issued by Let’s Encrypt. You installed Traefik to make your websites accessible outside your cluster and to use the TLS certificates issued by Let’s Encrypt. Finally, you created an Nginx website in your cluster to test your cert-manager and Traefik configurations.
Now that you have cert-manager and Traefik configured in your cluster, you could also set up more websites with different Ingress resources to serve many websites from the same cluster with a single cert-manager and Traefik installation.
You can read the Traefik proxy documentation to learn more about the various functionalities Traefik can provide in your cluster. cert-manager also has extensive documentation on how to use it with other types of Let’s Encrypt challenges, as well as sources outside of Let’s Encrypt.
To continue configuring your Kubernetes cluster, check out our other tutorials on Kubernetes.