Enabling Auto-TLS on EnRoute with Jetstack Cert Manager

EnRoute HowTos

Introduction - Jetstack Cert Manager

Jetstack Cert Manager is a Kubernetes package that helps working with Certificate Authorities like Let’s Encrypt to automatically sign and renew certificates. Helm is a popular package manager choice for Kubernetes. Installation of software, managing versions, upgrading versions and finding charts from registry are key benefits of Helm.

Installing TLS Certificates for EnRoute Ingress using Jetstack Cert Manager

EnRoute helm chart installs the EnRoute Ingress Controller to define L7 policy for a service running inside Kubernetes. The helm chart provides a fine-grained control to define L7 policies with its ability to enable/disable plugins for a service using configuration options that can be specified when helm is invoked.

EnRoute also supports plugins/filters to extend functionality and enforce policies. The features page lists the available plugins for the Gateway. More details about each of the plugins can also be found on plugin pages.

The helm chart integrates with Jetstack Cert manager to install a TLS certificate for a service. Once Jetstack Cert manager is installed, for example the following command sets up Jetstack Cert manager and issues a certificate -


helm upgrade httpbin-service-policy local-saaras/service-policy \
        --set service.namespace=demo-service                    \
        --set service.name=httpbin                              \
        --set service.prefix=/get                               \
        --set service.port=80                                   \
        --set service.enableTLS=true                            \
        --set autoTLS.certificateCN=httpbin.enroutedemo.com     \
        --set autoTLS.enableProd=true                                 

In the next few sections we describe what artifacts for certificate issue are created and how to debug it.

Artifacts created to support TLS Certificate Generation

Jetstack Cert Manager needs the creation of a ClusterIssuer that represent a certificate authority for certificates. EnRoute helm chart sets up a ClusterIssuer to work with Let’s encrypt staging, and another one to work with Let’s Encrypt production server -

ClusterIssuer

 kubectl describe --all-namespaces clusterissuers.cert-manager.io
Name:         letsencrypt-prod
Namespace:
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: httpbin-service-policy
              meta.helm.sh/release-namespace: default
API Version:  cert-manager.io/v1
Kind:         ClusterIssuer
Metadata:
    API Version:  cert-manager.io/v1
    Fields Type:  FieldsV1
  Self Link:         /apis/cert-manager.io/v1/clusterissuers/letsencrypt-prod
  UID:               370db8e7-fb61-4e41-a740-6e0f3bcabc1c
Spec:
  Acme:
    Email:            contact@example.com
    Preferred Chain:
    Private Key Secret Ref:
      Name:  letsencrypt-prod
    Server:  https://acme-v02.api.letsencrypt.org/directory
    Solvers:
      http01:
        Ingress:
          Class:  enroute
      Selector:
Status:
  Acme:
    Last Registered Email:  contact@example.com
    Uri:                    https://acme-v02.api.letsencrypt.org/acme/acct/118404211
  Conditions:
    Last Transition Time:  2021-04-16T23:33:02Z
    Message:               The ACME account was registered with the ACME server
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready
Events:                    <none>


Name:         letsencrypt-staging
Namespace:
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: httpbin-service-policy
              meta.helm.sh/release-namespace: default
API Version:  cert-manager.io/v1
Kind:         ClusterIssuer
Metadata:
    API Version:  cert-manager.io/v1
    Fields Type:  FieldsV1
  Self Link:         /apis/cert-manager.io/v1/clusterissuers/letsencrypt-staging
  UID:               34db7e69-f9a4-4009-bc68-7f1651f23d93
Spec:
  Acme:
    Email:            contact@example.com
    Preferred Chain:
    Private Key Secret Ref:
      Name:  letsencrypt-staging
    Server:  https://acme-staging-v02.api.letsencrypt.org/directory
    Solvers:
      http01:
        Ingress:
          Class:  enroute
      Selector:
Status:
  Acme:
    Last Registered Email:  contact@example.com
    Uri:                    https://acme-staging-v02.api.letsencrypt.org/acme/acct/18972900
  Conditions:
    Last Transition Time:  2021-04-16T23:33:02Z
    Message:               The ACME account was registered with the ACME server
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready
Events:                    <none>

