BLOG | NGINX

Aktivieren der Self-Service-DNS- und Zertifikatsverwaltung in Kubernetes

Jason Schmidt Miniaturbild
Jason Schmidt
Veröffentlicht am 01. November 2022

Das ultimative Ziel der Anwendungsentwicklung besteht natürlich darin, Apps im Internet verfügbar zu machen. Für einen Entwickler vereinfacht Kubernetes diesen Prozess bis zu einem gewissen Grad, indem es den Ingress-Controller als Mechanismus zum Weiterleiten von Anforderungen an die Anwendung bereitstellt. Allerdings ist nicht alles so selbstbedienbar, wie Sie es sich wahrscheinlich wünschen: Sie benötigen weiterhin einen Eintrag im Domain Name System (DNS), um den Domänennamen für die App der IP-Adresse des Ingress-Controllers zuzuordnen, und ein TLS-Zertifikat, um Verbindungen mit HTTPS zu sichern. In den meisten Organisationen besitzen Sie DNS oder TLS nicht selbst und müssen sich daher mit der (oder den) operativen Gruppe(n!) abstimmen, die darüber verfügen.

Für die Betreiber wird es dadurch nicht unbedingt einfacher. In den meisten Organisationen ist die Notwendigkeit zur Aktualisierung von DNS-Einträgen so selten, dass entsprechende Verfahren – sowohl Geschäftsregeln als auch die eigentlichen technischen Schritte – eher spärlich oder gar nicht vorhanden sind. Dies bedeutet, dass Sie, wenn Sie einen DNS-Eintrag hinzufügen müssen, zuerst die Dokumentation suchen, einen Kollegen fragen oder (im schlimmsten Fall) es selbst herausfinden müssen. Sie müssen außerdem sicherstellen, dass Sie sämtliche Sicherheitsregeln des Unternehmens einhalten und dass der eingehende Datenverkehr für die Firewalls ordnungsgemäß gekennzeichnet ist.

Glücklicherweise gibt es eine Möglichkeit, sowohl Entwicklern als auch Betreibern das Leben zu erleichtern. In diesem Beitrag zeigen wir, wie Betreiber eine Kubernetes-Bereitstellung konfigurieren können, um Entwicklern die Aktualisierung von DNS-Einträgen und die Generierung von TLS-Zertifikaten in einer Kubernetes-Umgebung im Self-Service zu ermöglichen. Indem Sie die Infrastruktur frühzeitig ausbauen, können Sie sicherstellen, dass alle notwendigen geschäftlichen und technischen Anforderungen erfüllt werden.

Überblick und Voraussetzungen

Wenn die Lösung vorhanden ist, muss ein Entwickler, um eine Anwendung im Internet verfügbar zu machen, lediglich einen Ingress-Controller gemäß einer bereitgestellten Vorlage erstellen, die einen vollqualifizierten Domänennamen (FQDN) innerhalb einer von der Kubernetes-Installation verwalteten Domäne enthält. Kubernetes verwendet die Vorlage, um dem Ingress-Controller eine IP-Adresse zuzuweisen, den DNS- A -Eintrag zu erstellen, um den FQDN der IP-Adresse zuzuordnen, TLS-Zertifikate für den FQDN zu generieren und sie dem Ingress-Controller hinzuzufügen. Die Bereinigung ist ebenso einfach: Wenn der Ingress entfernt wird, werden die DNS-Einträge bereinigt.

Die Lösung nutzt die folgenden Technologien (Anweisungen zur Installation und Konfiguration finden Sie weiter unten):

Bevor Sie die Lösung konfigurieren, benötigen Sie:

  • Eine Kubernetes-Cloud-Installation mit einem Egress-Objekt ( LoadBalancer ). Die Lösung verwendet Linode, aber auch andere Cloud-Anbieter funktionieren.
  • Ein bei Cloudflare gehosteter Domänenname, den wir ausgewählt haben, weil es einer der unterstützten DNS-Anbieter für Cert-Manager ist und ExternalDNS unterstützt (zum Zeitpunkt des Schreibens in der Beta -Version). Wir empfehlen dringend, die Domäne nicht für Produktions- oder andere kritische Zwecke zu verwenden.
  • Zugriff auf die Cloudflare-API, die im kostenlosen Kontingent enthalten ist.
  • Helm zum Installieren und Bereitstellen von Kubernetes.
  • kubectl als Befehlszeilenschnittstelle für Kubernetes.
  • Optional: K9s , eine gut konstruierte greifbare Benutzeroberfläche (TUI), die eine strukturiertere Möglichkeit zur Interaktion mit Kubernetes bietet.

