Fullstack k8s application blog series

Ingress & TLS/HTTPS with nginx, cert-manager & Vault

A B Vijay Kumar
Cloud Native Daily
Published in
8 min readNov 3, 2022


Chapter 8: In this blog, we will configure our ingress to use TLS/HTTPS, to access our web application. To generate the certificates we will use Vault, and then to manage certificates we will be using cert-manager


Ingress exposes the services, that we are built to the outside world. It provides the HTTP and HTTPS routes, that are defined by the ingress resource. To provide a secured connection, HTTPS/TLS is used, and for that, we will need to integrate ingress with a certificate authority (CA). The certificates that are issued by CA, also need to be managed. Jetstack’s cert-manager provides a Kubernetes native framework to manage the certificates and integrates with Ingress. For CA, we can use Let’s Encrypt, Hashicorp Vault, Vernafi etc.

Since we already have a vault cluster in our environment, it makes more sense to integrate cert-manager with Vault public key infrastructure (PKI) secret engine to generate X.509 certificate. cert-manager provides an Issuer interface, which can be used to implement the vault as the certificate issuer. The diagram below shows a very high-level interaction diagram between the cert-manager and the vault, on how the certificates are generated and managed by cert-manager.

Interaction Diagram — Jetstack’s cert-manager — Hashicorp Vault

1, 2 — When the Certificate is expired or required, the Issuer (custom resource of cert-manager) sends a request to Vault as a CertificateRequest object.

3 — Vault authenticates and validates the Issuer using Kubernetes authentication.

4 — Vault will generate a certificate with intermediate CA once authenticated and validated.

5 — The certificate is passed to the cert-manager

6 — cert-manager stores the certificate as a secret and serves it along with the web page.

In this chapter, we will be setting up the complete infrastructure to implement HTTPS. The following diagram shows how the various resources will come together to provide the HTTPS implementation for our application.

Jetstack’s cert-manager & Hashicorp Vault to implement HTTPS

We will be integrating with AWS ACM, in later blogs/chapters. This chapter focuses on the development environment and helps clear the concepts. Before you go any further, make sure you have gone through Chapter 2, where we are setting up the Vault cluster.

Let’s now go through the setup process

1) Setup Vault

Let's configure the public key infrastructure on our vault cluster.

Step 1.1: Log in to the vault pod using the following command

kubectl exec -n vault --stdin=true --tty=true vault-0 — /bin/sh

Step 1.2: Enable public key infrastructure, by executing the following command inside the vault container

vault secrets enable pki

Step 1.3: Set the maximum lease TTL (time to live). we are setting 365 days (8760 hours) since it's a Dev environment.

vault secrets tune -max-lease-ttl=8760h pki

Step 1.4: Generate the root CA

vault write pki/root/generate/internal \ \

We can check the certificate that is generated in the vault portal. Following is the screenshot Vault portal

Step 1.5: Set the PKI URLs for issuing certificates and certificate revocation list (CRL) distribution point URLs. Both of them will point to the PKI of Vault. The cert-manager will call these URLs to get the certificates and validate certificates that are revoked.

vault write pki/config/urls \
issuing_certificates=”http://vault.default:8200/v1/pki/ca" \

Step 1.6: Define the role. Set the allowed domain to, and also allow subdomains

vault write pki/roles/bozobooks-dot-com \ \
allow_subdomains=true \
require_cn=false \

Step 1.7: Set the service account for the issuer, please note that the namespace default is already included, we may have to specify bozo-book-library-dev along with that, as we will be having our issuer service account in that namespace

vault write auth/kubernetes/role/issuer \
bound_service_account_names=issuer \

Following is the screenshot on the vault portal

Step 1.8: Define the policy, and provide access.

vault policy write pki — <<EOF
path “pki*” { capabilities = [“read”, “list”] }
path “pki/sign/bozobooks-dot-com” { capabilities = [“create”, “update”] }
path “pki/issue/bozobooks-dot-com” { capabilities = [“create”] }

The following screenshot shows the policy that is defined, on the Vault portal.

Let’s now install cert-manager

2) Install cert-manager

cert-manager can be installed using the helm chart, by executing the following command. (note that we are also installing the CRDs, which are required for us to define the resources, later in the chapter).

helm upgrade -i  --create-namespace -n cert-manager cert-manager jetstack/cert-manager --set installCRDs=true

This should install the cert-manager CRDs and run the cert-manager pods, as shown in the below screenshot

3) Setup Kubernetes cluster

Step 3.1: Create Service Account

Create the service account issuer that we configured in the vault. Note that the namespace is bozo-book-library-dev, which we had already configured in the previous step

apiVersion: v1
kind: ServiceAccount
name: issuer
namespace: bozo-book-library-dev

Step 3.2: Create Issuer Secret

Create the issuer-token secret, This will be used by the cert-manager Issuer a resource to connect to the vault. The suggests the service account to which this secret token is linked.

apiVersion: v1
kind: Secret
name: issuer-token
namespace: bozo-book-library-dev
annotations: issuer

This creates a secret as shown in the below screenshot

As you can see in the screenshot, cert-manager has added additional annotations and has fetched the ca.crt, ts.crt, tls.key from Vault and populated it into the secret, this is used by the ingress controller, to serve the certificate and handle TLS/HTTPS.

Step 3.3: Create Issuer

Create Issuer resource, This is called by the cert-manager to request the certificate when the certificate is expired/required. We provide the vault details to this resource. We point it to the vault server, provide the path to the PKI that we configured in the previous section, and provide the service account to use (issuer) so that the vault will authenticate the request coming from the Issuer, and provide the generated certificate (as shown in the interaction diagram above)

kind: Issuer
name: vault-issuer
namespace: bozo-book-library-dev
server: http://vault.vault.svc.cluster.local:8200
path: pki/sign/bozobooks-dot-com
mountPath: /v1/auth/kubernetes
role: issuer
name: issuer-token
key: token

4) Update the hosts file

Since we are using this in the local development environment, we need to make the point to the localhost. To do that, we need to update the hosts file located in /etc. We can do that by executing sudo vi /etc/hosts. The screenshot below shows the entries

Let’s now install and configure Ingress

5) Install Nginx Ingress

We will be using Nginx Ingress. Use the following commands, to install Nginx ingress controller.

kubectl apply -f upgrade -i  --create-namespace -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx

Once this is installed, We will be defining the ingress for our project as follows.

As you can see this is a standard ingress definition, with three paths

  • / pointing to the ReactJS app, that we developed in Chapter 7
  • /bookinfopointing to the book information microservice service that we developed in Chapter 3
  • /booklibpointing to the book library microservice that we developed in Chapter 6.

An important thing to note is the annotation, where we are providing the issuer resource that we defined in previous steps. This is picked up by the cert-manager to use the respective issuer to get the certificate.

Let’s apply this manifest with the following command

kubectl apply -f ingress.yaml

Now we should be able to access our portal. Find below the screenshot of our application working, with

you can see that the site works with HTTPS, though the certificate is not secure, as it is self-signed.

When we move to production, we will be implementing the actual CA, where we will generate a certificate from a proper CA, and will be using AWS ACM.

Finally, we got our application working on the development environment.

Before we move to AWS architecture and deployment, we will go through setting up observability in a development environment, we will be going through this in the next few chapters.

Until then, take care, please leave your feedback and comments

See you soon ;-)



A B Vijay Kumar
Cloud Native Daily

IBM Fellow, Master Inventor, Mobile, RPi & Cloud Architect & Full-Stack Programmer