Certificates

You get a certificate to install on the service by creating a Certificate object. This initiates the certificate signing process. Depending on the Issuer used, the staging or production server is used to get a certificate.

kubectl describe --all-namespaces certificates.cert-manager.io
Name:         httpbin.enroutedemo.com
Namespace:    demo-service
Labels:       app.kubernetes.io/managed-by=Helm
Annotations:  meta.helm.sh/release-name: httpbin-service-policy
              meta.helm.sh/release-namespace: default
API Version:  cert-manager.io/v1
Kind:         Certificate
Metadata:
  Creation Timestamp:  2021-04-17T00:00:26Z
  Generation:          1
  Managed Fields:
    API Version:  cert-manager.io/v1
    Fields Type:  FieldsV1
    API Version:  cert-manager.io/v1
    Time:            2021-04-17T00:02:36Z
  Resource Version:  47879688
  Self Link:         /apis/cert-manager.io/v1/namespaces/demo-service/certificates/httpbin.enroutedemo.com
  UID:               e41092bf-6773-49d3-9f5d-4338798c97ab
Spec:
  Common Name:  httpbin.enroutedemo.com
  Dns Names:
    httpbin.enroutedemo.com
  Issuer Ref:
    Kind:       ClusterIssuer
    Name:       letsencrypt-prod
  Secret Name:  httpbin.enroutedemo.com
Status:
  Conditions:
    Last Transition Time:  2021-04-17T00:02:36Z
    Message:               Certificate is up to date and has not expired
    Reason:                Ready
    Status:                True
    Type:                  Ready
  Not After:               2021-07-15T23:02:34Z
  Not Before:              2021-04-16T23:02:34Z
  Renewal Time:            2021-06-15T23:02:34Z
  Revision:                1
Events:                    <none>

Tracing Certificate creation logs

Jetstack Cert Manager installation creates services in the cert manager space.

kubectl get all -n cert-manager
NAME                                           READY   STATUS    RESTARTS   AGE
pod/cert-manager-56f5c44b5d-wshwn              1/1     Running   1          3d23h
pod/cert-manager-cainjector-5f494679f9-q8jhq   1/1     Running   0          3d23h
pod/cert-manager-webhook-5f59d4c7bd-xhqgj      1/1     Running   0          3d23h

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/cert-manager           ClusterIP   10.96.82.166    <none>        9402/TCP   3d23h
service/cert-manager-webhook   ClusterIP   10.96.239.164   <none>        443/TCP    3d23h

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/cert-manager              1/1     1            1           3d23h
deployment.apps/cert-manager-cainjector   1/1     1            1           3d23h
deployment.apps/cert-manager-webhook      1/1     1            1           3d23h

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/cert-manager-56f5c44b5d              1         1         1       3d23h
replicaset.apps/cert-manager-cainjector-5f494679f9   1         1         1       3d23h
replicaset.apps/cert-manager-webhook-5f59d4c7bd      1         1         1       3d23h

Tailing logs for the cert-manager service provides logs to debug certificate issue