Wir setzen außerdem voraus, dass Sie über grundlegende Kenntnisse von Kubernetes verfügen (wie Sie ein Manifest anwenden, ein Helm-Diagramm verwenden und kubectl -Befehle ausgeben, um die Ausgabe anzuzeigen und Probleme zu beheben). Das Verständnis der grundlegenden Konzepte von Let‘s Encrypt ist hilfreich, aber nicht erforderlich; einen Überblick finden Sie in unserem Blog . Sie müssen auch nicht wissen, wie der Cert-Manager funktioniert, aber wenn Sie daran interessiert sind, wie er (und Zertifikate im Allgemeinen) mit dem NGINX Ingress Controller funktionieren, lesen Sie meinen neuesten Beitrag „Automatisierung der Zertifikatsverwaltung in einer Kubernetes-Umgebung “.

Wir haben die Lösung sowohl auf macOS als auch auf Linux getestet. Wir haben es nicht auf dem Windows-Subsystem für Linux Version 2 (WSL2) getestet, erwarten aber keine Probleme.

Notiz: Die Lösung ist als Beispiel für einen Proof of Concept gedacht und nicht für den Produktionseinsatz. Insbesondere berücksichtigt es nicht alle Best Practices für Betrieb und Sicherheit. Informationen zu diesen Themen finden Sie in der Cert-Manager- und ExternalDNS -Dokumentation.

Bereitstellen der Lösung

Befolgen Sie die Schritte in diesen Abschnitten, um die Lösung bereitzustellen:

Software herunterladen
  1. Laden Sie Ihr Cloudflare API-Token herunter.
  2. Klonen Sie das NGINX Ingress Controller-Repository:

    $ git clone https://github.com/nginxinc/kubernetes-ingress.gitCloning into 'kubernetes-ingress'...
    remote: Enumerating objects: 45176, done.
    remote: Counting objects: 100% (373/373), done.
    remote: Compressing objects: 100% (274/274), done.
    remote: Total 45176 (delta 173), reused 219 (delta 79), pack-reused 44803
    Receiving objects: 100% (45176/45176), 60.45 MiB | 26.81 MiB/s, done.
    Resolving deltas: 100% (26592/26592), done.
  3. Überprüfen Sie, ob Sie eine Verbindung zum Kubernetes-Cluster herstellen können.

    $ kubectl cluster-infoKubernetes control plane is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443
    KubeDNS is running at https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
     
    To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Bereitstellen des NGINX Ingress Controllers

  1. Stellen Sie mit Helm den NGINX Ingress Controller bereit. Beachten Sie, dass wir drei nicht standardmäßige Konfigurationsoptionen hinzufügen:

    • controller.enableCustomResources – Fordert Helm auf, die benutzerdefinierten Ressourcendefinitionen (CRDs) zu installieren, mit denen Sie die NGINX VirtualServer und VirtualServerRoute Custom Resources anlegen.
    • controller.enableCertManager – Konfiguriert den NGINX Ingress Controller für die Kommunikation mit Cert-Manager -Komponenten.
    • controller.enableExternalDNS – Konfiguriert den Ingress Controller für die Kommunikation mit ExternalDNS-Komponenten.
    $ helm install nginx-kic nginx-stable/nginx-ingress --namespace nginx-ingress  --set controller.enableCustomResources=true --create-namespace  --set controller.enableCertManager=true --set controller.enableExternalDNS=trueNAME: nginx-kic
    LAST DEPLOYED: Day Mon  DD hh:mm:ss YYYY
    NAMESPACE: nginx-ingress
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    The NGINX Ingress Controller has been installed.
  2. Überprüfen Sie, ob der NGINX Ingress Controller ausgeführt wird, und notieren Sie sich den Wert im Feld „EXTERNAL-IP“ . Dies ist die IP-Adresse für den NGINX Ingress Controller (hier: www.xxx.yyy.zzz ). Die Ausgabe ist der Lesbarkeit halber auf zwei Zeilen verteilt.

    $ kubectl get services --namespace nginx-ingressNAME                      TYPE           CLUSTER-IP      ...
    nginx-kic-nginx-ingress   LoadBalancer   10.128.152.88   ... 
    
       ... EXTERNAL-IP       PORT(S)                      AGE
       ... www.xxx.yyy.zzz   80:32457/TCP,443:31971/TCP   3h8m

