6 minute read  

Gardener Certificate Management

Introduction

Gardener comes with an extension that enables shoot owners to request X.509 compliant certificates for shoot domains.

Extension Installation

The shoot-cert-service extension can be deployed and configured via Gardener’s native resource ControllerRegistration.

Prerequisites

To let the shoot-cert-service operate properly, you need to have:

Operator Extension

Using an operator extension resource (extension.operator.gardener.cloud) is the recommended way to deploy the shoot-cert-service extension.

An example of an operator extension resource can be found at extension-shoot-cert-service.yaml.

The ControllerRegistration contains a reference to the Helm chart which eventually deploy the shoot-cert-service to seed clusters. It offers some configuration options, mainly to set up a default issuer for shoot clusters. With a default issuer, pre-existing Let’s Encrypt accounts can be used and shared with shoot clusters (See Integration Guide - One Account or Many?).

lightbulb-on-outline

Tip

Please keep the Let’s Encrypt Rate Limits in mind when using this shared account model. Depending on the amount of shoots and domains it is recommended to use an account with increased rate limits.

apiVersion: operator.gardener.cloud/v1alpha1
kind: Extension
metadata:
  annotations:
    security.gardener.cloud/pod-security-enforce: baseline
  name: extension-shoot-cert-service
spec:
  deployment:
    extension:
      helm:
        ociRepository:
          ref: ... # OCI reference to the Helm chart
      injectGardenKubeconfig: true
      policy: Always

      values:
        certificateConfig:
          defaultIssuer:
            name: default-issuer
            acme:
              email: some.user@example.com
              # optional private key for the Let's Encrypt account
              #privateKey: |-
              #-----BEGIN RSA PRIVATE KEY-----
              #...
              #-----END RSA PRIVATE KEY-----
              server: https://acme-v02.api.letsencrypt.org/directory
            # altenatively to `acme`, you can use a self-signed root or intermediate certificate for providing self-signed certificates
#           ca:
#             certificate: |
#               -----BEGIN CERTIFICATE-----
#               ...
#               -----END CERTIFICATE-----
#             certificateKey: |
#               -----BEGIN PRIVATE KEY-----
#               ...
#               -----END PRIVATE KEY-----

#          defaultRequestsPerDayQuota: 50

#          precheckNameservers: 8.8.8.8,8.8.4.4

#          caCertificates: | # optional custom CA certificates when using private ACME provider
#            -----BEGIN CERTIFICATE-----
#            ...
#            -----END CERTIFICATE-----
#            -----BEGIN CERTIFICATE-----
#            ...
#            -----END CERTIFICATE-----

        shootIssuers:
          enabled: false # if true, allows specifying issuers in the shoot clusters

        deactivateAuthorizations: true # if true, enables flag --acme-deactivate-authorizations in cert-controller-manager
        skipDNSChallengeValidation: false # if true, skips dns-challenges in cert-controller-manager

      # The following values are only needed if the extension should be deployed on the runtime cluster. 
      runtimeClusterValues:
        certificateConfig:
          defaultIssuer:
            # typically the same values as at .spec.deployment.values.certificateConfig.defaultIssuer
            ...
  resources:
  - globallyEnabled: true # if true, the extension is enabled for all shoots by default
    kind: Extension
    type: shoot-cert-service
    workerlessSupported: true

Providing Trusted TLS Certificate for Garden Runtime Cluster

The shoot-cert-service can provide the TLS secret labeled with gardener.cloud/role: garden-cert in the garden namespace to be used by the Gardener API server. See Trusted TLS Certificate for Garden Runtime Cluster for more information.

For this purpose, the extension must be deployed on the runtime cluster. Several configuration steps are needed:

  1. Provide the spec.runtimeClusterValues values in the extension.operator.gardener.cloud resource in the operator extension.
  2. Add the extension to the Garden resource on the Garden runtime cluster.
    apiVersion: operator.gardener.cloud/v1alpha1
    kind: Garden
    metadata:
      name: ...
    spec:
      extensions:
      - type: shoot-cert-service
        providerConfig:
          apiVersion: service.cert.extensions.gardener.cloud/v1alpha1
          kind: CertConfig
          generateControlPlaneCertificate: true
    

If you only want to deploy the cert-controller-manager in the garden namespace, you can set generateControlPlaneCertificate to false.