kubectl logs -n cert-manager cert-manager-56f5c44b5d-wshwn --follow --since=5m
I0415 19:03:14.188036       1 conditions.go:173] Setting lastTransitionTime for Certificate "httpbin.enroutedemo.com" condition "Issuing" to 2021-04-15 19:03:14.188026423 +0000 UTC m=+3382.297097405
I0415 19:03:14.191331       1 conditions.go:173] Setting lastTransitionTime for Certificate "httpbin.enroutedemo.com" condition "Ready" to 2021-04-15 19:03:14.191322087 +0000 UTC m=+3382.300393029
...
I0415 19:03:16.904672       1 pod.go:70] cert-manager/controller/challenges/http01/ensurePod "msg"="creating HTTP01 challenge solver pod" "dnsName"="httpbin.enroutedemo.com" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
...
I0415 19:03:17.018426       1 pod.go:58] cert-manager/controller/challenges/http01/selfCheck/http01/ensurePod "msg"="found one existing HTTP01 solver pod" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.018685       1 service.go:43] cert-manager/controller/challenges/http01/selfCheck/http01/ensureService "msg"="found one existing HTTP01 solver Service for challenge resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Service" "related_resource_name"="cm-acme-http-solver-vs8r7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.127299       1 pod.go:58] cert-manager/controller/challenges/http01/selfCheck/http01/ensurePod "msg"="found one existing HTTP01 solver pod" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.127613       1 service.go:43] cert-manager/controller/challenges/http01/selfCheck/http01/ensureService "msg"="found one existing HTTP01 solver Service for challenge resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Service" "related_resource_name"="cm-acme-http-solver-vs8r7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
E0415 19:03:17.139881       1 controller.go:156] ingress 'enroutedemo/cm-acme-http-solver-kd82k' in work queue no longer exists
E0415 19:03:17.150861       1 controller.go:156] ingress 'enroutedemo/cm-acme-http-solver-drhzw' in work queue no longer exists
I0415 19:03:17.269384       1 pod.go:58] cert-manager/controller/challenges/http01/selfCheck/http01/ensurePod "msg"="found one existing HTTP01 solver pod" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.269793       1 service.go:43] cert-manager/controller/challenges/http01/selfCheck/http01/ensureService "msg"="found one existing HTTP01 solver Service for challenge resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Service" "related_resource_name"="cm-acme-http-solver-vs8r7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.536732       1 pod.go:58] cert-manager/controller/challenges/http01/selfCheck/http01/ensurePod "msg"="found one existing HTTP01 solver pod" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.537821       1 service.go:43] cert-manager/controller/challenges/http01/selfCheck/http01/ensureService "msg"="found one existing HTTP01 solver Service for challenge resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Service" "related_resource_name"="cm-acme-http-solver-vs8r7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:17.538186       1 ingress.go:92] cert-manager/controller/challenges/http01/selfCheck/http01/ensureIngress "msg"="found one existing HTTP01 solver ingress" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Ingress" "related_resource_name"="cm-acme-http-solver-vglq7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1beta1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
...
I0415 19:03:27.071540       1 pod.go:58] cert-manager/controller/challenges/http01/selfCheck/http01/ensurePod "msg"="found one existing HTTP01 solver pod" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:27.071676       1 service.go:43] cert-manager/controller/challenges/http01/selfCheck/http01/ensureService "msg"="found one existing HTTP01 solver Service for challenge resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Service" "related_resource_name"="cm-acme-http-solver-vs8r7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:27.071761       1 ingress.go:92] cert-manager/controller/challenges/http01/selfCheck/http01/ensureIngress "msg"="found one existing HTTP01 solver ingress" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Ingress" "related_resource_name"="cm-acme-http-solver-vglq7" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1beta1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
...
I0415 19:03:38.290830       1 pod.go:118] cert-manager/controller/challenges/cleanupPods "msg"="deleting pod resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
I0415 19:03:38.309099       1 pod.go:126] cert-manager/controller/challenges/cleanupPods "msg"="successfully deleted pod resource" "dnsName"="httpbin.enroutedemo.com" "related_resource_kind"="Pod" "related_resource_name"="cm-acme-http-solver-29j68" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579-3409815712" "resource_namespace"="enroutedemo" "resource_version"="v1" "type"="HTTP-01"
E0415 19:03:38.415267       1 controller.go:156] ingress 'enroutedemo/cm-acme-http-solver-vglq7' in work queue no longer exists
I0415 19:03:38.832551       1 acme.go:198] cert-manager/controller/certificaterequests-issuer-acme/sign "msg"="certificate issued" "related_resource_kind"="Order" "related_resource_name"="httpbin.enroutedemo.com-f4xqt-2887721579" "related_resource_namespace"="enroutedemo" "related_resource_version"="v1" "resource_kind"="CertificateRequest" "resource_name"="httpbin.enroutedemo.com-f4xqt" "resource_namespace"="enroutedemo" "resource_version"="v1"
I0415 19:03:38.833597       1 conditions.go:222] Found status change for CertificateRequest "httpbin.enroutedemo.com-f4xqt" condition "Ready": "False" -> "True"; setting lastTransitionTime to 2021-04-15 19:03:38.833587237 +0000 UTC m=+3406.942658189
...