Secure your Kubernetes Services using Cert-Manager, NGINX Ingress and Let’s Encrypt

Uday Tatiraju
Jun 18, 2018 · 6 min read


There is little denying that we live in the age of microservices and containers. Most organizations, for the right use-cases, are moving from a monolithic architecture to a microservice architecture. Microservices enable rapid development of complex applications by splitting a large monolithic application into loosely coupled services that coordinate with each other. And containers are very well suited to deploy and run these microservices. However, microservices or containers bring in a new set of challenges. These challenges are inherent in any distributed architecture — from interservice communication and transactions that span service boundaries to testing, deployment and monitoring. Enter Kubernetes. Kubernetes is an open source orchestration tool that handles the operational complexity of microservices deployed in containers. It helps in automating deployments, scaling targeted services and the general management of containers.

This is all great, but consider this: you have developed a microservices based application and deployed it on a Kubernetes cluster. You have also exposed your single page web application, backed by your microservices or REST APIs, on a public facing IP address. One of the next logical steps before going live is to enable HTTPS and tie your public IP to your registered domain. Thanks to Let’s Encrypt, it is now easier than ever to acquire digital certificates (for free) and to enable HTTPS (SSL/TLS) for your services and websites. This article walks you through the configuration steps required to automatically enable TLS on your public Kubernetes services.


To follow the steps in this article, you will need the following:

  • A kubernetes cluster version 1.8+ running somewhere, like on a cloud provider of your choice.

Shameless promotion: you can sign-up for a free account on Oracle Cloud to run a Kubernetes engine (OKE).

  • The kubectl CLI installed and configured to talk to your Kubernetes cluster. You can quickly check your current context by running this command:
kubectl config current-context
  • A cluster role binding to grant administrative rights to the user principal you use to run your kubectl commands. If you don’t have the proper rights, run this command (replace the user_id token):
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole cluster-admin \
--user <user_id>
  • One or more services running inside the Kubernetes cluster with the spec type set to “ClusterIP”. For reference, here’s a sample yaml file that was used to create a service named “my-webapp”:
apiVersion: v1
kind: Service
name: my-webapp
app: my-webapp
tier: frontend
type: ClusterIP
— port: 80
targetPort: 8080
app: my-webapp
tier: frontend

Step 1: Install Helm

Helm is an official kubernetes native package manager. You can use helm to install and upgrade kubernetes applications. Helm uses a concept called charts — a collection of files that describe the kubernetes resources required to install and run an application. If you are a mac/brew user, run the following command:

brew install kubernetes-helm

To install Helm on a different OS or through other means, follow the instructions outlined in this Helm documentation.

Step 2: Install Tiller

Tiller is the server side component of Helm that typically runs in your Kubernetes cluster. For the purposes of this article, we will install tiller on the system namespace with RBAC enabled.

First, create a service account that will be used to run Tiller. Use the following command:

kubectl create serviceaccount tiller --namespace kube-system

Next, create a yaml file named “tiller-clusterrolebinding.yaml” and add the following text to it:

kind: ClusterRoleBinding
name: tiller-clusterrolebinding
— kind: ServiceAccount
name: tiller
namespace: kube-system
kind: ClusterRole
name: cluster-admin
apiGroup: ""

Now run the following command to create the cluster role binding and grant the “tiller” service account cluster wide admin rights:

kubectl create -f tiller-clusterrolebinding.yaml

Finally, install Tiller by running the following command:

helm init --service-account tiller

Optionally, verify that Tiller is installed and in service by running the following command and checking its output:

kubectl get pods --namespace kube-system

Step 3: Install Cert-Manager

Cert-Manager is a kubernetes native certificate manager. One of the most significant features that Cert-Manager provides is its ability to automatically provision TLS certificates. Based on the annotations in a Kubernetes ingress resource, the cert-manager will talk to Let’s Encrypt and acquire a certificate on your service’s behalf.

Run the following command to install Cert-Manager:

helm install \
--name cert-manager \
--namespace kube-system \
--set ingressShim.defaultIssuerName=letsencrypt-staging \
--set ingressShim.defaultIssuerKind=ClusterIssuer \
stable/cert-manager \
--version v0.3.0

Now let’s create a ClusterIssuer resource. A ClusterIssuer represents a certificate authority like Let’s Encrypt from which signed certificates can be obtained. At least one ClusterIssuer resource should be present in order for the certificate manager to begin issuing certificates.

Begin by creating a yaml file named “letsencrypt-staging.yaml” and add the following text to it:

kind: ClusterIssuer
name: letsencrypt-staging
# The ACME server URL
# Email address used for ACME registration
email: <>
# Name of a secret used to store the ACME account private key
name: letsencrypt-sec-staging
# Enable HTTP01 validations
http01: {}

Replace the value of the email field with the email address that you used to register your domain. Notice that we have configured an http challenge provider for this cluster issuer. You can read more about other challenges here.

Now create the ClusterIssuer resource by running this command:

kubectl create -f letsencrypt-staging.yaml

Let’s Encrypt production service imposes strict limits. I suggest that you use their staging service to test things out. Once you are ready, create a new ClusterIssuer that points to production:

Step 4: Install NGINX Ingress

In the Kubernetes world, Ingress is an object that manages external access to services within a cluster. An Ingress resource provides load balancing and SSL termination. The NGINX Ingress controller is based on the Ingress resource. We will configure this controller to act as an HTTPS load balancer and forward requests to specific services within the Kubernetes cluster.

Run the following command to install the NGINX Ingress controller into the system namespace with RBAC enabled:

helm install stable/nginx-ingress \
--name uck-nginx \
--set rbac.create=true \
--namespace kube-system

Step 5: Create Ingress

Let’s create the Ingress resource and specify a rule to forward requests to the service “my-webapp”. We need to annotate the resource definition so that Cert-Manager can automate the process of acquiring the required TLS certificate from Let’s Encrypt.

Begin by creating a yaml file named “my-ingress.yaml” and add the following text to it:

apiVersion: extensions/v1beta1
kind: Ingress
name: my-ingress
annotations: nginx letsencrypt-staging “true”
— host:
— path: /
serviceName: my-webapp
servicePort: 80
— secretName: tls-staging-cert

And now, for the grand finale, create the Ingress resource by running the following command:

kubectl create -f my-ingress.yaml

Sit back, relax and wait as Cert-Manager gets to work and acquires the certificate for your domain. Once it’s done, you can reach your service from the internet over HTTPS. With the sample Ingress above, that would be

If you have multiple sub domains like, and so on, you can get a wildcard certificate to simplify things. For instance, in the yaml above, simply specify “*” as the single element in the “hosts” list under “tls”.


Using Cert-Manager, NGINX Ingress and Let’s Encrypt streamlines the process of securely exposing your microservices that run on a Kubernetes cluster.

That’s all, folks.

The views expressed in this article are my own and do not represent those of my employer.

Oracle Developers

Aggregation of articles from Oracle & partners engineers, Groundbreaker ambassadors & the developer community on all things Oracle Cloud and its technologies. The views expressed are those of authors solely and do not necessarily reflect Oracle's. Contact @jimgris or @brhubart

Uday Tatiraju

Written by

Technologist, Deep learning enthusiast, Age of empires champion. NOTE: The views expressed here are my own and do not represent those of my employer.

Oracle Developers

Aggregation of articles from Oracle & partners engineers, Groundbreaker ambassadors & the developer community on all things Oracle Cloud and its technologies. The views expressed are those of authors solely and do not necessarily reflect Oracle's. Contact @jimgris or @brhubart

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade