OpenShift Route support for cert-manager

  • By null
  • Last update: Nov 17, 2022
  • Comments: 10

cert-manager project logo

OpenShift Route Support for cert-manager

This project supports automatically getting a certificate for OpenShift routes from any cert-manager Issuer.

Prerequisites:

  1. Ensure you have cert-manager installed through the method of your choice. But make sure you install cert-manager and openshift-routes-deployment in the same namespace. By default this is in the namespace cert-manager. For example, with the regular manifest:
oc apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.0/cert-manager.yaml

Both ClusterIssuer and namespace based Issuer are possible. Here a ClusterIssuer is used:

  1. For example, create the ClusterIssuer (no additional ingress class is needed for the openshift-ingress router. The example.com email must be replaced by another one):
apiVersion: v1
items:
- apiVersion: cert-manager.io/v1
  kind: ClusterIssuer
  metadata:
    annotations:
    name: letsencrypt-prod
  spec:
    acme:
      email: [email protected]
      preferredChain: ""
      privateKeySecretRef:
        name: letsencrypt-prod
      server: https://acme-v02.api.letsencrypt.org/directory
      solvers:
      - http01:
          ingress: {}
oc apply -f clusterissuer.yaml
  1. Make sure that there is an A record on the load balancer IP or a CNAME record on the load balancer hostname in your DNS system for the HTTP-01 subdomain.
CNAME:
  Name: *.service.clustername.domain.com
  Alias: your-lb-domain.cloud

Usage

Install in your cluster using the static manifests:

oc apply -f https://github.com/cert-manager/openshift-routes/releases/latest/download/cert-manager-openshift-routes.yaml

If you follow the above prerequisites, use this annotations below

...
metadata:
  annotations:
    cert-manager.io/issuer-kind: ClusterIssuer
    cert-manager.io/issuer-name: letsencrypt-prod
...
spec:
  host: app.service.clustername.domain.com
...

Annotate your routes:

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: example-route
  annotations:
    cert-manager.io/issuer-name: my-issuer # This is the only required annotation
    cert-manager.io/issuer-group: cert-manager.io # Optional, defaults to cert-manager.io
    cert-manager.io/issuer-kind: Issuer # Optional, defaults to Issuer, could be ClusterIssuer or an External Issuer
    cert-manager.io/duration: 1h # Optional, defaults to 90 days
    cert-manager.io/renew-before: 30m # Optional, defaults to 1/3 of total certificate duration.
    cert-manager.io/common-name: "My Certificate" # Optional, no default.
    cert-manager.io/alt-names: "mycooldomain.com,mysecondarydomain.com" # Optional, no default
    cert-manager.io/ip-sans: "10.20.30.40,192.168.192.168" # Optional, no default
    cert-manager.io/uri-sans: "spiffe://trustdomain/workload" # Optional, no default
spec:
  host: app.service.clustername.domain.com # will be added to the Subject Alternative Names of the CertificateRequest
  port:
    targetPort: 8080
  to:
    kind: Service
    name: hello-openshift

Observe the route.Spec.TLS section of your route being populated automatically by cert-manager.

The route's TLS certificate will be rotated 2/3 of the way through the certificate's lifetime, or cert-manager.io/renew-before time before it expires.

Now the website can be called: https://app.service.clustername.domain.com

Why is This a Separate Project?

We do not wish to support non Kubernetes (or kubernetes-sigs) APIs in cert-manager core. This adds a large maintenance burden, and it's hard for us to e2e test everyone's CRDs. However, OpenShift is widely used, so it makes sense to have some support for it in the cert-manager ecosystem.

Ideally we would have contributed this controller to an existing project, e.g. https://github.com/redhat-cop/cert-utils-operator. Unfortunately, cert-manager is not really designed to be imported as a module. It has a large number of transitive dependencies that would add an unfair amount of maintenance to whichever project we submitted it to. In the future, we would like to split the cert-manager APIs and typed clients out of the main cert-manager repo, at which point it would be easier for other people to consume in their projects.

Download

openshift-routes.zip

