Cert-Manager integration

The Cert-Manager backend is experimental, and subject to change.

Cert-Manager is a common tool to manage certificates in Kubernetes, especially when backed by an external Certificate Authority (CA) such as Let's Encrypt.

The Stackable Secret Operator supports requesting certificates from Cert-Manager.

Caveats

Cert-Manager is designed to manage relatively long-lived certificates that are stored in Kubernetes Secrets. By contrast, the Stackable Secret Operator is designed to generate temporary short-lived certificates.

This has a couple of repercussions:

  • Longer-lived certificates mean that a leaked certificate has potential to be abused for longer.

  • Application teams may have access to read Secrets in their respective applications' Namespaces.

Where possible, it is recommended using the autoTls backend instead.

Configuring Cert-Manager

Using the autoTls backend instead for self-signed PKIs is recommended. The Cert-Manager’s CA issuer is used in these examples to illustrate the broader concepts.

To do this, you will first need to teach Cert-Manager how to create your certificates.

In a production setup this will likely use an external CA such as ACME or OpenBao/Vault. However, to make this guide self-contained, Cert-Manager will create a self-signed CA certificate instead.

---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: secret-operator-demonstration (1)
spec:
  ca:
    secretName: secret-operator-demonstration-ca
# Create a self-signed CA for secret-operator-demonstration to use
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: secret-operator-demonstration-ca
spec:
  secretName: secret-operator-demonstration-ca
  isCA: true
  commonName: Stackable Secret Operator/Cert-Manager Demonstration CA
  issuerRef:
    kind: Issuer
    name: secret-operator-demonstration-ca
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: secret-operator-demonstration-ca
spec:
  selfSigned: {}
1 This is the Issuer that our created certificates will reference later

Creating a SecretClass

The Stackable Secret Operator needs to know how to request the certificates from Cert-Manager. Do this by creating a SecretClass using the experimentalCertManager backend.

---
apiVersion: secrets.stackable.tech/v1alpha1
kind: SecretClass
metadata:
  name: tls-cert-manager (1)
spec:
  backend:
    experimentalCertManager:
      issuer:
        kind: Issuer (2)
        name: secret-operator-demonstration (3)
1 Both certificates and Pods will reference this name, to ensure that the correct certificates are found
2 This guide uses a namespaced Issuer, rather than a cluster-scoped ClusterIssuer
3 The Cert-Manager Issuer that should sign these certificates, as created before

Using the certificate

Finally, you can create and expose a Pod that requests and uses the certificate!

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - name: tls
              mountPath: /tls
            - name: config
              mountPath: /etc/nginx/conf.d
          ports:
            - name: https
              containerPort: 443
      volumes:
        - name: tls (1)
          ephemeral:
            volumeClaimTemplate:
              metadata:
                annotations:
                  secrets.stackable.tech/class: tls-cert-manager (2)
                  secrets.stackable.tech/scope: node,service=my-app (3)
              spec:
                storageClassName: secrets.stackable.tech
                accessModes:
                  - ReadWriteOnce
                resources:
                  requests:
                    storage: "1"
        - name: config
          configMap:
            name: my-app
--- (4)
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app
data:
  default.conf: |
    server {
        listen 443 ssl;
        ssl_certificate /tls/tls.crt;
        ssl_certificate_key /tls/tls.key;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
--- (5)
apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  selector:
    app: my-app
  ports:
    - name: https
      port: 443
1 A secret volume is created, where the certificate will be exposed to the app
2 The volume references the SecretClass defined before
3 The app requires the certificate to be valid for the scopes node and service=my-app
4 nginx is configured to use the mounted certificate
5 nginx is exposed as a Kubernetes Service