Author: Daniyal Javed

This is a follow up blog to my previous blog which talked about using the Vault PKI engine to create dynamic certs for webapps running on GKE. A lot of Arctiq’s customers use OpenShift as their choice of Kubernetes flavor so a similar blog for OpenShift was in high demand.

For those of our readers that haven’t read the previous blog, I’ll go over the workflow again.

What is Vault?

Vault is a tool for securely accessing secrets. Vault allows users to store, manage and control access to tokens, username password and database credentials. There are many secrets management tools out there but Vault has gained a lot of popularity thanks to it’s flexible API and providing encryption at rest and in flight.

There have been cases of applications leaking credentials through logs, diagnostic output, external logging to a logging stack. Vault can provide dynamic secrets which help provide short-lived ephemeral credentials to applications instead of long live credentials. With dynamic secrets, even if an application writes it to an external system, it is valid for a specific period of time.

I’m not going to get into how to install Vault but going to cover more around the integration with apps running on OpenShift.

Vault PKI Secrets Engine

Vault enables you to deal with a whole Public Key Infrastructure (PKI) to guarantee secure correspondence among various applications. This enables organizations to effectively setup their own certificate authority (CA), revoke or issue new certs using basic API calls.. and dumping the agonizing procedure of always creating self signed certificates.

In this guide, I am going to clarify how Vault PKI engine functions and how you can utilize it to make your very own Root CA.


Cert-manager is a fantastic open-source project which can be used to request dynamic TLS certificates from Vault, Letsencrypt etc. Cert-manager runs as a pod on OpenShift and grabs TLS names from ingress objects.

Using Ingress on OpenShift

OpenShift ships with an HA Proxy router which acts a front end load balancer for wildcard application URLs which supports the Route API end point. Cert-manager does not support the Route object yet. So as a work around we will use NGINX reverse proxy to create ingress objects for OpenShift. There is a really good doc written for installing NGINX reverse proxy on kubernetes here. I won’t be getting into how to install the reverse proxy on OpenShift in this blog but I will link our public repo which will have the manifests at the end of this blog.

A lot of moving parts again but let’s get started:

Deploy the application

The application I’m going to be using is going to be the weather app again.

  • Create a new project in OpenShift
oc new-project weather
  • Create the deployment config
$ cat weather-dc.yaml
apiVersion: extensions/v1beta1
kind: Deployment
  name: weather
  replicas: 1
        app: weather
      - image:
        imagePullPolicy: Always
        name: weather
        - containerPort: 8080
$ oc create -f weather-dc.yaml
  • Create the service for the weather app
$ cat weather-svc.yaml 
apiVersion: v1
kind: Service
  name: weather
  - port: 8080
    targetPort: 8080
    protocol: TCP
    app: weather
$ oc create -f weather-svc.yaml
  • Assign DNS

At Arctiq’s production environment we use Terraform to dynamically update DNS for applications for lab and customer testing. I won’t get into too much about how to accomplish that with Terraform. It’s fairly straight forward by following Google’s and Hashicorp’s guides.

To make things simple I assigned the public IP of the node where the NGINX reverse proxy pod is running.

  • Create the ingress for the weather app
$ cat weather-ingress.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
  name: weather
  annotations: "nginx"
  - hosts:
    secretName: weather-tls
  - host: <YOUR-DNS-NAME>
      - path: /
          serviceName: weather
          servicePort: 8080
$ oc create -f weather-ingress.yaml

Install cert-manager

At this stage, cert-manager can be installed on the OpenShift cluster.

  • Clone the JetStack repo.
$ git clone
  • Create the objects for the cert-manager deployment:
$ cd deploy/manifests/
$ oc create -f 00-crds.yaml
$ oc create -f 01-namespace.yaml
$ oc create -f cert-manager.yaml
  • Verify cert-manager is running:
$ oc get pods -n cert-manager
NAME                                      READY     STATUS             RESTARTS   AGE
cert-manager-589678351-vd599              1/1       Running            0          1h

Configure Vault PKI back end

  • Create policy

I won’t get into how to install Vault. Cert-manager requires issue and sign on the PKI back end:

path "pki/issue/cert-manager" {
  capabilities = ["read", "list", "create", "update"]

path "pki/sign/cert-manager" {
  capabilities = ["read", "list", "create", "update"]
  • Create approle for cert-manager

Save your role-id and secret-id:

$ vault write auth/approle/role/cert-manager-role policies=cert-manager-pki
$ vault read auth/approle/role/cert-manager-role/role-id
$ vault write -f auth/approle/role/cert-manager-role/secret-id
  • Enable Vault PKI backend to act as a private CA
$ vault secrets enable pki vault secrets tune -default-lease-ttl=2160h -max-lease-ttl=87600h pki
$ vault write pki/root/generate/internal ttl=87600h
$ vault write pki/roles/cert-manager \ \ allow_subdomains=true max_ttl=8760h
  • Create kubernetes secret containing secret-id (saved in the previous steps)
cat cert-manager-vault-approle.yaml 
apiVersion: v1
kind: Secret
type: Opaque
  name: cert-manager-vault-approle
  namespace: weather
  secretId: "<base-64-encoded>" ### your secret-id
  • Create the vault issuer for cert-manager
$ cat issuer.yaml
kind: Issuer
  name: vault-issuer
    path: pki/sign/cert-manager
        path: approle
        roleId: "d37b79df-3d0f-f089-4121-be4c6887b367" ### your role-id
          name: cert-manager-vault-approle
          key: secretId
  • Create the certificate for cert-manager
$ cat certificate.yaml
kind: Certificate
  name: weather
  secretName: weather-tls ### should be the same as in ingress manifest
    name: vault-issuer
  commonName: <YOUR-DNS-NAME>
  - www.<YOUR-DNS-NAME>

At this point, test if the weather-tls secret is dynamically created:

$ oc get secrets -n weather
NAME                       TYPE                                  DATA      AGE
builder-dockercfg-5k6fv               1         1h
builder-token-2cpzw   4         1h
builder-token-7zcjw   4         1h
cert-manager-vault-token   Opaque                                1         1h
default-dockercfg-r648w               1         1h
default-token-mclnr   4         1h
default-token-tkpx5   4         1h
deployer-dockercfg-bkb2j               1         1h
deployer-token-b52qz   4         1h
deployer-token-srqgn   4         1h

Test the application:

And done! I have committed the code for the guide here

This demo was also recorded live at one of Arctiq’s event. A recap can be seen here.

Interested in learning more about this demo? Feel free to contact us by click on the link below

//take the first step



//blog search

//other topics