Comments(10)

  • 1

    Enhancing README with full tutorial on production okd.

    Worked together with Jake Sanders and the openshift slack community to test the newly repo out on a production okd cluster. Additional steps to be taken are added to the README.md. An edge + redirect route is assumed here.

  • 2

    release needed to make README.md instructions valid.

    The manifest deployment of the cert-manager-openshift-routes mentioned in the README.md pulls from the latest release on Github which includes a security context that won't be allowed without anyuid set for the service account. Since this was removed in 857bb1481d9703d1d629a8eadb8d36113b2b92b1 i'm assuming that a run of the release process would include that commit which makes the instructions in the README.md work.

    Cheers for putting this together btw, this is great.

  • 3

    Ignore CA as it may cause extended validation errors

    The CA field in the cert-manager CertificateRequest may not be set, or be useful at all. I've had reports of having the CA set causing extendedValidation errors in openshift, so I'd rather ignore the CA field entirely for now.

  • 4

    default ClusterRole needs PATCH on Events

    It seems that at least for certificate issuance failures that cert-manager-openshift-routes needs the ability to PATCH routes in addition to creating them:

    E0622 11:30:08.665072       1 event.go:267] Server rejected event '&v1.Event{TypeMeta:v1.TypeMeta{Kind:"", APIVersion:""}, ObjectMeta:v1.ObjectMeta{Name:"nbc9-test.16faba395a3cfe2e", GenerateName:"", Namespace:"nbc9-stuff", SelfLink:"", UID:"", ResourceVersion:"90166022", Generation:0, CreationTimestamp:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), DeletionTimestamp:<nil>, DeletionGracePeriodSeconds:(*int64)(nil), Labels:map[string]string(nil), Annotations:map[string]string(nil), OwnerReferences:[]v1.OwnerReference(nil), Finalizers:[]string(nil), ZZZ_DeprecatedClusterName:"", ManagedFields:[]v1.ManagedFieldsEntry(nil)}, InvolvedObject:v1.ObjectReference{Kind:"Route", Namespace:"nbc9-stuff", Name:"nbc9-test", UID:"fbeb012f-d913-4a07-a610-221a147904d0", APIVersion:"route.openshift.io/v1", ResourceVersion:"92122963", FieldPath:""}, Reason:"Issuing", Message:"Issuing cert as no certificate exists", Source:v1.EventSource{Component:"cert-manager-openshift-routes", Host:""}, FirstTimestamp:time.Date(2022, time.June, 21, 19, 42, 48, 0, time.Local), LastTimestamp:time.Date(2022, time.June, 22, 11, 30, 8, 662870925, time.Local), Count:96, Type:"Normal", EventTime:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), Series:(*v1.EventSeries)(nil), Action:"", Related:(*v1.ObjectReference)(nil), ReportingController:"", ReportingInstance:""}': 'events "nbc9-test.16faba395a3cfe2e" is forbidden: User "system:serviceaccount:openshift-operators:cert-manager-openshift-routes" cannot patch resource "events" in API group "" in the namespace "nbc9-stuff"' (will not retry!)
    

    Ignore the actual error it's trying to stick into the Event, that's certainly a separate issue. This issue is just about giving the SA the ability to do the thing.

  • 5

    Namespace is hardcoded

    Hi,

    I have modified the cert-manager-route to match the namespace where my cert-manager was installed but the application failed to work and create the certs for routes. When I checked the logs of the pod I saw that it kept searching for namespace cert-manager, although it is running in a different namespace.

    E1115 17:39:54.701737 1 leaderelection.go:334] error initially creating leader election record: namespaces "cert-manager" not found
    I1115 17:39:54.701755 1 leaderelection.go:253] failed to acquire lease cert-manager/cert-manager-openshift-routes
    I1115 17:39:56.786822 1 shared_informer.go:285] caches populated
    
  • 6

    possible interop issue with new cert-manager operator version v1.10.0

    We're using this plugin to configure our Routes in our OKD4 clusters and started getting a cert error (incorrect subject name) talking to the cert-manager service.

    E1103 16:12:16.053541       1 controller.go:326] cert-manager-openshift-routes/controller-manager "msg"="Reconciler error" "error"="Internal error occurred: failed calling webhook \"mutate.webhooks.cert-manager.io\": failed to call webhook: Post \"https://cert-manager-webhook-service.openshift-operators.svc:443/mutate?timeout=10s\": x509: certificate is valid for cert-manager-webhook, cert-manager-webhook.openshift-operators, cert-manager-webhook.openshift-operators.svc, not cert-manager-webhook-service.openshift-operators.svc" "controller"="route" "controllerGroup"="route.openshift.io" "controllerKind"="Route" "name"="whoami-external" "namespace"="nbc9-stuff" "reconcileID"="d2ba6bb6-cc08-4373-bd0e-633e0da4ed61" "route"={"name":"whoami-external","namespace":"nbc9-stuff"} 
    

    I don't see anything related in the v1.10.0 changelog so i'm not sure where it came from.

    The services defined do seem to be a little odd as well (20h ago was when we pulled in the v1.10.0 update to the cert-manager operator):

    ❯ kubectl get svc
    NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    cert-manager                   ClusterIP   10.129.203.158   <none>        9402/TCP   62d
    cert-manager-webhook           ClusterIP   10.129.152.47    <none>        443/TCP    62d
    cert-manager-webhook-service   ClusterIP   10.129.211.108   <none>        443/TCP    20h
    

    I'm not sure if this is a cert-manager operator bug, a cert-manager/openshift-routes bug or just an "us" bug.

  • 7

    Feature: Support for ECC certs

    https://cert-manager.io/docs/faq/#is-ecc-elliptic-curve-cryptography-supported indicates ECC keys can be used if the privateKey is properly set in the Certificate object.

    It would be great if we could have access to do this through openshift-routes.

    This may be related to #4.

  • 8

    Annotation generates CertificatesRequests repeatedly until blocked by letsencrypt

    The following annotation generates CertificatesRequests in a row and Lets Encrypt block it for requesting too many certificates for the same domain. cert-manager.io/duration: 2160h cert-manager.io/issuer-kind: ClusterIssuer cert-manager.io/issuer-name: letsencrypt-clusterissuer cert-manager.io/renew-before: 360h

  • 9

    Can the plugin be configured to use a wildcard certificate?

    Judging by description, this plugin issues a multi-domain certificate that includes SANs from each route host. But can it somehow generate one wildcard certificate to cover all routes at once? (By the way this question is connected with the DNS validation, since wildcard certificates do not support HTTP validation)

  • 10

    Support for the route subdomain enhancement

    Upcoming OpenShift releases (maybe 4.11) support to specify .spec.subdomain in OpenShift Route resources instead of .spec.host. The .spec.subdomain value will be extended by the Routers domain. .spec.host will not be filled for such routes. The hostname(s) can be found in .status.ingress[].host. Multiple OpenShift Routers can expose a single Route - so multiple host values can exist.

    Enhancement docs: https://github.com/openshift/enhancements/blob/master/enhancements/ingress/route-subdomain.md