Bereitstellen des Zertifikatmanagers

In der Lösung verwendet cert-manager beim Abrufen eines TLS-Zertifikats den Challenge-Typ DNS-01 und verlangt, dass Sie bei der Erstellung der ClusterIssuer-Ressource das Cloudflare-API-Token bereitstellen. Das API-Token wird dabei als Kubernetes-Secret hinterlegt.

  1. Stellen Sie mit Helm den Cert-Manager bereit :

    $ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1  --set installCRDs=trueNAME: cert-manager
    LAST DEPLOYED: Day Mon  DD hh:mm:ss YYYY
    NAMESPACE: cert-manager
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    NOTES:
    cert-manager v1.9.1 has been deployed successfully!
  2. Stellen Sie das Cloudflare-API-Token als Kubernetes-Geheimnis bereit und ersetzen Sie es durch <Ihr API-Token>:

    $ kubectl apply -f - <<EOFapiVersion: v1
    kind: Secret
    metadata:
      name: Cloudflare-api-token-secret
      namespace: cert-manager
    type: Opaque
    stringData:
      api-token: "<your-API-token>"
    EOF
    secret/Cloudflare-api-token-secret created
  3. Erstellen Sie ein ClusterIssuer-Objekt und geben Sie Cloudflare-api-token-secret (im vorherigen Schritt definiert) als Ort zum Abrufen des Tokens an. Wenn Sie möchten, können Sie „example-issuer“ im Feld „metadata.name“ (und „example-issuer-account-key“ im Feld „spec.acme.privateKeySecretRef.name“ ) durch einen anderen Namen ersetzen.

    $ kubectl apply -f - <<EOFapiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: example-issuer
      namespace: cert-manager
    spec:
      acme:
        email: example@example.com
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: example-issuer-account-key
        solvers:
          - dns01:
              Cloudflare:
                apiTokenSecretRef:
                  name: Cloudflare-api-token-secret
                  key: api-token
    EOF
    clusterissuer.cert-manager.io/example-issuer created
  4. Überprüfen Sie, ob der ClusterIssuer bereitgestellt und bereit ist (der Wert im Feld READY ist True ).

    $ kubectl get clusterissuerNAME             READY   AGE
    example-issuer   True    3h9m

ExternalDNS bereitstellen

