Zertifikate verwalten

Wählen Sie eine Dokumentationsversion aus:

Mit benutzerdefinierten Zertifikatsausstellern können Sie TLS-Zertifikate (Transport Layer Security) in Ihrem Kubernetes-basierten AlloyDB Omni-Datenbankcluster verwalten.

Standardmäßig verwendet der AlloyDB Omni Kubernetes-Operator cert-manager, um für jeden Datenbankcluster einen Satz TLS-Zertifikate bereitzustellen. Neben dem Datenbankserverzertifikat erstellt der Operator auch Zertifikate für Komponenten der Steuerungsebene, um sicherzustellen, dass auch interne Verbindungen sicher sind. Standardmäßig wird jedes Zertifikat von einem Aussteller signiert, der vom Operator verwaltet wird.

Wenn Sie möchten, dass alle Zertifikate, einschließlich der Zertifikate für Komponenten der Steuerungsebene, mit Ihrer eigenen vertrauenswürdigen Root-Zertifizierungsstelle (CA) verkettet werden, können Sie den Operator so konfigurieren, dass er einen Aussteller Ihrer Wahl verwendet. So können Sie alle Zertifikate mit Ihrer eigenen Public-Key-Infrastruktur (PKI) verknüpfen, einschließlich der Zertifikate, die für die Funktionen der Steuerungsebene verwendet werden, ohne die Implementierungsdetails der einzelnen internen Entitäten offenzulegen.

Standardlebensdauer von Zertifikaten

Standardmäßig verwendet der AlloyDB Omni-Operator cert-manager, um TLS-Zertifikate für den Operator, die Steuerungsebene und die Datenbankinstanzen auszustellen und automatisch zu verlängern.

In der folgenden Tabelle sind die Standardgültigkeitsdauern für Zertifikate aufgeführt, die vom AlloyDB Omni-Operator verwaltet werden:

Zertifikatstyp Zertifikatsbeschreibung Secret-Name Namespace Standarddauer
mTLS-Clientzertifikat des Operators Wird vom local-controller-manager-Deployment für Hochverfügbarkeits-Systemdiagnosen und Verbindungen zwischen dem Operator und den Agents der Steuerungsebene verwendet. dbs-al-cert-l2-operator Operator-Namespace 1440h0m0s (60 Tage)
Operator-Webhook-Serverzertifikate Wird von den Webhook-Servern für die Operator-Zulassung verwendet, um benutzerdefinierte Ressourcen zu validieren und zu mutieren. fleet-webhook-server-cert

local-webhook-server-cert
Operator-Namespace 1440h0m0s (60 Tage)
Instanzspezifische Zertifikate für den Agent der Steuerungsebene Wird vom instanzspezifischen Datenbank-Agenten, Knotenmanager und Sicherungs-Daemon für Verbindungen zur Steuerungsebene verwendet. dbs-al-cert-dbd-INSTANCE_ID-DB_CLUSTER_NAME

dbs-al-cert-al-INSTANCE_ID-DB_CLUSTER_NAME-nm

dbs-al-cert-backup-daemon-BACKUP_REPO_NAME
Namespace des Datenbankclusters 1440h0m0s (60 Tage)
Sicherungszertifikate Wird von Sicherungsdiensten für Sicherungs- und Wiederherstellungsverbindungen verwendet. dbs-al-cert-backup-client

dbs-al-cert-backup-client-DATA_PLANE_ISSUER_NAME

dbs-al-cert-backup-server-INSTANCE_ID-DB_CLUSTER_NAME

dbs-al-cert-standby-backup-server-INSTANCE_ID-DB_CLUSTER_NAME
Namespace des Datenbankclusters 1440h0m0s (60 Tage)
Datenbankserverzertifikat Sichert Clientverbindungen der Datenebene zur Datenbankinstanz. dbs-al-cert-DB_CLUSTER_NAME Namespace des Datenbankclusters 87600h0m0s (10 Jahre)
PgBouncer-Authentifizierungsabfragezertifikat Datenbank-Clientzertifikat, das vom PgBouncer-Deployment verwendet wird, um eine Verbindung zur Datenbank herzustellen und Verbindungs-Pooling durchzuführen. Wird nur erstellt, wenn Sie eine PgBouncer-Ressource erstellen. dbs-al-pgb-cert-PGBOUNCER_NAME Namespace des Datenbankclusters 87600h0m0s (10 Jahre)
Vom Operator verwaltete selbstsignierte CA-Zertifikate Root-CA-Zertifikate, die von den standardmäßigen selbst signierten Ausstellern des Operators verwendet werden, um Operator-, Steuerungsebenen-Agent-, Sicherungs- und Datenbankserverzertifikate zu signieren. dbs-al-ca-l2-operator

dbs-al-ca-DB_CLUSTER_NAME

dbs-al-ca-dbd-INSTANCE_ID-DB_CLUSTER_NAME

dbs-al-ca-backup-server

dbs-al-ca-backup-daemon-BACKUP_REPO_NAME
Operator-Namespace und Datenbankcluster-Namespace 87600h0m0s (10 Jahre)

In dieser Tabelle werden die folgenden Platzhalter für die Secret-Namen verwendet:

  • INSTANCE_ID: die vierstellige Kennung, die für die Datenbankinstanz generiert wurde.
  • DB_CLUSTER_NAME: der Name Ihrer DBCluster-Ressource.
  • DATA_PLANE_ISSUER_NAME: der Name des benutzerdefinierten cert-manager-Ausstellers, der in spec.primarySpec.tls.dataPlaneCertIssuer.name konfiguriert ist, falls angegeben.
  • BACKUP_REPO_NAME: der Name Ihrer BackupRepository-Ressource, falls konfiguriert.
  • PGBOUNCER_NAME: der Name Ihrer PgBouncer-Ressource.

Benutzerdefinierte Aussteller konfigurieren

Sie können benutzerdefinierte Zertifikatsaussteller für den Datenbankcluster, den AlloyDB Omni-Operator und PgBouncer konfigurieren.

Wenn Sie einen Zertifikatsaussteller konfigurieren möchten, müssen Sie zuerst einen cert-manager-Aussteller erstellen, der mit der Zertifizierungsstelle verknüpft ist, die Ihre Zertifikate signieren soll. Sie können einen der cert-manager-Ausstellertypen oder einen kompatiblen externen Aussteller verwenden. Der AlloyDB Omni-Operator verweist beim Erstellen von Zertifikaten auf diesen Aussteller.

Benutzerdefinierte cert-manager-Zertifikatsaussteller müssen das Feld ca.crt im generierten Zertifikats-Secret mit dem Zertifikat der Stammzertifizierungsstelle füllen.

Datenbankcluster-Zertifikate

Es gibt zwei Felder in der Datenbankclusterspezifikation, um Zertifikatsaussteller zu konfigurieren:

  • spec.primarySpec.tls.dataPlaneCertIssuer: Ein Verweis auf den cert-manager-Aussteller, der Zertifikate für die Datenebene bereitstellt. Die Aussteller-Zertifizierungsstelle ist diejenige, der der Datenbankclient vertrauen kann, um die Datenbank während einer TLS-Verbindung zu verifizieren.

  • spec.primarySpec.tls.controlPlaneAgentsCertIssuer: ein Verweis auf den cert-manager-Aussteller, der Zertifikate für die Steuerungsebene bereitstellt. Diese Zertifikate werden für interne Verbindungen verwendet.

spec:
  primarySpec:
    tls:
      dataPlaneCertIssuer:
        name: DATA_PLANE_ISSUER_NAME
        kind: DATA_PLANE_ISSUER_KIND
        group: DATA_PLANE_ISSUER_GROUP
      controlPlaneAgentsCertIssuer:
        name: CONTROL_PLANE_ISSUER_NAME
        kind: CONTROL_PLANE_ISSUER_KIND
        group: CONTROL_PLANE_ISSUER_GROUP

Ersetzen Sie Folgendes:

  • DATA_PLANE_ISSUER_NAME: Der Name des cert-manager-Ausstellers, der Zertifikate für die Datenebene bereitstellt, z. B. für den Datenbankserver.

  • DATA_PLANE_ISSUER_KIND: die API-Art des cert-manager-Ausstellers. Die Standardeinstellung ist Issuer.

  • DATA_PLANE_ISSUER_GROUP: die API-Gruppe des Ausstellers. Die Standardeinstellung ist cert-manager.io.

  • CONTROL_PLANE_ISSUER_NAME: der Name des cert-manager-Ausstellers, der Zertifikate der Steuerungsebene für interne Komponenten bereitstellt.

  • CONTROL_PLANE_ISSUER_KIND: die API-Art des cert-manager-Ausstellers. Die Standardeinstellung ist Issuer.

  • CONTROL_PLANE_ISSUER_GROUP: die API-Gruppe des Ausstellers. Die Standardeinstellung ist cert-manager.io.

Operator-Zertifikate

Die Schritte zum Konfigurieren eines cert-manager-Ausstellers für Operatorzertifikate hängen von der Methode ab, die zur Installation des AlloyDB Omni-Operators verwendet wurde.

Mit Helm konfigurieren

Wenn Sie den AlloyDB Omni-Operator zum ersten Mal installieren, verwenden Sie helm install und legen Sie die entsprechenden Werte fest. Dabei wird davon ausgegangen, dass Sie der Anleitung zum Bereitstellen des Operators mit Helm folgen.

helm install alloydbomni-operator alloydbomni-operator-OPERATOR_VERSION.tgz \
--create-namespace \
--namespace alloydb-omni-system \
--set operatorCertIssuer.certManagerIssuerName="OPERATOR_CERT_ISSUER_NAME" \
--set operatorCertIssuer.certManagerIssuerKind="OPERATOR_CERT_ISSUER_KIND" \
--set operatorCertIssuer.certManagerIssuerGroup="OPERATOR_CERT_ISSUER_GROUP" \
--atomic \
--timeout 5m

Wenn der Operator bereits installiert ist und Sie den Zertifikatsaussteller festlegen müssen, verwenden Sie helm upgrade, um die entsprechenden Werte festzulegen:

helm upgrade alloydbomni-operator alloydbomni-operator-OPERATOR_VERSION.tgz \
--create-namespace \
--namespace alloydb-omni-system \
--set operatorCertIssuer.certManagerIssuerName="OPERATOR_CERT_ISSUER_NAME" \
--set operatorCertIssuer.certManagerIssuerKind="OPERATOR_CERT_ISSUER_KIND" \
--set operatorCertIssuer.certManagerIssuerGroup="OPERATOR_CERT_ISSUER_GROUP" \
--atomic \
--timeout 5m

Ersetzen Sie Folgendes:

  • OPERATOR_VERSION: Die Version des AlloyDB Omni-Operators, die installiert werden soll.

  • OPERATOR_CERT_ISSUER_NAME: Der Name des cert-manager-Ausstellers, der das Operatorzertifikat bereitstellt, das für interne Verbindungen verwendet wird.

  • OPERATOR_CERT_ISSUER_KIND: die API-Art des cert-manager-Ausstellers. Die Standardeinstellung ist Issuer.

  • OPERATOR_CERT_ISSUER_GROUP: die API-Gruppe des Ausstellers. Die Standardeinstellung ist cert-manager.io.

Mit Operator Lifecycle Manager konfigurieren

Wenn Sie den Operator Lifecycle Manager (OLM) verwendet haben, um den AlloyDB Omni-Operator zu installieren, können Sie das Feld spec.config.env der Ressource Subscription ändern, um die Umgebungsvariablen CERT_MANAGER_ISSUER_NAME, CERT_MANAGER_ISSUER_KIND und CERT_MANAGER_ISSUER_GROUP des Operators Deployment festzulegen.

spec:
  config:
    env:
    - name: CERT_MANAGER_ISSUER_NAME
      value: OPERATOR_CERT_ISSUER_NAME
    - name: CERT_MANAGER_ISSUER_KIND
      value: OPERATOR_CERT_ISSUER_KIND
    - name: CERT_MANAGER_ISSUER_GROUP
      value: OPERATOR_CERT_ISSUER_GROUP

Ersetzen Sie Folgendes:

  • OPERATOR_CERT_ISSUER_NAME: Der Name des cert-manager-Ausstellers, der das Operatorzertifikat bereitstellt, das für interne Verbindungen verwendet wird.

  • OPERATOR_CERT_ISSUER_KIND: die API-Art des cert-manager-Ausstellers. Die Standardeinstellung ist Issuer.

  • OPERATOR_CERT_ISSUER_GROUP: die API-Gruppe des Ausstellers. Die Standardeinstellung ist cert-manager.io.

PgBouncer-Zertifikate

Zur Unterstützung benutzerdefinierter Aussteller prüft der PgBouncer-Controller das Feld DBCluster spec.primarySpec.tls.dataPlaneCertIssuer und verwendet es, um das PgBouncer-Zertifikat bereitzustellen. Der PgBouncer-Controller verwendet auch die in spec.primarySpec.tls.dataPlaneCertRequest konfigurierten Attribute, um das PgBouncer-Zertifikat bereitzustellen. So wird sichergestellt, dass PgBouncer ein Zertifikat von derselben Zertifizierungsstelle verwendet, das dieselben Attribute wie die Datenbank hat.

Benutzerdefinierte Zertifikatsattribute konfigurieren

Sie können die Attribute der vom Operator generierten TLS-Zertifikate anpassen, z. B. die Zertifikatsdauer, das Verlängerungsfenster, die alternativen Antragstellernamen (SANs), den allgemeinen Namen und die Konfiguration des privaten Schlüssels.

Sie konfigurieren benutzerdefinierte Zertifikatsattribute in Ihrem DBCluster-Manifest:

  • spec.primarySpec.tls.dataPlaneCertRequest: Gibt Attribute für Zertifikate der Datenebene an, einschließlich des pgBackRest-Servers, der PgBouncer-Authentifizierungsabfrage und der Datenbankserverzertifikate.
  • spec.primarySpec.tls.controlPlaneAgentsCertRequest: Gibt Attribute für die Bereitstellung von Zertifikaten für die Steuerungsebene an. Diese Zertifikate werden für interne Verbindungen verwendet.

Zertifikatsanfragen konfigurieren

Geben Sie die Anfrageattribute im folgenden Format an:

spec:
  primarySpec:
    tls:
      dataPlaneCertRequest:
        commonName: DATABASE_COMMON_NAME
        dnsNames:
        - DATABASE_DNS_NAME_1
        - DATABASE_DNS_NAME_2
        duration: DATA_PLANE_DURATION
        renewBefore: DATA_PLANE_RENEW_BEFORE
        privateKey:
          algorithm: DATA_PLANE_ALGORITHM
          size: DATA_PLANE_KEY_SIZE
          rotationPolicy: DATA_PLANE_ROTATION_POLICY
      controlPlaneAgentsCertRequest:
        duration: CONTROL_PLANE_DURATION
        renewBefore: CONTROL_PLANE_RENEW_BEFORE
        privateKey:
          algorithm: CONTROL_PLANE_ALGORITHM
          size: CONTROL_PLANE_KEY_SIZE
          rotationPolicy: CONTROL_PLANE_ROTATION_POLICY

Ersetzen Sie Folgendes:

  • DATABASE_COMMON_NAME: (Optional, nur Datenebene) Der allgemeine Name des Datenbankzertifikats.
  • DATABASE_DNS_NAME_1, DATABASE_DNS_NAME_2: (Optional, nur Datenebene) Eine Liste von Subject Alternative Names (SANs) für das Datenbankzertifikat.
  • DATA_PLANE_DURATION und CONTROL_PLANE_DURATION: die angeforderte Gültigkeitsdauer des Zertifikats als Stringdauer, z. B. 720h0m0s für eine benutzerdefinierte Dauer von 30 Tagen. In jedem Zertifikatsanforderungsblock müssen Sie entweder sowohl duration als auch renewBefore angeben (wobei renewBefore kleiner als duration sein muss) oder beide Felder weglassen. Wenn beide Felder weggelassen werden, beträgt die Standarddauer 1440h0m0s (60 Tage) für Zertifikate der Steuerungsebene und Sicherungszertifikate und 87600h0m0s (10 Jahre) für Zertifikate des Datenbankservers und der PgBouncer-Authentifizierungsabfrage.
  • DATA_PLANE_RENEW_BEFORE und CONTROL_PLANE_RENEW_BEFORE: die Dauer vor dem Ablauf, nach der cert-manager einen Verlängerungsversuch starten muss, z. B. 120h0m0s für fünf Tage vor dem Ablauf. In jedem Zertifikatsanforderungsblock müssen Sie entweder sowohl duration als auch renewBefore angeben (wobei renewBefore kleiner als duration sein muss) oder beide Felder weglassen. Wenn beide Felder weggelassen werden, beträgt das Standardverlängerungsfenster für Zertifikate der Steuerungsebene und Sicherungszertifikate 120h0m0s (fünf Tage) und für Zertifikate des Datenbankservers und der PgBouncer-Authentifizierungsabfrage 1440h0m0s (60 Tage).
  • DATA_PLANE_ALGORITHM und CONTROL_PLANE_ALGORITHM: der Algorithmus für den privaten Schlüssel. Gültige Werte sind RSA, ECDSA und Ed25519.
  • DATA_PLANE_KEY_SIZE und CONTROL_PLANE_KEY_SIZE: die Größe des privaten Schlüssels in Bit. Wenn der Algorithmus RSA ist, sind die gültigen Werte 4096 oder 8192 (Standardwert ist 4096). Wenn der Algorithmus ECDSA ist, sind die gültigen Werte 384 oder 521 (Standardwert ist 384). Wenn der Algorithmus Ed25519 ist, wird die Größe ignoriert.
  • DATA_PLANE_ROTATION_POLICY und CONTROL_PLANE_ROTATION_POLICY: Die Richtlinie, die die Neuerstellung des privaten Schlüssels steuert. Gültige Werte sind Always und Never.

