Kubernetes Cert-Manager

Komplexität: Hoch
Dauer: 2-3 Stunden Setup
Voraussetzung: Kubernetes 1.25+, Helm

Automatische Zertifikatsverwaltung in Kubernetes mit cert-manager und eigener PKI.


Architektur

flowchart TB subgraph K8S["☸️ KUBERNETES CLUSTER"] subgraph CM["cert-manager"] I[Issuer/ClusterIssuer] C[Certificate] CR[CertificateRequest] end subgraph APP["Anwendung"] P[Pod] S[Secret] ING[Ingress] end C --> CR --> I I --> S S --> P S --> ING end subgraph EXTERNAL["🔐 EXTERNE CA"] CA[Internal CA] V[Vault PKI] LE[Let's Encrypt] end I --> CA I --> V I --> LE style CM fill:#e3f2fd style I fill:#fff3e0


Installation

# Helm Repository hinzufügen
helm repo add jetstack https://charts.jetstack.io
helm repo update
 
# cert-manager installieren
helm install cert-manager jetstack/cert-manager \
    --namespace cert-manager \
    --create-namespace \
    --set installCRDs=true \
    --set prometheus.enabled=true
 
# Installation prüfen
kubectl get pods -n cert-manager

Issuer-Typen

Issuer-Typ Use Case PQ-Support
———————-————
SelfSigned Testing, Bootstrapping Nein
CA Interne PKI Ja (mit WvdS)
Vault HashiCorp Vault PKI Teilweise
ACME Let's Encrypt, öffentliche CAs Nein
Venafi Enterprise PKI Teilweise

ClusterIssuer mit eigener CA

Schritt 1: CA-Secret erstellen

# CA-Zertifikat und Key als Secret
kubectl create secret tls ca-key-pair \
    --cert=intermediate-ca.pem \
    --key=intermediate-ca.key \
    --namespace cert-manager

Oder als YAML:

# ca-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: ca-key-pair
  namespace: cert-manager
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-ca-cert>
  tls.key: <base64-encoded-ca-key>

Schritt 2: ClusterIssuer definieren

# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: internal-ca-issuer
spec:
  ca:
    secretName: ca-key-pair
kubectl apply -f cluster-issuer.yaml
 
# Status prüfen
kubectl get clusterissuer internal-ca-issuer

Certificate-Ressource

# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: app-tls
  namespace: production
spec:
  # Secret, das erstellt wird
  secretName: app-tls-secret
 
  # Gültigkeitsdauer
  duration: 2160h    # 90 Tage
  renewBefore: 360h  # 15 Tage vor Ablauf erneuern
 
  # Subject
  subject:
    organizations:
      - EMSR DATA
  commonName: app.example.com
 
  # Schlüssel-Konfiguration
  privateKey:
    algorithm: ECDSA
    size: 384
    rotationPolicy: Always
 
  # Verwendungszweck
  usages:
    - server auth
    - client auth
 
  # DNS/IP SANs
  dnsNames:
    - app.example.com
    - app.production.svc.cluster.local
  ipAddresses:
    - 10.0.0.100
 
  # Issuer-Referenz
  issuerRef:
    name: internal-ca-issuer
    kind: ClusterIssuer
kubectl apply -f certificate.yaml
 
# Status prüfen
kubectl get certificate -n production
kubectl describe certificate app-tls -n production
 
# Secret anzeigen
kubectl get secret app-tls-secret -n production -o yaml

Ingress-Annotation (automatisch)

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  namespace: production
  annotations:
    # cert-manager erstellt Zertifikat automatisch
    cert-manager.io/cluster-issuer: "internal-ca-issuer"
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: app-ingress-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-service
                port:
                  number: 80

Vault PKI Integration

# vault-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    server: https://vault.example.com
    path: pki/sign/server-role
    caBundle: <base64-encoded-vault-ca>
    auth:
      kubernetes:
        role: cert-manager
        mountPath: /v1/auth/kubernetes
        secretRef:
          name: vault-token
          key: token

Vault-Konfiguration:

# PKI Engine aktivieren
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
 
# Root-CA generieren (oder importieren)
vault write pki/root/generate/internal \
    common_name="Internal Root CA" \
    ttl=87600h
 
# Rolle für cert-manager
vault write pki/roles/server-role \
    allowed_domains="example.com,svc.cluster.local" \
    allow_subdomains=true \
    max_ttl=720h
 
# Kubernetes Auth
vault auth enable kubernetes
vault write auth/kubernetes/config \
    kubernetes_host="https://kubernetes.default.svc"

Monitoring

Prometheus Metrics

# ServiceMonitor für cert-manager
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: cert-manager
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: cert-manager
  endpoints:
    - port: http-metrics

Wichtige Metriken:

Metrik Beschreibung Alert-Schwelle
——–————–—————-
certmanager_certificate_expiration_timestamp_seconds Ablaufzeit < 7 Tage
certmanager_certificate_ready_status Ready-Status != 1
certmanager_certificate_renewal_timestamp_seconds Letzte Erneuerung -

Alert-Rules

# PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: cert-manager-alerts
  namespace: monitoring
spec:
  groups:
    - name: cert-manager
      rules:
        - alert: CertificateExpiringSoon
          expr: |
            certmanager_certificate_expiration_timestamp_seconds - time() < 604800
          for: 1h
          labels:
            severity: warning
          annotations:
            summary: "Zertifikat {{ $labels.name }} läuft in < 7 Tagen ab"

        - alert: CertificateNotReady
          expr: |
            certmanager_certificate_ready_status != 1
          for: 10m
          labels:
            severity: critical
          annotations:
            summary: "Zertifikat {{ $labels.name }} nicht bereit"

Troubleshooting

# Certificate-Status
kubectl get certificate -A
kubectl describe certificate <name> -n <namespace>
 
# CertificateRequest prüfen
kubectl get certificaterequest -A
kubectl describe certificaterequest <name>
 
# cert-manager Logs
kubectl logs -n cert-manager -l app=cert-manager -f
 
# Events
kubectl get events -n cert-manager --sort-by='.lastTimestamp'

Häufige Probleme:

Problem Ursache Lösung
————————–
Issuer not found ClusterIssuer vs. Issuer Kind prüfen
Secret not found CA-Secret nicht erstellt Secret anlegen
Failed to generate CSR Key-Algorithmus Algorithm/Size prüfen
Challenge failed ACME-Problem DNS/HTTP Challenge prüfen

Post-Quantum mit eigener CA

PQ-Zertifikate mit cert-manager:

Cert-manager selbst unterstützt keine PQ-Algorithmen, aber Sie können eine PQ-fähige CA verwenden und die Zertifikate manuell erstellen.

// Kubernetes Secret mit PQ-Zertifikat erstellen
using var intermediate = new X509Certificate2("intermediate.pfx", "password");
 
// CSR aus Kubernetes laden
var csr = CertificateRequest.LoadSigningRequest(csrBytes, HashAlgorithmName.SHA384);
 
// PQ-Hybrid-Zertifikat ausstellen
var cert = csr.Create(
    intermediate,
    DateTimeOffset.UtcNow,
    DateTimeOffset.UtcNow.AddDays(90),
    Guid.NewGuid().ToByteArray(),
    CryptoMode.Hybrid);
 
// Als Kubernetes Secret speichern
var secret = new V1Secret
{
    Metadata = new V1ObjectMeta { Name = "pq-tls-secret" },
    Type = "kubernetes.io/tls",
    Data = new Dictionary<string, byte[]>
    {
        ["tls.crt"] = Encoding.UTF8.GetBytes(cert.ExportCertificatePem()),
        ["tls.key"] = Encoding.UTF8.GetBytes(cert.GetECDsaPrivateKey().ExportPkcs8PrivateKeyPem())
    }
};

Checkliste

# Prüfpunkt
———–
1 cert-manager installiert
2 ClusterIssuer konfiguriert
3 CA-Secret erstellt
4 Test-Certificate funktioniert
5 Prometheus Monitoring aktiv
6 Alerts konfiguriert

Verwandte Dokumentation


« ← CI/CD Code-Signing | → Scheduled Renewal »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: den 29.01.2026 um 15:12