If generateControlPlaneCertificate is set to true, the current values spec.virtualCluster.dns.domains and spec.runtimeCluster.ingress.domains from the Garden resource are read, and the certificate is created/updated in the garden namespace. The certificate will be reconciled by the cert-controller-manager to provide the TLS secret with the label gardener.cloud/role: garden-cert in the garden namespace. Additionally, the extension provides a webhook to mutate the virtual-garden-kube-apiserver deployment in the garden namespace. It will manage the --tls-sni-cert-key command line arguments and patches the volume/volume mount with the TLS secret. Only the secondary domain names will be used for the SNI certificate, as the self-signed certificate of the first domain name is provided by the Gardener operator.

Example for resulting domains of the certificate

If the Garden resource contains the following values:

apiVersion: operator.gardener.cloud/v1alpha1
kind: Garden
spec:
  runtimeCluster:
    ingress:
      domains:
      - name: "ingress.garden.example.com"
        provider: gardener-dns
  virtualCluster:
    dns:
      domains:
      - name: "primary.garden.example.com"
        provider: gardener-dns
      - name: "secondary.foo.example.com"
        provider: gardener-dns

then the Certificate will be created with these wildcard domain names:

  • *.primary.garden.example.com
  • *.secondary.foo.example.com
  • *.ingress.garden.example.com

Providing Trusted TLS Certificate for Shoot Control Planes

The shoot-cert-service can provide the TLS secret labeled with gardener.cloud/role: controlplane-cert in the garden namespace on the seeds. See Trusted TLS Certificate for Shoot Control Planes for more information.

For this purpose, the extension must be enabled for the seed(s) by adding the shoot-cert-service to the Seed manifest:

apiVersion: core.gardener.cloud/v1beta1
kind: Seed
metadata:
  name: ...
spec:
  extensions:
  - type: shoot-cert-service
    providerConfig:
      apiVersion: service.cert.extensions.gardener.cloud/v1alpha1
      kind: CertConfig
      generateControlPlaneCertificate: true

The certificate will contain the wildcard domain name using the base domain name from the .spec.ingress.domain value of the Seed resource.

ControllerRegistration

information-outline

Note

Using a ControllerRegistration / ControllerDeployment directly is not recommended if your Gardener landscape has a virtual Garden cluster. In this case, please use an extension.operator.gardener.cloud resource as described above. The Gardener operator will then take care of the ControllerRegistration and ControllerDeployment for you.

An example of a ControllerRegistration for the shoot-cert-service can be found at controller-registration.yaml.

The ControllerRegistration contains a Helm chart which eventually deploy the shoot-cert-service to seed clusters. It offers some configuration options, mainly to set up a default issuer for shoot clusters. With a default issuer, pre-existing Let’s Encrypt accounts can be used and shared with shoot clusters (See “One Account or Many?” of the Integration Guide).

Please keep the Let’s Encrypt Rate Limits in mind when using this shared account model. Depending on the amount of shoots and domains it is recommended to use an account with increased rate limits.

apiVersion: core.gardener.cloud/v1beta1
kind: ControllerRegistration
...
  values:
    certificateConfig:
      defaultIssuer:
        acme:
            email: foo@example.com
            privateKey: |-
              -----BEGIN RSA PRIVATE KEY-----
              ...
              -----END RSA PRIVATE KEY-----              
            server: https://acme-v02.api.letsencrypt.org/directory
        name: default-issuer
#       restricted: true # restrict default issuer to any sub-domain of shoot.spec.dns.domain

#     defaultRequestsPerDayQuota: 50

#     precheckNameservers: 8.8.8.8,8.8.4.4

#     caCertificates: | # optional custom CA certificates when using private ACME provider
#     -----BEGIN CERTIFICATE-----
#     ...
#     -----END CERTIFICATE-----
#
#     -----BEGIN CERTIFICATE-----
#     ...
#     -----END CERTIFICATE-----

      shootIssuers:
        enabled: false # if true, allows to specify issuers in the shoot clusters

Enablement

If the shoot-cert-service should be enabled for every shoot cluster in your Gardener managed environment, you need to globally enable it in the ControllerRegistration:

apiVersion: core.gardener.cloud/v1beta1
kind: ControllerRegistration
...
  resources:
  - globallyEnabled: true
    kind: Extension
    type: shoot-cert-service

Alternatively, you’re given the option to only enable the service for certain shoots:

kind: Shoot
apiVersion: core.gardener.cloud/v1beta1
...
spec:
  extensions:
  - type: shoot-cert-service
...