Operator- und Sicherungsclientzertifikate

Wenn Sie Zertifikatsattribute für den Operator und den Sicherungsclient anpassen möchten, die von allen Instanzen in einem Namespace gemeinsam genutzt und nicht von einer Datenbankclusterspezifikation verwaltet werden, ändern Sie die benutzerdefinierten Certificate-Ressourcen. Der Operator behält diese manuellen Änderungen bei.

Zertifikats-Secrets bereinigen

Wenn Sie eine DBCluster-Ressource löschen, löscht der AlloyDB Omni-Operator die zugehörigen Certificate-Ressourcen. cert-manager bereinigt die Zertifikats-Secret-Ressourcen jedoch nicht standardmäßig. Informationen zum Konfigurieren des cert-manager-Controllers, damit Secrets beim Löschen von Zertifikaten bereinigt werden, finden Sie in der cert-manager-Dokumentation unter Secrets beim Löschen von Zertifikaten bereinigen.

Wenn Sie bereits eine DBCluster-Ressource gelöscht haben, ohne die automatische Bereinigung zu konfigurieren, löschen Sie die verbleibenden Zertifikats-Secrets manuell:

kubectl delete secret CERTIFICATE_SECRET_NAME -n NAMESPACE

Ersetzen Sie Folgendes:

  • CERTIFICATE_SECRET_NAME: der Name des zu löschenden Zertifikats-Secrets.
  • NAMESPACE: Der Namespace des Datenbankclusters.

Bestätigen

Führen Sie den folgenden Befehl aus, um zu prüfen, ob der Operator Deployment fehlerfrei ist und die Umgebungsvariablen CERT_MANAGER_ISSUER_NAME, CERT_MANAGER_ISSUER_KIND und CERT_MANAGER_ISSUER_GROUP festgelegt sind:

kubectl get deployments local-controller-manager -n alloydb-omni-system -o yaml

Prüfen Sie mit den folgenden Certificate-Objekten, ob der richtige Aussteller verwendet wird:

kubectl get certificate -n NAMESPACE

Ersetzen Sie NAMESPACE durch den Namespace Ihres Datenbankclusters oder alloydb-omni-system für das Operatorzertifikat.

Prüfen Sie das Feld issuerRef in der Ausgabe für jedes Zertifikat, um sicherzustellen, dass es mit Ihrem benutzerdefinierten Aussteller übereinstimmt.

Ablauf des Operator-Clientzertifikats in Operator-Versionen vor 1.8.2 beheben

In AlloyDB Omni-Operator-Versionen vor 1.8.2 speichert das Deployment local-controller-manager das 60-tägige mTLS-Clientzertifikat dbs-al-cert-l2-operator im Arbeitsspeicher für HA-Systemdiagnoseverbindungen zu Steuerungsebenen-Agents. Obwohl cert-manager das Secret dbs-al-cert-l2-operator fünf Tage vor Ablauf automatisch verlängert, wird das verlängerte Zertifikat erst nach dem Neustart des Operator-Pods vom Deployment local-controller-manager neu geladen. Wenn das im Cache gespeicherte Zertifikat am 60. Tag abläuft, schlagen nachfolgende Wiederverbindungen für die Systemdiagnose mit dem Fehler tls: expired certificate fehl und können ungeplante HA-Failover auslösen.

Um dieses Problem dauerhaft zu beheben, aktualisieren Sie den AlloyDB Omni-Operator auf Version 1.8.2 oder höher.

Wenn Sie nicht sofort ein Upgrade auf die Operator-Version 1.8.2 oder höher ausführen können, rotieren Sie das Secret dbs-al-cert-l2-operator und starten Sie das Deployment local-controller-manager mindestens 10 Tage vor Ablauf des Zertifikats neu. Bei diesem Verfahren werden keine Datenbank-Pods neu gestartet und der Datenbank-Traffic wird nicht unterbrochen.

