Gardener certification manager
The cert-manager controller is usually used to manage TLS certificates in Kubernetes clusters.
In a multi-cluster environment like Gardener, it becomes cumbersome to use existing open source projects, such as cert-manager, for managing the certificates. Therefore OSC provides an extension for the Shoots, which allows the usage of cert-manager's CRDs without the need to install and configure cert-manager itself.

Note
The cert-manager provided by OSC project uses a different approach compared to the Gardener project' cert-manager. The OSC implementation uses the standard cert-manager implementation deployed as a Gardener Extension.
Deploying the extension
Warning
It is not supported to deploy the upstream cert-manager to a Shoot cluster where the extension is enabled.
Such setup won't function correctly, and the issues will remain even after removing one of the cert-managers. Please either enable the extension or deploy your own cert-manager, never both.
The extension is activated for a Shoot by defining it in its
manifest in the extensions
section.
This can be done either at the Shoot's creation,
or later, by editing and re-applying an existing Shoot's manifest.
The extension is deployed when the Shoot is reconciled.
apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: <name of the shoot>
namespace: garden-<name of the project where shoot needs to be located>
spec:
extensions:
# enable the cert-manager extension
- type: osc-cert-manager-service
To change it through the Gardener dashboard, click on the YAML section on the Shoot's status page, and edit the manifest:

The Shoot will be reconciled after pressing the SAVE button on the bottom of page.
Disabling the extension
The extension can be explicitly disabled, which may be needed in case the cert-manager extension is globally enabled.
kind: Shoot
spec:
extensions:
- type: osc-cert-manager-service
disabled: true
Usage
The cert-manager Custom Resource Definitions (CRDs) are available on the Shoot clusters. The CRDs have the same definition as those of the upstream cert-manager's.
Users can use the extension with their own Certification Authority (CA) certificate. This has to be uploaded to the Shoot as a Secret, and referenced in the Issuer object.
Each Gardener stack has a self-signed CA certificate,
available to all Shoots of the stack.
To create certificates issued by the predefined extension-provided
ClusterIssuer, define the issuerRef
in the following way:
issuerRef:
group: cert-manager.osc.extensions.gardener.cloud
kind: ClusterIssuer
name: Gardener
secretName: ca-cert-inbuild
If needed, users can create an Issuer which will generate certificates issued by Let's Encrypt using ACME.
Example: Generating Ingress certificate by annotation
This example shows how to deploy a cert-manager Issuer and use it to issue an Ingress certificate by annotating the Ingress. The predefined stack CA certificate will be used as the issuing certificate. All actions are performed directly on Shoot cluster.
- Option 1: obtain a certificate secret using the OSC provided ClusterIssuer
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: ca-cert namespace: kube-system spec: isCA: true dnsNames: - somedomain.live issuerRef: group: cert-manager.osc.extensions.gardener.cloud kind: ClusterIssuer name: Gardener secretName: ca-cert
- Option 2: deploy a Secret with a custom certificate/private key pair
apiVersion: v1 kind: Secret metadata: name: ca-cert namespace: kube-system type: kubernetes.io/tls data: tls.crt: <Base-64 encoded PEM of the certificate> tls.key: <Base-64 encoded PEM of the private key>
In both cases a Secret named
ca-cert
will be present, containing the certificate/key pair.
- The next step is to create an Issuer in the same Namespace,
referencing the Secret.
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: gardener-issuer namespace: kube-system spec: ca: secretName: ca-cert
- When an Ingress is created with the correct annotation and TLS section,
the cert-manager extension will create a new certificate/key pair for the Ingress, based on the Issuer and the
ca-cert
from the previous step.Let's consider that we already have:
- a service `my-service` in the kube-system namespace - a deployed nginx-ingress-controller - a DNS record `*.somedomain.live` in the [DNS provider extension][dnsext] connected to the ingress controller's public IP.
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: application-ingress namespace: kube-system annotations: cert-manager.io/issuer: gardener-issuer spec: ingressClassName: nginx rules: - host: ingresstest.somedomain.live http: paths: - pathType: Prefix path: "/" backend: service: name: my-service port: number: 8080 # placing a host in the TLS config will determine what ends up # in the cert's subjectAltNames tls: - hosts: - ingresstest.somedomain.live secretName: application-ingress-cert
The following objects are created on the cluster:
kubectl get ingress -n kube-system NAME CLASS HOSTS ADDRESS PORTS AGE application-ingress nginx ingresstest.somedomain.live 80.158.33.50 80, 443 47s
kubectl get certificate -n kube-system NAME READY SECRET AGE application-ingress-cert True application-ingress-cert 55s
kubectl get secret/application-ingress-cert -n kube-system NAME TYPE DATA AGE application-ingress-cert kubernetes.io/tls 3 87s
Example: Using Let's Encrypt with ACME
This example shows how to use cert-manager with ACME to obtain certificates from Let's Encrypt. The ACME plugin is included in the cert-manager extension.
- Create a new Issuer based on Let's Encrypt:
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-staging namespace: kube-system spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: some.mail@mailprovider.com privateKeySecretRef: name: letsencrypt-staging solvers: - http01: ingress: class: nginx
The ACME plugin can contain more solvers (methods to confirm the owner of the domain). For demonstration purposes the http solver is used.
- Create the Ingress with new Issuer:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: application-ingress namespace: kube-system annotations: cert-manager.io/issuer: letsencrypt-staging acme.cert-manager.io/http01-edit-in-place: "true" spec: ingressClassName: nginx rules: - host: ingresstest.somedomain.live http: paths: - pathType: Prefix path: "/" backend: service: name: my-service port: number: 8080 # placing a host in the TLS config will determine what ends up # in the cert's subjectAltNames tls: - hosts: - ingresstest.somedomain.live secretName: application-ingress-cert
- In addition to the Ingress, a Certificate and 2 Secrets are created
(one containing the private key for certificate
and one with the TLS certificate):
kubectl get ingress -n kube-system NAME CLASS HOSTS ADDRESS PORTS AGE application-ingress nginx ingresstest.somedomain.live 80.158.33.50 80, 443 47s
kubectl get secret application-ingress-cert -n kube-system NAME TYPE DATA AGE application-ingress-cert kubernetes.io/tls 2 7m32s
Warning
The kube-system
namespace is used in both examples.
It is strongly discouraged to use it to deploy application load,
as it is primarily designed for system components of the cluster.
Warning
In the cert-manager extension is not possible to use an user-defined ClusterIssuer due to the s because of system how extension is deployed through the seed cluster. Therefore cluster issuer will fail that he is not able to find certificate which is a base of cluster issuer (he is looking for it in seed cluster).