Kubernetes Gateway API integration with Cert Manager

This article will walk you through the steps to activate Cert Manager with LetsEncrypt certificates for use with the Kubernetes Gateway API resources.

Series - Gateway API

This post is a part of the Gateway API series on Kubito. Make sure you check out the other posts in this series in the menu above.

Building on our previous discussions about establishing the Gateway API with Cilium and its configuration for exposing applications from a Kubernetes cluster, we now turn our focus to integrating Cert Manager with the Gateway API. This step is crucial for terminating SSL directly at the Gateway API level.

In our setup, we will leverage Cert Manager to streamline the generation and automated renewal of SSL certificates for our domains. This setup aligns with our previous work with Cilium and Gateway API resources. Cert Manager not only generates a certificate but also crafts a Kubernetes Secret from it. This secret is subsequently utilized by the previously established Gateway. It handles automatic renewal 15 days prior to expiration, aligning with our preset configuration.

The foundation of Cert Manager’s functionality is a ClusterIssuer resource. This resource demands the staging or production LetsEncrypt server and the API token created by our desired DNS records manager. In this post, we will use Cloudflare in the examples. You should have a Secret ready with the Cloudflare API token. With this resource in place, Cert Manager is empowered to issue certificates across the entire cluster. In our scenario, we’re setting up two distinct ClusterIssuers, one for each of our domain types: .link and .io.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-link
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory # production server
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-link
    solvers:
    - dns01:
        cloudflare:
          email: [email protected]
          apiTokenSecretRef:
            name: cloudflare-api-token-secret # name of cloudflare api token secret
            key: api-token # key of the api token

---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-io
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory # production server
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-io
    solvers:
    - dns01:
        cloudflare:
          email: [email protected]
          apiTokenSecretRef:
            name: cloudflare-api-token-secret # name of cloudflare api token secret
            key: api-token # key of the api token

Now, let’s delve into the specifics of our certificate configurations. We’ve opted for wildcard certificates to ensure that all subdomains are equally secured with valid certificates. Each certificate configuration explicitly references the appropriate ClusterIssuer, ensuring a seamless integration. Additionally, we meticulously set the duration and renewal periods for each certificate. It’s important to note that the names we assign to these certificates are not just labels; they are the key identifiers for the secrets that the Gateway will reference.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-steeris-link
  namespace: common
spec:
  secretName: wildcard-steeris-link # we reference secrets in gateway .link listeners with this
  duration: 2160h0m0s # 90d
  renewBefore: 360h0m0s # 15d
  issuerRef:
    name: letsencrypt-link
    kind: ClusterIssuer
  commonName: "*.example.link"
  dnsNames:
  - "*.example.link"

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-steeris-io
  namespace: common
spec:
  secretName: wildcard-steeris-io # we reference secrets in gateway .io listeners with this
  duration: 2160h0m0s # 90d
  renewBefore: 360h0m0s # 15d
  issuerRef:
    name: letsencrypt-io
    kind: ClusterIssuer
  commonName: "*.example.io"
  dnsNames:
  - "*.example.io"

After generating the certificates, you can simply attach the secret to the HTTPS listeners:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
listeners:
  # HTTPS Listener for example.io
  - name: https-io
    port: 443
    protocol: HTTPS
    hostname: "*.example.io"
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: wildcard-example-io # name of the secret
    allowedRoutes:
      namespaces:
        from: All

Cert Manager is adept at producing TLS certificates specifically for Gateway resources. This capability is used by appending annotations to a Gateway, a process akin to what we undertake when securing Ingress Resources.

Activating the cert-manager feature for GatewayAPI integration involves enabling the GatewayAPI feature gate. For those utilizing Helm, the process is straightforward:

1
2
helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager \
  --set "extraArgs={--feature-gates=ExperimentalGatewayAPISupport=true}"

When configuring cert-manager for a Gateway, the annotations cert-manager.io/issuer or cert-manager.io/cluster-issuer play a pivotal role. They signal cert-manager to initiate the creation of a Certificate specifically for that Gateway. Consider the following scenario, a Gateway configured as below will prompt cert-manager to generate a Certificate named example-com-tls:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: example
  namespace: common
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-io
spec:
  gatewayClassName: cilium
  addresses:
    - value: "10.0.1.250"
  listeners:
    # HTTPS Listener for example.io
    - name: https-io
      port: 443
      protocol: HTTPS
      hostname: "*.example.io"
      tls:
        mode: Terminate
        certificateRefs:
        - kind: Secret
          name: wildcard-example-io
      allowedRoutes:
        namespaces:
          from: All

Shortly after the initial setup, cert-manager springs into action, creating a Certificate. This Certificate bears the name of the Secret, wildcard-example-io, in this instance. Notably, the dnsNames field within the Certificate aligns with the hostname field specified in the Gateway specifications.

This post details integrating Cert Manager with the Gateway API in Kubernetes for efficient SSL termination. It focuses on using Cert Manager for automated SSL certificate generation and renewal, highlighting the configuration of ClusterIssuer resources for domain-specific management. The setup includes creating wildcard certificates for broader security coverage and linking these certificates to the Gateway via Kubernetes secrets. Additionally, the post explores Cert Manager’s capability to generate TLS certificates for Gateway resources using annotations, streamlining certificate management and enhancing security in Kubernetes clusters. This integration exemplifies a seamless and secure approach to SSL certificate management in Kubernetes environments.