Wie cert-manager erfordert das ExternalDNS-Projekt ein Cloudflare-API-Token zur Verwaltung von DNS. Derselbe Token kann für beide Projekte verwendet werden, das ist jedoch nicht erforderlich.

  1. Erstellen Sie die ExternalDNS-CRDs für den NGINX Ingress Controller, um die Integration zwischen den Projekten zu ermöglichen.

    $ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yamlcustomresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org created
  2. Erstellen Sie den externen DNS-Dienst ( external-dns ). Da das Manifest ziemlich lang ist, teilen wir es hier in zwei Teile auf. Der erste Teil konfiguriert Konten, Rollen und Berechtigungen:

    • Erstellt ein ServiceAccount-Objekt namens „external-dns“, um alle Schreib- und Aktualisierungsvorgänge für die DNS-Verwaltung zu verwalten.
    • Erstellt ein ClusterRole-Objekt (auch external-dns genannt), das die erforderlichen Berechtigungen definiert.
    • Bindet die Clusterrolle an den Serviceaccount.
    $ kubectl apply -f - <<EOFapiVersion: v1
    kind: ServiceAccount
    metadata:
      name: external-dns
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: external-dns
    rules:
    - apiGroups: [""]
      resources: ["services","endpoints","pods"]
      verbs: ["get","watch","list"]
    - apiGroups: ["extensions","networking.k8s.io"]
      resources: ["ingresses"]
      verbs: ["get","watch","list"]
    - apiGroups: ["externaldns.nginx.org"]
      resources: ["dnsendpoints"]
      verbs: ["get","watch","list"]
    - apiGroups: ["externaldns.nginx.org"]
      resources: ["dnsendpoints/status"]
      verbs: ["update"]
    - apiGroups: [""]
      resources: ["nodes"]
      verbs: ["list","watch"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: external-dns-viewer
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: external-dns
    subjects:
    - kind: ServiceAccount
      name: external-dns
      namespace: default
    EOF
    serviceaccount/external-dns created
    clusterrole.rbac.authorization.k8s.io/external-dns created
    clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created

    Der zweite Teil des Manifests erstellt die ExternalDNS-Bereitstellung:

    • Erstellt einen Domänenfilter, der den Umfang möglicher Schäden begrenzt, die durch ExternalDNS bei der Verwaltung von Domänen verursacht werden. Sie können beispielsweise die Domänennamen von Staging-Umgebungen angeben, um Änderungen an Produktionsumgebungen zu verhindern. In diesem Beispiel setzen wir den Domänenfilter auf example.com .
    • Legt die Umgebungsvariable CF_API_TOKEN auf Ihr Cloudflare-API-Token fest. Für <Ihr API-Token>, ersetzen Sie entweder das eigentliche Token oder ein Geheimnis, das das Token enthält. Im letzteren Fall müssen Sie das Geheimnis auch mithilfe einer Umgebungsvariablen in den Container projizieren .
    • Setzt die Umgebungsvariable FREE_TIER auf „true“ (angemessen, sofern Sie nicht über ein kostenpflichtiges Cloudflare-Abonnement verfügen).
    $  kubectl apply -f - <<EOF 
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: external-dns
    spec:
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app: external-dns
      template:
        metadata:
          labels:
            app: external-dns
        spec:
          serviceAccountName: external-dns
          containers:
          - name: external-dns
            image: k8s.gcr.io/external-dns/external-dns:v0.12.0
            args:
            - --source=service
            - --source=ingress
            - --source=crd
            - --crd-source-apiversion=externaldns.nginx.org/v1
            - --crd-source-kind=DNSEndpoint
            - --domain-filter=example.com
            - --provider=Cloudflare
            env:
              - name: CF_API_TOKEN
                value: "<your-API-token>"
              - name: FREE_TIER
                value: "true"
    EOF
    serviceaccount/external-dns created
    clusterrole.rbac.authorization.k8s.io/external-dns created
    clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
    deployment.apps/external-dns created

Bereitstellen der Beispielanwendung

Verwenden Sie zu Testzwecken die standardmäßige NGINX Ingress Controller-Beispielanwendung namens Cafe .

  1. Stellen Sie die Cafe-Anwendung bereit.

    $ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yamldeployment.apps/coffee created
    service/coffee-svc created
    deployment.apps/tea created
    service/tea-svc created
  2. Stellen Sie den NGINX Ingress Controller für die Cafe-Anwendung bereit. Beachten Sie folgende Einstellungen:

    • Art: VirtualServer – Wir verwenden die NGINX VirtualServer benutzerdefinierte Ressource statt der standardmäßigen Kubernetes Ingress-Ressource.
    • spec.host – Ersetzen Sie cafe.example.com durch den Namen des Hosts, den Sie bereitstellen. Der Host muss sich innerhalb der Domäne befinden, die mit ExternalDNS verwaltet wird.
    • spec.tls.cert-manager.cluster-issuer – Wenn Sie die in diesem Beitrag angegebenen Werte verwendet haben, ist dies example-issuer . Ersetzen Sie ihn bei Bedarf durch den Namen, den Sie in Schritt 3 von „Cert‑Manager bereitstellen“ gewählt haben.
    • spec.externalDNS.enable – Der Wert „true“ weist ExternalDNS an, einen DNS- A- Eintrag zu erstellen.

    Beachten Sie, dass die für diesen Schritt benötigte Zeit stark vom DNS-Anbieter abhängt, da Kubernetes mit der DNS-API des Anbieters interagiert.

    $ kubectl apply -f - <<EOFapiVersion: k8s.nginx.org/v1
    kind: VirtualServer
    metadata:
      name: cafe
    spec:
      host: cafe.example.com
      tls:
        secret: cafe-secret
        cert-manager:
          cluster-issuer: example-issuer
      externalDNS:
        enable: true
      upstreams:
      - name: tea
        service: tea-svc
        port: 80
      - name: coffee
        service: coffee-svc
        port: 80
      routes:
      - path: /tea
        action:
          pass: tea
      - path: /coffee
        action:
          pass: coffee
    EOF
    virtualserver.k8s.nginx.org/cafe created

Validieren der Lösung

  1. Überprüfen Sie den DNS- A- Eintrag – insbesondere, ob im Block ANSWER SECTION der FQDN (hier cafe.example.com ) der richtigen IP-Adresse ( www.xxx.yyy.zzz ) zugeordnet ist.

    $ dig cafe.example.com 
    ; <<>> DiG 9.10.6 <<>> cafe.example.com
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22633
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
     
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 4096
    ;; QUESTION SECTION:
    ;cafe.example.com.		IN	A
     
    ;; ANSWER SECTION:
    cafe.example.com.	279	IN	A	www.xxx.yyy.zzz
     
    ;; Query time: 1 msec
    ;; SERVER: 2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359#53(2607:fb91:119b:4ac4:2e0:xxxx:fe1e:1359)
    ;; WHEN: Day Mon  DD hh:mm:ss TZ YYYY
    ;; MSG SIZE  rcvd: 67
  2. Überprüfen Sie, ob das Zertifikat gültig ist (der Wert im Feld READY ist True ).

    $ kubectl get certificatesNAME          READY   SECRET        AGE
    cafe-secret   True    cafe-secret   8m51s
  3. Überprüfen Sie, ob Sie die Anwendung erreichen können.

    $ curl https://cafe.example.com/coffeeServer address: 10.2.2.4:8080
    Server name: coffee-7c86d7d67c-lsfs6
    Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
    URI: /coffee
    Request ID: 91077575f19e6e735a91b9d06e9684cd
    $ curl https://cafe.example.com/tea
    Server address: 10.2.2.5:8080
    Server name: tea-5c457db9-ztpns
    Date: DD/Mon/YYYY:hh:mm:ss +TZ-offset
    URI: /tea
    Request ID: 2164c245a495d22c11e900aa0103b00f

Was passiert, wenn ein Entwickler den NGINX Ingress Controller einsetzt?

Hinter den Kulissen läuft viel, sobald Sie die Lösung implementiert haben. Das Diagramm zeigt, was passiert, wenn Sie den NGINX Ingress Controller mit einer benutzerdefinierten NGINX VirtualServer-Ressource bereitstellen. Dabei lassen wir einige betriebliche Details aus.

  1. Der Anwendungsentwickler setzt eine VirtualServer-Ressource mit der NGINX-CRD ein
  2. Kubernetes erstellt den VirtualServer mit dem NGINX Ingress Controller
  3. NGINX Ingress Controller ruft ExternalDNS auf, um einen DNS A -Eintrag zu erstellen
  4. ExternalDNS erstellt den A- Eintrag im DNS
  5. NGINX Ingress Controller ruft den Cert-Manager auf, um ein TLS-Zertifikat anzufordern
  6. cert-manager fügt einen DNS-Eintrag zur Verwendung während der DNS-01- Challenge hinzu
  7. cert-manager kontaktiert Let’s Encrypt, um die Herausforderung abzuschließen
  8. Let’s Encrypt validiert die Challenge gegenüber DNS
  9. Let’s Encrypt stellt das TLS-Zertifikat aus
  10. cert-manager stellt das TLS-Zertifikat für den NGINX Ingress Controller bereit
  11. Der NGINX Ingress Controller leitet TLS-gesicherte externe Anfragen an die Anwendungs-Pods weiter.

Fehlerbehebung

Angesichts der Komplexität von Kubernetes und der von uns verwendeten Komponenten ist es schwierig, eine umfassende Anleitung zur Fehlerbehebung bereitzustellen. Dennoch gibt es einige grundlegende Vorschläge, die Ihnen bei der Ermittlung des Problems helfen können.

  • Verwenden Sie die Befehle „kubectl get“ und „kubectl describe“, um die Konfiguration bereitgestellter Objekte zu validieren.
  • Verwenden Sie die kubectl Protokolle <Komponente> Befehl zum Anzeigen der Protokolldateien für die verschiedenen bereitgestellten Komponenten.
  • Verwenden Sie K9s , um die Installation zu überprüfen. Die Software hebt Probleme in Gelb oder Rot hervor (je nach Schweregrad) und bietet eine Schnittstelle für den Zugriff auf Protokolle und Details zu Objekten.

Wenn Sie weiterhin Probleme haben, finden Sie uns im NGINXCommunity Slack und bitten Sie um Hilfe! Wir haben eine lebendige Community und arbeiten Probleme immer gerne gemeinsam durch.

Um den auf NGINX Plus basierenden NGINX Ingress Controller auszuprobieren, starten Sie noch heute Ihre 30-tägige kostenlose Testversion oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen .


„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."