Hinweis

Prüfen Sie vor dem Ausführen des rotate_cert.sh-Skripts, ob Ihre Umgebung die folgenden Anforderungen erfüllt:

  • Installieren Sie bash, kubectl, openssl und base64 in Ihrem PATH.
  • Konfigurieren Sie den Zugriff auf Ihren Kubernetes-Cluster und legen Sie den aktiven kubectl-Kontext auf den Zielcluster fest. Führen Sie kubectl config current-context aus, um den aktiven Kontext zu bestätigen. Wiederholen Sie diesen Vorgang für jeden Cluster, auf dem eine Operatorversion vor 1.8.2 ausgeführt wird.
  • Prüfen Sie, ob Ihr Konto im Operator-Namespace, der standardmäßig alloydb-omni-system lautet, Berechtigungen für die rollenbasierte Zugriffssteuerung (Role-Based Access Control, RBAC) von Kubernetes hat:
    • get für Certificate-Ressourcen und Pod-Logs
    • get und list für Pod-Ressourcen
    • get und delete für das Secret dbs-al-cert-l2-operator (plus create und patch, um ein gesichertes Secret wiederherzustellen)
    • get und patch im Deployment local-controller-manager
    • delete für CertificateRequest-Ressourcen (zum Wiederherstellen eines gesicherten Secrets)

Operator-Clientzertifikat rotieren

Das Skript rotate_cert.sh unterstützt zwei Modi und ein optionales Namespace-Argument, das standardmäßig auf alloydb-omni-system gesetzt ist:

  • ./rotate_cert.sh check: Führt eine schreibgeschützte Prüfung durch und gibt die folgenden Informationen aus:
    • Aktuelle Seriennummer des Zertifikats und Gültigkeitsdaten
    • Empfohlene Rotationsfrist, 10 Tage vor Ablauf festgelegt
    • local-controller-manager Containerstartzeit
    • In-Memory-Zertifikatsstatus von entweder [OK] oder [WARNING]
    • Ein kubectl-Sicherungsbefehl
  • ./rotate_cert.sh rotate: führt die folgenden Aktionen aus:
    • Löscht das Secret dbs-al-cert-l2-operator
    • Wartet, bis cert-manager eine neue Zertifikatsseriennummer ausstellt und die dbs-al-cert-request-l2-operator-Ressource Certificate aktualisiert.
    • Startet das Deployment local-controller-manager neu
    • Prüft die Logs des neuen Pods und gibt das neue Ablaufdatum aus

