In dieser Anleitung wird gezeigt, wie Sie Egress- und Ingress-Gateways von Anthos Service Mesh verwenden, um Traffic zwischen Clustern mithilfe von gegenseitiger Transport Layer Security (mTLS) zu schützen. Die Anleitung richtet sich an Kubernetes-Clusteradministratoren, die für Netzwerk-, Sicherheits- und Plattformaspekte zuständig sind. Die hier erläuterten Kontrollen können insbesondere für Organisationen mit erhöhten Sicherheitsanforderungen oder für die Einhaltung gesetzlicher Vorschriften hilfreich sein. Diese Anleitung wird durch einen entsprechenden Konzeptleitfaden ergänzt.
In dieser Anleitung wird davon ausgegangen, dass Sie mit Kubernetes und Anthos Service Mesh vertraut sind.
Ziele
- Infrastruktur mit Terraform einrichten:
- Benutzerdefiniertes VPC-Netzwerk mit zwei privaten Subnetzen erstellen
- Zwei Kubernetes-Cluster mit aktiviertem Anthos Service Mesh erstellen:
- Einen GKE-Cluster
- Einen kOps-Cluster (Kubernetes Operations), der im benutzerdefinierten VPC-Netzwerk ausgeführt wird
- Cluster bei GKE Hub registrieren
- MySQL-Client im GKE-Cluster bereitstellen
- MySQL-Server in einem kOps-Cluster bereitstellen
- Egress- und Ingress-Gateways konfigurieren, um einen Server mithilfe von mTLS bereitzustellen
- Zugriff auf einen MySQL-Server mithilfe eines MySQL-Clients testen, der in verschiedenen Clustern oder VPCs ausgeführt wird
Kosten
In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:
- Google Kubernetes Engine (GKE)
- Compute Engine
- Container Registry
- Anthos Service Mesh
- Cloud-Netzwerke und Load-Balancing
Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.
Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.
Hinweis
Für diese Anleitung benötigen Sie ein Google Cloud-Projekt. Sie können ein neues Projekt erstellen oder ein vorhandenes Projekt auswählen:
-
Rufen Sie in der Google Cloud Console die Seite für die Projektauswahl auf.
-
Wählen Sie ein Google Cloud-Projekt aus oder erstellen Sie eines.
-
Die Abrechnung für das Google Cloud-Projekt muss aktiviert sein.
Rufen Sie in der Google Cloud Console Cloud Shell auf.
Unten in der Google Cloud Console wird eine Cloud Shell-Sitzung mit einer Eingabeaufforderung geöffnet. Cloud Shell ist eine Shell-Umgebung, in der das Google Cloud CLI bereits installiert ist, einschließlich der Google Cloud-Befehlszeile. Das Initialisieren der Sitzung kann einige Sekunden dauern.
- Achten Sie darauf, dass Sie in Cloud Shell in dem Projekt arbeiten, das Sie erstellt oder ausgewählt haben:
export PROJECT_ID=PROJECT_ID gcloud config set project ${PROJECT_ID}
Ersetzen Sie
PROJECT_ID
durch Ihre Projekt-ID. - Erstellen Sie eine Umgebungsvariable für die E-Mail-Adresse, die Sie für Google Cloud verwenden:
export GOOGLE_CLOUD_EMAIL_ADDRESS=GOOGLE_CLOUD_EMAIL_ADDRESS
Ersetzen Sie dabei
GOOGLE_CLOUD_EMAIL_ADDRESS
durch die E-Mail-Adresse, die Sie in Google Cloud nutzen. - Legen Sie die Region und Zone für Ihre Compute-Ressourcen fest:
export REGION=us-central1 export ZONE=us-central1-b gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE}
In dieser Anleitung wird
us-central1
für die Region undus-central1-b
für die Zone verwendet. Sie können in einer Region Ihrer Wahl bereitstellen. - Legen Sie die erforderlichen IAM-Rollen (Identitäts- und Zugriffsverwaltung) fest. Wenn Sie Projektinhaber sind, haben Sie alle erforderlichen Berechtigungen, um die Installation auszuführen. Wenn nicht, bitten Sie Ihren Administrator, Ihnen entsprechende IAM-Rollen (Identity and Access Management) zuzuweisen. Führen Sie dazu den folgenden Befehl in Cloud Shell aus:
ROLES=( 'roles/container.admin' \ 'roles/gkehub.admin' \ 'roles/iam.serviceAccountAdmin' \ 'roles/iam.serviceAccountKeyAdmin' \ 'roles/resourcemanager.projectIamAdmin' \ 'roles/compute.securityAdmin' \ 'roles/compute.instanceAdmin' \ 'roles/storage.admin' \ 'roles/serviceusage.serviceUsageAdmin' ) for role in "${ROLES[@]}" do gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member "user:${GOOGLE_CLOUD_EMAIL_ADDRESS}" \ --role="$role" done
- Aktivieren Sie die für die Anleitung erforderlichen APIs:
gcloud services enable \ anthos.googleapis.com \ anthosgke.googleapis.com \ anthosaudit.googleapis.com \ compute.googleapis.com \ container.googleapis.com \ cloudresourcemanager.googleapis.com \ serviceusage.googleapis.com \ stackdriver.googleapis.com \ monitoring.googleapis.com \ logging.googleapis.com \ cloudtrace.googleapis.com \ meshca.googleapis.com \ meshconfig.googleapis.com \ iamcredentials.googleapis.com \ gkeconnect.googleapis.com \ gkehub.googleapis.com
Umgebung vorbereiten
Klonen Sie in Cloud Shell das folgende Repository:
git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples cd anthos-service-mesh-samples/docs/mtls-egress-ingress
Aktualisieren Sie Terraform für Ihre Umgebung. Standardmäßig ist in der Google Cloud Console Terraform 0.12 enthalten. In dieser Anleitung wird davon ausgegangen, dass Sie Terraform 0.13.5 oder höher installiert haben. Mit den folgenden Befehlen können Sie vorübergehend eine andere Version von Terraform verwenden:
mkdir ~/bin curl https://releases.hashicorp.com/terraform/0.13.5/terraform_0.13.5_linux_amd64.zip -o ~/bin/terraform.zip unzip ~/bin/terraform.zip -d ~/bin/
Wechseln Sie in den Unterordner
terraform
und initialisieren Sie Terraform:cd terraform/ ~/bin/terraform init
Erstellen Sie eine Datei
terraform.tfvars
anhand der zuvor erstellten Umgebungsvariablen:cat << EOF > terraform.tfvars project_id = "${PROJECT_ID}" region = "${REGION}" zones = ["${ZONE}"] EOF
Im nächsten Schritt erstellen Sie die anfängliche Infrastruktur. Dazu erstellen Sie den Terraform-Ausführungsplan für diese Konfiguration und wenden ihn an. Mit den Skripts und Modulen in diesem Plan wird Folgendes erstellt:
- Ein benutzerdefiniertes VPC-Netzwerk mit zwei privaten Subnetzen
- Zwei Kubernetes-Cluster mit aktiviertem Anthos Service Mesh
- Ein GKE-Cluster
- Ein kOps-Cluster, der im benutzerdefinierten VPC-Netzwerk ausgeführt wird
Mit dem Ausführungsplan werden auch Cluster für GKE Hub registriert.
Führen Sie den Ausführungsplan aus:
~/bin/terraform plan -out mtls-terraform-plan ~/bin/terraform apply "mtls-terraform-plan"
Die Ausgabe sieht etwa so aus:
Apply complete! Resources: 27 added, 0 changed, 0 destroyed. Outputs: server_token = <sensitive>
<sensitive>
ist dabei eine Terraform-Ausgabevariable, die in der Console nicht angezeigt wird, aber abgefragt werden kann, z. B.~/bin/terraform output server_token
.Rufen Sie die Datei
kubeconfig
des Serverclusters aus dem Verzeichnisterraform
ab. Führen Sie sie dann mit der Konfigurationsdateiclient-cluster
zusammen:cd .. export KUBECONFIG=client-server-kubeconfig cp ./terraform/server-kubeconfig $KUBECONFIG gcloud container clusters get-credentials client-cluster --zone ${ZONE} --project ${PROJECT_ID}
Die Datei
client-server-kubeconfig
enthält jetzt die Konfiguration für beide Cluster. Diese können Sie mit dem folgenden Befehl prüfen:kubectl config view -ojson | jq -r '.clusters[].name'
Die Ausgabe sieht so aus:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Rufen Sie den Kontext für die beiden Cluster zur späteren Verwendung ab:
export CLIENT_CLUSTER=$(kubectl config view -ojson | jq -r '.clusters[].name' | grep client) export SERVER_CLUSTER=$(kubectl config view -ojson | jq -r '.clusters[].name' | grep server) echo -e "${CLIENT_CLUSTER}\n${SERVER_CLUSTER}"
Die Ausgabe sieht (wieder) so aus:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Sie können diese Clusternamen jetzt als Kontext für weitere
kubectl
-Befehle verwenden.Verweisen Sie auf den Clientcluster:
kubectl --context ${CLIENT_CLUSTER} get pods -n istio-system
Verweisen Sie auf den Servercluster:
kubectl --context ${SERVER_CLUSTER} get pods -n istio-system
Clientseite konfigurieren
Wie im Konzeptleitfaden dargestellt, müssen Sie für die Clientseite das Egress-Gateway in Anthos Service Mesh konfigurieren.
In diesem Abschnitt konfigurieren Sie Anthos Service Mesh-Elemente, um externen Traffic anhand seines Ursprungs zu ermitteln und um ein benutzerdefiniertes Zertifikat zum Verschlüsseln der Kommunikation zu nutzen. Außerdem soll nur dieser Traffic an sein Ziel (die MySQL-DB in einem Container) weitergeleitet werden. In der Regel verwenden Sie dazu einen Dienst in Kubernetes. In diesem Fall müssen Sie den Traffic innerhalb der Mesh-Kommunikation erfassen. Zum Erfassen des Traffics verwenden Sie Istio-Elemente für das Erstellen einer speziellen Definition des Dienstes. Sie definieren dabei die folgenden Elemente:
- Egress-Gateway
- Diensteintrag
- Virtueller Dienst
- TLS-Zertifikate (als Secret)
- Zielregeln
Rufen Sie in Cloud Shell die serverseitige IP-Adresse des Ingress-Gateways ab. Fragen Sie dazu die Load-Balancer-IP-Adresse des
istio-ingressgateway
-Dienstes mit dem Kontext der Serverseite ab (zuvor erstellter$SERVER_CLUSTER
):INGRESS_HOST=$(kubectl -n istio-system --context ${SERVER_CLUSTER} get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
Da der
INGRESS_HOST
nur der IP-Adressteil Ihres Hosts ist, müssen Sie einen vollständig qualifizierten Domainnamen (FQDN) erstellen. Dieser Schritt ist notwendig, da die Zertifikate für die korrekte Funktionsweise einen Domainnamen erfordern.In dieser Anleitung verwenden Sie den Platzhalter-DNS-Dienst nip.io, um einen FQDN für die Eingangs-IP-Adresse zu erstellen. Mit diesem Dienst können Sie den FQDN anlegen, ohne eine Domain zu haben.
Speichern Sie die URL des FQDN-Dienstes in einer Umgebungsvariablen:
export SERVICE_URL="${INGRESS_HOST}.nip.io"
Nachdem Sie
SERVICE_URL
als FQDN definiert haben, können Sie mit der Definition des Istio-Teils des Clientclusters beginnen.
Egress-Gateway erstellen
Sie beginnen mit dem Erstellen des Egress-Gateways für die Überwachung auf Traffic, der für den externen Dienst bestimmt ist.
Erstellen Sie in Cloud Shell die folgende YAML-Datei und nennen Sie sie
client-egress-gateway.yaml
:cat <<EOF > client-egress-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway-mysql spec: selector: istio: egressgateway servers: - port: number: 15443 name: tls protocol: TLS hosts: - $SERVICE_URL tls: mode: ISTIO_MUTUAL EOF
Wenden Sie die obige YAML-Datei auf den Clientcluster an:
kubectl --context ${CLIENT_CLUSTER} apply -f client-egress-gateway.yaml
Achten Sie auf die Ports. Sie haben hier den
default
-Port für den Switch für ausgehende Server verwendet, nämlich15443
. Wenn Sie einen anderen Port verwenden möchten, müssen Sie dasservice
-Objekt des Egress-Gateways bearbeiten und zu Ihren benutzerdefinierten Ports hinzufügen.Der
hosts
-Switch definiert den Endpunkt, zu dem der Traffic geleitet werden soll.
Diensteintrag definieren
Als Nächstes legen Sie für das Service Mesh den externen Dienst fest. Istio hat eine eigene Registry, in der Dienstendpunkte für das Mesh gespeichert sind. Wenn Istio zusätzlich zu Kubernetes installiert ist, werden die im Cluster definierten Dienste der Istio-Registry automatisch hinzugefügt. Mit der Definition des Diensteintrags fügen Sie der Istio-Registry einen neuen Endpunkt hinzu, wie im folgenden Diagramm dargestellt:
Erstellen Sie in Cloud Shell die folgende YAML-Datei und nennen Sie sie
client-service-entry.yaml
:cat <<EOF > client-service-entry.yaml apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: mysql-external spec: hosts: - $SERVICE_URL location: MESH_EXTERNAL ports: - number: 3306 name: tcp protocol: TCP - number: 13306 name: tls protocol: TLS resolution: DNS endpoints: - address: $SERVICE_URL ports: tls: 13306 EOF
Wenden Sie die obige YAML-Datei auf den Clientcluster an:
kubectl --context ${CLIENT_CLUSTER} apply -f client-service-entry.yaml
Die Clientdienstdefinition in dieser YAML-Datei legt für den Dienst fest, welche Art von Traffic erwartet wird (MySQL L4 – Netzwerkebene 4 über Port 3306). Außerdem definieren Sie die Kommunikation als „Mesh-extern“. Im Abschnitt „Endpunkte“ legen Sie fest, dass der Traffic zu der zuvor festgelegten FQDN-Adresse
$SERVICE_URL
geleitet werden soll, die dem Ingress-Gateway auf dem Servercluster zugeordnet (kOps) ist.
Virtuellen Dienst definieren
Ein virtueller Dienst besteht aus einer Reihe von Traffic-Routingregeln, die angewendet werden sollen, wenn ein Host adressiert wird. Mit jeder Routingregel werden Kriterien zum Abgleich für den Traffic eines bestimmten Protokolls definiert. Wenn der Traffic der Regel entspricht, wird er an einen benannten Zieldienst (oder an eine Untergruppe oder Version davon) gesendet, der in der Registry definiert ist. Weitere Informationen finden Sie in der Istio-Dokumentation.
Die Definition des virtuellen Dienstes legt für Istio fest, wie das Routing für den Traffic zum externen Dienst angewendet werden soll. Mit der folgenden Definition legen Sie für das Mesh fest, den Traffic vom Client an das Egress-Gateway an Port 15443
weiterzuleiten. Leiten Sie dann den Traffic vom Egress-Gateway zum Host $SERVICE_URL
an Port 13306
weiter. Dieser wird durch Ihr serverseitiges Ingress-Gateway überwacht.
Erstellen Sie die folgende YAML-Datei und nennen Sie sie
client-virtual-service.yaml
:cat <<EOF > client-virtual-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-mysql-through-egress-gateway spec: hosts: - $SERVICE_URL gateways: - istio-egressgateway-mysql - mesh tcp: - match: - gateways: - mesh port: 3306 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: mysql port: number: 15443 weight: 100 - match: - gateways: - istio-egressgateway-mysql port: 15443 route: - destination: host: $SERVICE_URL port: number: 13306 weight: 100 EOF
Wenden Sie die YAML-Definition auf den Clientcluster an:
kubectl --context ${CLIENT_CLUSTER} apply -f client-virtual-service.yaml
Sie können festlegen, auf welche Gateways die Konfiguration angewendet werden soll. Dazu bearbeiten Sie in der YAML-Datei den Switch
gateways
.Der wesentliche Teil in dieser Definition ist die Verwendung des reservierten Begriffs
mesh
, der alle Sidecars im Mesh impliziert. Wird dieses Feld weggelassen, wird gemäß der Istio-Dokumentation das Standard-Gateway (Mesh) verwendet, um die Regel auf alle Sidecars im Mesh anzuwenden. Wenn Sie eine Liste mit Gatewaynamen bereitstellen, gelten die Regeln nur für die Gateways. Wenn Sie die Regeln auf Gateways und Sidecars anwenden möchten, geben Siemesh
als einen Gatewaynamen an.
Im nächsten Abschnitt definieren Sie, wie der Traffic verarbeitet wird, der den Client-Produktions-Proxy match.gateways.mesh
verlässt. Außerdem definieren Sie mit dem Switch match.gateways.istio-egressgateway-mysql
wie Traffic vom Egress-Gateway an den externen Dienst weitergeleitet wird.
Zielregel definieren (vom Client zum Egress-Gateway)
Nachdem Sie definiert haben, wie Traffic an den externen Dienst weitergeleitet wird, müssen Sie die Trafficrichtlinien festlegen. Der oben definierte virtuelle Dienst verarbeitet zwei Routingfälle gleichzeitig. In einem Fall wird Traffic vom Sidecar-Proxy zum Egress-Gateway und im anderen Fall Traffic vom Egress-Gateway zum externen Dienst verarbeitet.
Damit diese Fälle mit den Zielregeln abgeglichen werden, benötigen Sie zwei separate Regeln. Das folgende Diagramm zeigt die erste Regel, mit der Traffic vom Proxy zum Egress-Gateway verarbeitet wird Mit dieser Definition legen Sie für Anthos Service Mesh fest, dass seine Standardzertifikate für die mTLS-Kommunikation verwendet werden sollen.
Erstellen Sie in Cloud Shell die folgende YAML-Datei und nennen Sie sie
client-destination-rule-to-egress-gateway.yaml
:cat <<EOF > client-destination-rule-to-egress-gateway.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-mysql spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: mysql trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 15443 tls: mode: ISTIO_MUTUAL sni: $SERVICE_URL EOF
Wenden Sie die obige YAML-Definition auf den Clientcluster an:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-egress-gateway.yaml
In obiger YAML-Datei haben Sie mit dem Switch
hosts
definiert, wie Traffic vom Client-Proxy zum Egress-Gateway weitergeleitet wird. Außerdem haben Sie das Mesh so konfiguriert, dassISTIO_MUTUAL
auf Port15443
verwendet wird. Dies ist einer der Ports, der automatisch am Egress-Gateway geöffnet wird.
Zielregel erstellen (vom Egress-Gateway zum externen Dienst)
Das folgende Diagramm zeigt die zweite Zielregel, die für das Mesh festlegt, wie Traffic vom Egress-Gateway zum externen Dienst verarbeitet werden soll.
Sie müssen für das Mesh festlegen, dass für die gegenseitige TLS-Kommunikation mit dem externen Dienst Ihre eingefügten Zertifikate verwendet werden sollen.
Erstellen Sie die Zertifikate in Cloud Shell im Verzeichnis
anthos-service-mesh-samples/docs/mtls-egress-ingress
:./create-keys.sh
Achten Sie darauf, ein Passwort anzugeben, wenn das Skript dazu auffordert.
Kopieren Sie die generierten Dateien in das aktuelle Verzeichnis:
cp ./certs/2_intermediate/certs/ca-chain.cert.pem ca-chain.cert.pem cp ./certs/4_client/private/$SERVICE_URL.key.pem client-$SERVICE_URL.key.pem cp ./certs/4_client/certs/$SERVICE_URL.cert.pem client-$SERVICE_URL.cert.pem
Erstellen Sie ein Kubernetes-Secret, das die Zertifikate speichert, damit später im Gateway darauf verwiesen werden kann:
kubectl --context ${CLIENT_CLUSTER} create secret -n istio-system \ generic client-credential \ --from-file=tls.key=client-$SERVICE_URL.key.pem \ --from-file=tls.crt=client-$SERVICE_URL.cert.pem \ --from-file=ca.crt=ca-chain.cert.pem
Mit dem obigen Befehl werden dem Secret die folgenden Zertifikatsdateien hinzugefügt:
client-$SERVICE_URL.key.pem client-$SERVICE_URL.cert.pem ca-chain.cert.pem
Im Folgenden wird die aktuelle Best Practice zur Verteilung von Zertifikaten durch Nutzung des Secret Discovery Service (SDS) anstelle von Dateibereitstellungen angewendet. Durch diese Vorgehensweise wird ein Neustart der Pods nach dem Hinzufügen eines neuen Zertifikats vermieden. Ab Istio 1.8/1.9 benötigen Sie mit dieser Methode keine Lesezugriffsrechte (RBAC) mehr für das Secret der Gateways.
Fügen Sie die Zertifikate zur
DestinationRule
hinzu und benennen Sie sie mitclient-destination-rule-to-external-service.yaml
:cat <<EOF > client-destination-rule-to-external-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-mtls-for-mysql spec: host: $SERVICE_URL trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 13306 tls: mode: MUTUAL credentialName: client-credential sni: $SERVICE_URL EOF
Wenden Sie die obige YAML-Definition auf den Clientcluster an:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-external-service.yaml
Diese Regel ist nur wirksam, wenn Sie das Secret zuvor erstellt haben. Das Secret sorgt dafür, dass die Zertifikate zur mTLS-Verschlüsselung vom Egress-Gateway zum externen Endpunkt verwendet werden.
Nachdem Sie diese Schritte ausgeführt haben, ist die clientseitige Einrichtung abgeschlossen wie im folgenden Diagramm dargestellt.
Serverseite konfigurieren
Wie im Konzeptleitfaden erläutert müssen Sie für den Server das Ingress-Gateway in Anthos Service Mesh konfigurieren. Bevor Sie die erforderlichen Dateien erstellen, sollten Sie prüfen, welche Komponenten erforderlich sind, um den Serverteil der Lösung umzusetzen.
Im Wesentlichen möchten Sie eingehenden Traffic anhand seines Ursprungs und des Zertifikats ermitteln. Sie möchten auch nur diesen Traffic an sein Ziel weiterleiten, Ihre MySQL-DB in einem Container. Normalerweise verwenden Sie dazu einen Dienst in Kubernetes. In diesem Beispiel ermitteln Sie dagegen den eingehenden Traffic innerhalb der Mesh-Kommunikation. Daher benötigen Sie eine spezielle Definition für einen Dienst, der Folgendes enthält:
- TLS-Zertifikate (als Secret)
- Ingress-Gateway
- Virtueller Dienst
Secret für das Ingress-Gateway erstellen
Zum Schutz der Kommunikation für das Ingress-Gateway müssen Sie die gleichen Zertifikate wie für das Egress-Gateway verwenden. Speichern Sie dazu die Zertifikate in einem Secret und definieren Sie dieses Secret mit dem Ingress-Gatewayobjekt.
Kopieren Sie in Cloud Shell die generierten Dateien in den Speicherort, an dem Sie den nächsten Befehl ausführen:
cp ./certs/3_application/private/$SERVICE_URL.key.pem server-$SERVICE_URL.key.pem cp ./certs/3_application/certs/$SERVICE_URL.cert.pem server-$SERVICE_URL.cert.pem
Erstellen Sie das Server-Secret:
kubectl --context ${SERVER_CLUSTER} create secret -n istio-system \ generic mysql-credential \ --from-file=tls.key=server-$SERVICE_URL.key.pem \ --from-file=tls.crt=server-$SERVICE_URL.cert.pem \ --from-file=ca.crt=ca-chain.cert.pem
Sie haben jetzt dem Secret die folgenden Zertifikatsdateien hinzugefügt:
server-$SERVICE_URL.key.pem server-$SERVICE_URL.cert.pem ca-chain.cert.pem
Ingress-Gateway definieren
Um Traffic vom clientseitigen Cluster zu empfangen, müssen Sie ein Ingress-Gateway angeben, das die TLS-Kommunikation mithilfe der Zertifikate entschlüsseln und prüfen kann.
Dieses Diagramm zeigt, wo sich das Ingress-Gateway in Ihrem Cluster befindet. Der Traffic wird weitergeleitet und geprüft, ob er den Sicherheits- und Weiterleitungskriterien entspricht.
Verwenden Sie in Cloud Shell die folgende YAML-Datei und nennen Sie sie
server-ingress-gatway.yaml
:cat <<EOF > server-ingress-gatway.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: gateway-mysql spec: selector: istio: ingressgateway # Istio default gateway implementation servers: - port: number: 13306 name: tls-mysql protocol: TLS tls: mode: MUTUAL credentialName: mysql-credential hosts: - "$SERVICE_URL" EOF
Wenden Sie die obige YAML-Definition auf den Clientcluster an:
kubectl --context ${SERVER_CLUSTER} apply -f server-ingress-gatway.yaml
Beachten Sie den Abschnitt
tls:
, der besonders wichtig ist. In diesem Abschnitt definieren Sie die Verwendung von mTLS. Damit dies tatsächlich wie gewünscht funktioniert, müssen Sie das von Ihnen erstellte Secret mit den Zertifikaten bereitstellen.Aktivieren Sie Port
13306
durch Patchen des Dienstes für eingehenden Traffic. Zum Aktivieren dieses Ports erstellen Sie die folgende JSON-Datei und nennen Sie siegateway-patch.json
:cat <<EOF > gateway-patch.json [{ "op": "add", "path": "/spec/ports/0", "value": { "name": "tls-mysql", "protocol": "TCP", "targetPort": 13306, "port": 13306 } }] EOF
Wenden Sie den Patch auf den Gatewaydienst an:
kubectl --context ${SERVER_CLUSTER} -n istio-system patch --type=json svc istio-ingressgateway -p "$(cat gateway-patch.json)"
Nachdem Sie den Port des Ingress-Gateways geöffnet haben, müssen Sie von Ihrem neuen Ingress-Gateway eingehenden Traffic abrufen und an Ihren Datenbank-Pod weiterleiten. Dazu verwenden Sie ein internes Mesh-Objekt, den virtuellen Dienst.
Virtuellen Dienst definieren
Wie bereits erwähnt, ist der virtuelle Dienst eine Definition von Trafficmustern zum Abgleich, die den Traffic innerhalb des Mesh bestimmen. Sie müssen den Traffic von Ihrem Ingress-Gateway an Ihren MySQL-DB-Dienst korrekt ermitteln und weiterleiten, wie im folgenden Diagramm dargestellt.
Erstellen Sie in Cloud Shell die folgende YAML-Datei und nennen Sie sie
server-virtual-service.yaml
:cat <<EOF > server-virtual-service.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: mysql-virtual-service spec: hosts: - "$SERVICE_URL" gateways: - gateway-mysql tcp: - route: - destination: port: number: 3306 host: mysql.default.svc.cluster.local EOF
Es ist erforderlich, dass dieser virtuelle Dienst auf das Ingress-Gateway verweist, von dem der Traffic stammt. Der Name des Gateways lautet
gateway-mysql
.Da dieser virtuelle Dienst auf L4 angewendet wird, müssen Sie das Flag
tcp
zur Beschreibung Ihres MySQL-Traffics angeben. Dieses Flag legt für das Mesh grundsätzlich fest, dass für diesen Traffic L4 verwendet wird.Sie haben vielleicht schon gesehen, dass der Dienst für eingehenden Traffic Port
13306
für die Weiterleitung des Traffics nutzt. Der virtuelle Dienst übernimmt diesen Port und setzt ihn auf3306
zurück.Zum Abschluss leiten Sie Traffic an den MySQL-Server im Kubernetes-Cluster des Servers weiter. In diesem Beispiel überwacht der Server den Standard-MySQL-Port
3306
.Wenden Sie die YAML-Definition auf den Servercluster an:
kubectl --context ${SERVER_CLUSTER} apply -f server-virtual-service.yaml
Diese beiden Definitionen entschlüsseln die mTLS-gekapselte MySQL-Clientanfrage und leiten sie an die MySQL-Datenbank im Mesh weiter.
Beachten Sie, dass die interne Mesh-Weiterleitung ebenfalls mit Verschlüsselung ausgeführt wird. In diesem Fall basiert die Verschlüsselung aber auf den internen Mesh-Zertifikaten. Die mTLS-Beendigung erfolgt am Gateway.
Jetzt haben Sie eine vollständig und gegenseitig verschlüsselte Möglichkeit der Kommunikation mit Ihrem MySQL-Server. Diese Art der Verschlüsselung ist für den MySQL-Client und -Server transparent, sodass keine Anwendungsänderungen erforderlich sind. Dies vereinfacht Aufgaben wie das Ändern oder Rotieren von Zertifikaten. Außerdem kann diese Art der Kommunikation für viele unterschiedliche Szenarien verwendet werden.
Einrichtung testen
Nachdem Sie die client- und serverseitige Einrichtung vorgenommen haben, können Sie diese testen.
Nun muss Traffic vom Client zum Server generiert werden. Sie möchten dem Trafficfluss folgen und dafür sorgen, dass der Traffic wie gewünscht weitergeleitet und verschlüsselt bzw. entschlüsselt wird.
Stellen Sie in Cloud Shell den MySQL-Server im Servercluster bereit:
kubectl --context ${SERVER_CLUSTER} apply -f server/mysql-server/mysql.yaml
Starten Sie einen MySQL-Client im Clientcluster:
kubectl run --context ${CLIENT_CLUSTER} --env=SERVICE_URL=$SERVICE_URL -it --image=mysql:5.6 mysql-client-1 --restart=Never -- /bin/bash
Wenn der Container gestartet wurde, wird eine Shell angezeigt, die so aussehen sollte:
root@mysql-client-1:/#
Stellen Sie eine Verbindung zu Ihrem MySQL-Server her:
mysql -pyougottoknowme -h $SERVICE_URL
Verwenden Sie die folgenden Befehle, um eine Datenbank und eine Tabelle hinzuzufügen:
CREATE DATABASE test_encrypted_connection; USE test_encrypted_connection; CREATE TABLE message (id INT, content VARCHAR(20)); INSERT INTO message (id,content) VALUES(1,"Crypto Hi");
Nachdem Sie die Verbindung hergestellt und die Tabelle hinzugefügt haben, beenden Sie die MySQL-Verbindung und den Pod:
exit exit
Sie müssen dafür „exit“ zweimal eingeben: einmal, um die DB-Verbindung zu beenden, und dann noch einmal, um den Pod zu beenden. Wenn der Pod nach dem Beenden nicht mehr reagiert, drücken Sie Strg+C, um die Bash-Shell zu schließen.
Mit diesen Schritten sollte eine aussagekräftige Logging-Ausgabe generiert werden, die Sie dann weiter analysieren können.
Im nächsten Abschnitt prüfen Sie, ob der clientseitige Traffic über den Proxy und das Egress-Gateway weitergeleitet wurde. Außerdem testen Sie, ob der Traffic beim Server über das Ingress-Gateway eingeht.
Clientseitigen Proxy und Egress-Gateway testen
Prüfen Sie in Cloud Shell auf dem clientseitigen Proxy, ob die Istio-Proxy-Logs angezeigt werden:
kubectl --context ${CLIENT_CLUSTER} logs -l run=mysql-client-1 -c istio-proxy -f
Die Debug-Ausgabe sieht dann ungefähr so aus:
[2021-02-10T21:19:08.292Z] "- - -" 0 - "-" "-" 176 115 10 - "-" "-" "-" "-" "192.168.1.4:15443" outbound|15443|mysql|istio-egressgateway.istio-system.svc.cluster.local 192.168.1.12:58614 34.66.165.46:3306 192.168.1.12:39642 - -
Drücken Sie Strg+C, um die Logausgabe zu beenden.
In diesem Logeintrag sehen Sie, dass der Client die Anfrage an den Server an der IP-Adresse
34.66.165.46
an Port3306
sendet. Die Anfrage wird weitergeleitet (outbound
) zumistio-egressgateway
, das die IP-Adresse192.168.1.4
an Port15443
überwacht. Sie haben diese Weiterleitung in Ihrem virtuellen Dienst (client-virtual-service.yaml
) definiert.Prüfen Sie die Proxy-Logs des Egress-Gateways:
kubectl --context ${CLIENT_CLUSTER} logs -n istio-system -l app=istio-egressgateway -f
Die Ausgabe sieht in etwa so aus:
[2021-02-10T21:19:08.292Z] "- - -" 0 - "-" "-" 176 115 19 - "-" "-" "-" "-" "34.66.165.46:13306" outbound|13306||34.66.165.46.nip.io 192.168.1.4:53542 192.168.1.4:15443 192.168.1.12:58614 34.66.165.46.nip.io -
Drücken Sie Strg+C, um die Logausgabe zu beenden.
In diesem Logeintrag können Sie feststellen, dass die Clientanfrage, die an das
istio-egressgateway
weitergeleitet wurde, das die IP-Adresse192.168.1.4
an Port15443
überwacht, an außerhalb des Service Mesh zu dem externen Dienst weitergeleitet wurde, der die IP-Adresse34.66.165.46
an Port13306.
überwacht. Sie haben diese Weiterleitung im zweiten Teil Ihres virtuellen Dienstes definiert (client-virtual-service.yaml
).
Serverseitiges Ingress-Gateway testen
Rufen Sie in Cloud Shell auf der Serverseite die Proxy-Logs des Ingress-Gateways auf:
kubectl --context ${SERVER_CLUSTER} logs -n istio-system -l app=istio-ingressgateway -f
Die Ausgabe im Log sieht in etwa so aus:
[2021-02-10T21:22:27.381Z] "- - -" 0 - "-" "-" 0 78 5 - "-" "-" "-" "-" "100.96.4.8:3306" outbound|3306||mysql.default.svc.cluster.local 100.96.1.3:55730 100.96.1.3:13306 100.96.1.1:42244 34.66.165.46.nip.io -
Drücken Sie Strg+C, um die Logausgabe zu beenden.
In diesem Logeintrag können Sie feststellen, dass die Anfrage des externen Clients, die an das
istio-ingressgateway
weitergeleitet wurde, das die IP-Adresse34.66.165.46
an Port13306
überwacht, zum MySQL-Dienst innerhalb des Mesh weitergeleitet wurde, der mit dem Dienstnamenmysql.default.svc.cluster.local
an Port3306.
identifiziert wurde. Sie haben diese Weiterleitung im Ingress-Gateway (server-ingress-gateway.yaml
) definiert.Prüfen Sie für den MySQL-Server die Istio-Proxy-Logs:
kubectl --context ${SERVER_CLUSTER} logs -l app=mysql -c istio-proxy -f
Die Ausgabe sieht dann ungefähr so aus:
[2021-02-10T21:22:27.382Z] "- - -" 0 - "-" "-" 1555 1471 4 - "-" "-" "-" "-" "127.0.0.1:3306" inbound|3306|mysql|mysql.default.svc.cluster.local 127.0.0.1:45894 100.96.4.8:3306 100.96.1.3:55730 outbound_.3306_._.mysql.default.svc.cluster.local -
Drücken Sie Strg+C, um die Logausgabe zu beenden.
In diesem Logeintrag ist der eingehende Aufruf an den MySQL-Datenbankserver aufgeführt, der die IP-Adresse
100.96.4.8
an Port3306
überwacht. Der Aufruf stammt vom Pod für eingehenden Traffic mit der IP-Adresse100.96.1.3
.Weitere Informationen zum Logging-Format von Envoy finden Sie unter Zugriffslogs von Envoy abrufen.
Testen Sie Ihre Datenbank, um die generierte Eingabe zu prüfen:
MYSQL=$(kubectl --context ${SERVER_CLUSTER} get pods -n default | tail -n 1 | awk '{print $1}') kubectl --context ${SERVER_CLUSTER} exec $MYSQL -ti -- /bin/bash
Prüfen Sie die erstellte Datenbank:
mysql -pyougottoknowme USE test_encrypted_connection; SELECT * from message;
Die Ausgabe sieht etwa so aus:
+------+-----------+ | id | content | +------+-----------+ | 1 | Crypto Hi | +------+-----------+ 1 row in set (0.00 sec)
Verlassen Sie die MySQL-Datenbank:
exit exit
Sie müssen
exit
zweimal eingeben – einmal, um die DB-Verbindung zu beenden, und dann noch einmal, um den Pod zu beenden.
Zugriff nach Entfernen der Zertifikate testen
Nachdem Sie nun getestet und geprüft haben, ob der Zugriff über die eingefügten Zertifikate funktioniert, testen Sie nun das Gegenteil: Was geschieht, wenn Sie das Egress-Gateway und das Zertifikat weglassen? Dieser Test wird auch als negativer Test bezeichnet.
Sie können diesen Test durch Starten eines anderen Pods in einem Namespace ausführen, bei dem der Proxy nicht auf der jeweiligen Seite eingefügt wurde.
Erstellen Sie in Cloud Shell einen neuen Namespace.
kubectl --context ${CLIENT_CLUSTER} create ns unencrypted
Erstellen Sie einen Pod und starten Sie eine interaktive Shell im Container:
kubectl --context ${CLIENT_CLUSTER} run -it --image=mysql:5.6 \ mysql-client-2 --env=SERVICE_URL=$SERVICE_URL \ -n unencrypted --restart=Never -- /bin/bash
Versuchen Sie, nach dem Start der interaktiven Shell eine Verbindung zur Datenbank herzustellen:
mysql -pyougottoknowme -h $SERVICE_URL
Nach 30 Sekunden wird eine Ausgabe ähnlich der folgenden dargestellt:
Warning: Using a password on the command line interface can be insecure. ERROR 2003 (HY000): Can't connect to MySQL server on '104.154.164.12.nip.io' (110)
Diese Warnung ist erwartungsgemäß, da dieser Pod das Egress-Gateway umgeht und versucht, das Ingress-Gateway (
$SERVICE_URL
) direkt über das Internet zu erreichen.Versuchen Sie, die Dienst-IP-Adresse aufzulösen:
resolveip $SERVICE_URL
Die entsprechende Ausgabe sieht etwa so aus: Ihre IP-Adresse lautet aber anders.
IP address of 104.154.164.12.nip.io is 104.154.164.12
Dies zeigt, dass der FQDN aufgelöst werden kann und die fehlgeschlagene Verbindung tatsächlich auf das Fehlen eines eingefügten Zertifikats zurückzuführen ist.
Beenden Sie die MySQL-Verbindung und den MySQL-Server-Pod:
exit exit
Genauere Untersuchung
In dieser Anleitung wird nicht behandelt, dass Konfigurationen für ausgehenden Traffic normalerweise zu einer anderen Rolle oder Organisation in Ihrem Unternehmen gehören, da sie im Namespace istio-system
gehostet werden. Konfigurieren Sie Kubernetes RBAC-Berechtigungen so, dass nur Netzwerkadministratoren die in dieser Anleitung beschriebenen Ressourcen direkt erstellen und ändern können.
Nachdem Sie nun wissen, wie Sie ein Service Mesh verwenden, um eine sichere Kommunikation zu gewährleisten, sollten Sie dies mit einer Anwendung testen, die Daten sicher austauschen muss und bei der Sie die Verschlüsselung bis zur Zertifikatsebene steuern möchten. Für den Einstieg können Sie Anthos Service Mesh installieren.
Verwenden Sie zwei GKE-Cluster und kombinieren Sie diese mithilfe der Methode dieser Anleitung. Diese Methode funktioniert auf der GKE Enterprise-Plattform auch zwischen zwei ausländischen Kubernetes-Clustern.
Service Meshes sind eine hervorragende Möglichkeit, den Schutz innerhalb des Clusters sowie bei externen Diensten zu erhöhen. Ein letzter Anwendungsfall für den Test ist ein mTLS-Endpunkt, der kein zweiter Kubernetes-Cluster, sondern ein Drittanbieter ist (z. B. ein Zahlungsdienstleister) ist.
Bereinigen
Um zu vermeiden, dass Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen in Rechnung gestellt werden, können Sie Ihr Projekt löschen.
Projekt löschen
- Wechseln Sie in der Google Cloud Console zur Seite Ressourcen verwalten.
- Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie dann auf Löschen.
- Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Shut down (Beenden), um das Projekt zu löschen.
Nächste Schritte
- Lesen Sie den Leitfaden für Companion-Konzepte.
- Weitere Best Practices zur Konfiguration Ihres Egress-Gateways finden Sie unter Egress-Gateways von Anthos Service Mesh in GKE-Clustern verwenden: Anleitung.
- Weitere Informationen finden Sie im GKE-Härtungsleitfaden und im zugehörigen Terraform-Modul.
- Referenzarchitekturen, Diagramme und Best Practices zu Google Cloud kennenlernen. Weitere Informationen zu Cloud Architecture Center