So prüfen und rotieren Sie das Operator-Clientzertifikat:

  1. Speichern Sie das folgende Script in einer Datei mit dem Namen rotate_cert.sh und machen Sie die Datei ausführbar:

    cat << 'EOF' > rotate_cert.sh
    #!/usr/bin/env bash
    set -euo pipefail
    MODE="${1:-}"
    NS="${2:-alloydb-omni-system}"
    SECRET="dbs-al-cert-l2-operator"
    CERT="dbs-al-cert-request-l2-operator"
    DEPLOY="local-controller-manager"
    get_cert_info() {
      kubectl get secret "$SECRET" -n "$NS" -o jsonpath='{.data.tls\.crt}' 2>/dev/null \
        | base64 -d 2>/dev/null | openssl x509 -noout -serial -enddate 2>/dev/null || true
    }
    calc_rotate_by() {
      date -u -d "$1 - 10 days" +"%Y-%m-%d" 2>/dev/null \
        || date -u -j -v-10d -f "%Y-%m-%dT%H:%M:%SZ" "$1" +"%Y-%m-%d" 2>/dev/null || echo "unknown"
    }
    get_container_name() {
      local names
      names="$(kubectl get pods -n "$NS" -l local-control-plane=controller-manager \
        --field-selector=status.phase=Running --sort-by=.metadata.creationTimestamp \
        -o jsonpath='{.items[-1].spec.containers[*].name}' 2>/dev/null || true)"
      if [[ " $names " == *" local-manager "* ]]; then
        echo "local-manager"
      else
        echo "manager"
      fi
    }
    case "$MODE" in
      check)
        INFO="$(get_cert_info)"
        SERIAL="$(echo "$INFO" | sed -n 's/^serial=//p')"
        ENDDATE="$(echo "$INFO" | sed -n 's/^notAfter=//p')"
        NOT_BEFORE="$(kubectl get certificate "$CERT" -n "$NS" -o jsonpath='{.status.notBefore}')"
        NOT_AFTER="$(kubectl get certificate "$CERT" -n "$NS" -o jsonpath='{.status.notAfter}')"
        CONTAINER="$(get_container_name)"
        STARTED_AT="$(kubectl get pods -n "$NS" -l local-control-plane=controller-manager \
          --field-selector=status.phase=Running --sort-by=.metadata.creationTimestamp \
          -o jsonpath="{.items[-1].status.containerStatuses[?(@.name==\"$CONTAINER\")].state.running.startedAt}")"
        echo "Certificate Serial      : $SERIAL"
        echo "Certificate Start Date  : $NOT_BEFORE"
        echo "Certificate End Date    : $ENDDATE ($NOT_AFTER)"
        echo "Recommended Rotate By   : $(calc_rotate_by "$NOT_AFTER") (10 days before expiry)"
        echo "Operator Started At     : $STARTED_AT"
        if [[ "$STARTED_AT" < "$NOT_BEFORE" ]]; then
          echo "[WARNING] Operator started ($STARTED_AT) BEFORE current cert was issued ($NOT_BEFORE). It is still caching the old cert in memory! Run './rotate_cert.sh rotate $NS' now."
        else
          echo "[OK] Operator is running with the current certificate in memory."
        fi
        echo "Optional Backup Command : kubectl get secret $SECRET -n $NS -o yaml > $SECRET-backup.yaml"
        ;;
      rotate)
        OLD_SERIAL="$(get_cert_info | sed -n 's/^serial=//p')"
        OLD_REV="$(kubectl get certificate "$CERT" -n "$NS" -o jsonpath='{.status.revision}' 2>/dev/null || true)"
        echo "Current Certificate Serial: ${OLD_SERIAL:-none}"
        kubectl delete secret "$SECRET" -n "$NS" --ignore-not-found
        NEW_SERIAL=""
        NOT_AFTER=""
        for _ in {1..30}; do
          sleep 2
          NEW_SERIAL="$(get_cert_info | sed -n 's/^serial=//p')"
          NEW_REV="$(kubectl get certificate "$CERT" -n "$NS" -o jsonpath='{.status.revision}' 2>/dev/null || true)"
          READY_COND="$(kubectl get certificate "$CERT" -n "$NS" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || true)"
          NOT_AFTER="$(kubectl get certificate "$CERT" -n "$NS" -o jsonpath='{.status.notAfter}' 2>/dev/null || true)"
          [[ -n "$NEW_SERIAL" && "$NEW_SERIAL" != "$OLD_SERIAL" && "$NEW_REV" != "$OLD_REV" && "$READY_COND" == "True" && -n "$NOT_AFTER" ]] && break
        done
        [[ -n "$NEW_SERIAL" && "$NEW_SERIAL" != "$OLD_SERIAL" && "$READY_COND" == "True" ]] || { echo "[ERROR] Timed out waiting for new cert."; exit 1; }
        kubectl rollout restart "deployment/$DEPLOY" -n "$NS"
        kubectl rollout status "deployment/$DEPLOY" -n "$NS" --timeout=180s
        NEW_POD="$(kubectl get pods -n "$NS" -l local-control-plane=controller-manager \
          --field-selector=status.phase=Running --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1].metadata.name}')"
        CONTAINER="$(get_container_name)"
        READY=false
        for _ in {1..40}; do
          LOGS="$(kubectl logs "pod/$NEW_POD" -n "$NS" -c "$CONTAINER" 2>/dev/null || true)"
          grep -q "tls: expired certificate" <<<"$LOGS" && { echo "[ERROR] Found 'tls: expired certificate' in operator logs!"; exit 1; }
          grep -q "L2 controller cert generation completed successfully" <<<"$LOGS" && { READY=true; break; }
          sleep 3
        done
        [[ "$READY" == "true" ]] || { echo "[ERROR] Timed out waiting for L2 controller cert generation log."; exit 1; }
        echo "[SUCCESS] New Serial: $NEW_SERIAL | End Date: $NOT_AFTER | Next Rotate By: $(calc_rotate_by "$NOT_AFTER") (10 days before expiry)"
        ;;
      *)
        echo "Usage: $0 <check|rotate> [namespace]"
        echo "  check       : Validate current certificate status and operator start time."
        echo "  rotate      : Trigger immediate certificate rotation and restart the operator."
        echo "  [namespace] : Namespace of the operator (defaults to 'alloydb-omni-system')."
        exit 1 ;;
    esac
    EOF
    chmod +x rotate_cert.sh
    
  2. Führen Sie das Skript rotate_cert.sh im Modus check aus, um das aktuelle Ablaufdatum des Zertifikats, das empfohlene Rotationsdatum und den In-Memory-Status des Operators zu prüfen:

    ./rotate_cert.sh check
    
  3. Optional: Sichern Sie das Secret dbs-al-cert-l2-operator, bevor Sie das Zertifikat rotieren:

    kubectl get secret dbs-al-cert-l2-operator -n alloydb-omni-system \
      -o yaml > dbs-al-cert-l2-operator-backup.yaml
    
  4. Wenn in der Ausgabe für check [WARNING] angezeigt wird oder das aktuelle Datum am oder vor dem Recommended Rotate By-Datum liegt, führen Sie das Skript rotate_cert.sh im Modus rotate aus:

    ./rotate_cert.sh rotate
    

    Prüfen Sie, ob die Ausgabe mit [SUCCESS] endet und die neue Zertifikatsseriennummer, das Ablaufdatum und das nächste empfohlene Rotationsdatum angezeigt werden. Wenn in der Ausgabe [ERROR] angezeigt wird oder das Script mit einem Status ungleich null beendet wird, führen Sie ./rotate_cert.sh check noch einmal aus und prüfen Sie die Operatorlogs mit kubectl logs deployment/local-controller-manager -n alloydb-omni-system -c local-manager (oder -c manager in Operatorversionen vor 1.6.0).

  5. Optional: Wenn Sie in Schritt 3 eine Sicherungsdatei erstellt haben, löschen Sie die lokale Sicherungsdatei, nachdem Sie bestätigt haben, dass die Rotation erfolgreich war, da die Datei den alten privaten Schlüssel enthält:

    rm -f dbs-al-cert-l2-operator-backup.yaml
    

Gesichertes Zertifikat wiederherstellen

Wenn cert-manager während der Rotation kein neues Zertifikat ausstellen kann und Sie ein Rollback zu einer nicht abgelaufenen dbs-al-cert-l2-operator-backup.yaml-Datei durchführen müssen, gehen Sie so vor:

  1. Löschen Sie die ausstehende oder fehlgeschlagene CertificateRequest-Ressource für das dbs-al-cert-request-l2-operator-Zertifikat, damit cert-manager den wiederhergestellten privaten Schlüssel nicht mit dem Grund SecretMismatch ablehnt und das wiederhergestellte Secret überschreibt:

    REV="$(kubectl get certificate dbs-al-cert-request-l2-operator -n alloydb-omni-system -o jsonpath='{.status.revision}')"
    kubectl delete certificaterequest \
      "dbs-al-cert-request-l2-operator-$((REV + 1))" \
      -n alloydb-omni-system --ignore-not-found
    
  2. Entfernen Sie die Felder metadata.resourceVersion und metadata.uid auf oberster Ebene aus der Datei dbs-al-cert-l2-operator-backup.yaml und wenden Sie das Secret mit der serverseitigen Anwendung an:

    grep -vE '^  (resourceVersion|uid):' dbs-al-cert-l2-operator-backup.yaml \
      | kubectl apply --server-side --force-conflicts -f -
    
  3. Starten Sie das Deployment local-controller-manager neu, um das wiederhergestellte Zertifikat in den Arbeitsspeicher zu laden:

    kubectl rollout restart deployment/local-controller-manager -n alloydb-omni-system
    kubectl rollout status deployment/local-controller-manager -n alloydb-omni-system --timeout=180s
    
  4. Führen Sie das Skript rotate_cert.sh im Modus check aus, um zu prüfen, ob der Wert Certificate Serial mit der Seriennummer des gesicherten Zertifikats übereinstimmt und ob das Skript [OK] meldet:

    ./rotate_cert.sh check
    

    Das wiederhergestellte Zertifikat behält sein ursprüngliches Ablaufdatum. Sie müssen das Zertifikat also weiterhin am oder vor dem Recommended Rotate By-Datum rotieren.

  5. Löschen Sie die lokale Sicherungsdatei, nachdem Sie die Wiederherstellung bestätigt haben:

    rm -f dbs-al-cert-l2-operator-backup.yaml