Questo tutorial descrive come utilizzare i gateway in uscita e in entrata Anthos Service Mesh per proteggere il traffico tra i cluster utilizzando mTLS (mutual Transport Layer Security). Il tutorial è destinato agli amministratori di cluster Kubernetes responsabili degli aspetti della rete, della sicurezza e della piattaforma. I controlli descritti qui potrebbero essere particolarmente utili per le organizzazioni con requisiti di sicurezza più severi o per soddisfare prerequisiti normativi. Questo tutorial è accompagnato da una guida concettuale complementare.
Questo tutorial presuppone che tu conosca Kubernetes e Anthos Service Mesh.
Obiettivi
- Utilizza Terraform per configurare l'infrastruttura:
- Crea una rete VPC personalizzata con due subnet private.
- Crea due cluster Kubernetes con Anthos Service Mesh abilitato:
- Un cluster GKE
- Un cluster Kubernetes Operations (kOps) in esecuzione nella rete VPC personalizzata
- Registra i cluster in GKE Hub.
- Eseguire il deployment di un client MySQL su un cluster GKE.
- Eseguire il deployment di un server MySQL su un cluster kOps.
- Configura i gateway in uscita e in entrata per esporre un server mediante mTLS.
- Verifica l'accesso a un server MySQL utilizzando un client MySQL in esecuzione in cluster o VPC diversi.
Costi
In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:
- Google Kubernetes Engine (GKE)
- Compute Engine
- Container Registry
- Anthos Service Mesh
- Networking e bilanciamento del carico cloud
Per generare una stima dei costi in base all'utilizzo previsto,
utilizza il Calcolatore prezzi.
Una volta completate le attività descritte in questo documento, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la pagina Pulizia.
Prima di iniziare
Per questo tutorial è necessario un progetto Google Cloud. Puoi crearne uno nuovo o selezionare un progetto che hai già creato:
-
Nella console Google Cloud, vai alla pagina del selettore progetto.
-
Seleziona o crea un progetto Google Cloud.
-
Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.
Nella console Google Cloud, vai a Cloud Shell.
Nella parte inferiore della console Google Cloud, si apre una sessione Cloud Shell che mostra un prompt della riga di comando. Cloud Shell è un ambiente shell con Google Cloud CLI già installato, che include Google Cloud CLI. L'inizializzazione della sessione può richiedere alcuni secondi.
- In Cloud Shell, assicurati di lavorare nel progetto che hai creato o selezionato:
export PROJECT_ID=PROJECT_ID gcloud config set project ${PROJECT_ID}
Sostituisci
PROJECT_ID
con l'ID progetto. - Crea una variabile di ambiente per l'indirizzo email che utilizzi per Google Cloud:
export GOOGLE_CLOUD_EMAIL_ADDRESS=GOOGLE_CLOUD_EMAIL_ADDRESS
Sostituisci
GOOGLE_CLOUD_EMAIL_ADDRESS
con l'indirizzo email che utilizzi in Google Cloud. - Imposta la regione e la zona per le risorse di computing:
export REGION=us-central1 export ZONE=us-central1-b gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE}
Questo tutorial utilizza
us-central1
per la regione eus-central1-b
per la zona. Puoi eseguire il deployment in una regione a tua scelta. - Imposta i ruoli IAM (Identity and Access Management) richiesti. Se sei un Proprietario progetto, disponi di tutte le autorizzazioni necessarie per completare l'installazione. In caso contrario, chiedi all'amministratore di concederti i ruoli IAM (Identity and Access Management) eseguendo questo comando in Cloud Shell:
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
- Abilita le API necessarie per il tutorial:
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
Preparazione dell'ambiente
In Cloud Shell, clona il seguente repository:
git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples cd anthos-service-mesh-samples/docs/mtls-egress-ingress
Aggiorna Terraform per il tuo ambiente. Per impostazione predefinita, la console Google Cloud include Terraform 0.12. Questo tutorial presuppone che tu abbia installato Terraform 0.13.5 o versioni successive. Puoi utilizzare temporaneamente un'altra versione di Terraform eseguendo questi comandi:
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/
Vai alla sottocartella
terraform
e inizializza Terraform:cd terraform/ ~/bin/terraform init
Crea un file
terraform.tfvars
(in base alle variabili di ambiente create in precedenza):cat << EOF > terraform.tfvars project_id = "${PROJECT_ID}" region = "${REGION}" zones = ["${ZONE}"] EOF
Nel passaggio successivo creerai l'infrastruttura iniziale. Per farlo, devi creare e applicare il piano di esecuzione Terraform per questa configurazione. Gli script e i moduli di questo piano creano quanto segue:
- Una rete VPC personalizzata con due subnet private
- Due cluster Kubernetes con Anthos Service Mesh abilitato
- Un cluster GKE
- Un cluster kOps in esecuzione nella rete VPC personalizzata
Il piano di esecuzione registra anche i cluster in GKE Hub.
Esegui il piano di esecuzione:
~/bin/terraform plan -out mtls-terraform-plan ~/bin/terraform apply "mtls-terraform-plan"
L'output è simile al seguente:
Apply complete! Resources: 27 added, 0 changed, 0 destroyed. Outputs: server_token = <sensitive>
La parte
<sensitive>
è una variabile di output di Terraform che non viene mostrata nella console, ma su cui è possibile eseguire query, ad esempio~/bin/terraform output server_token
.Recupera il file del cluster di server
kubeconfig
dalla directoryterraform
. Quindi uniscilo al file di configurazioneclient-cluster
:cd .. export KUBECONFIG=client-server-kubeconfig cp ./terraform/server-kubeconfig $KUBECONFIG gcloud container clusters get-credentials client-cluster --zone ${ZONE} --project ${PROJECT_ID}
Il file
client-server-kubeconfig
ora contiene la configurazione per entrambi i cluster, che puoi verificare eseguendo questo comando:kubectl config view -ojson | jq -r '.clusters[].name'
L'output è il seguente:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Ottieni il contesto per i due cluster per un uso futuro:
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}"
L'output è (nuovamente) il seguente:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Ora puoi utilizzare questi nomi di cluster come contesto per ulteriori comandi
kubectl
.Fai riferimento al cluster client:
kubectl --context ${CLIENT_CLUSTER} get pods -n istio-system
Fai riferimento al cluster di server:
kubectl --context ${SERVER_CLUSTER} get pods -n istio-system
Configurazione del lato client
Come menzionato nella guida concettuale, il lato client richiede la configurazione del gateway in uscita in Anthos Service Mesh.
In questa sezione, configurerai gli elementi Anthos Service Mesh per identificare il traffico esterno in base alla sua origine e utilizzare un certificato personalizzato per criptare le comunicazioni. Inoltre, vuoi instradare in modo specifico solo quel traffico alla sua destinazione (il database MySQL in un container). In genere, puoi farlo utilizzando un servizio in Kubernetes. In questo caso, devi catturare questo traffico all'interno della comunicazione mesh. Per rilevare il traffico, utilizza gli elementi Istio per creare una definizione speciale del servizio. Sei tu a definire i seguenti elementi:
- Gateway in uscita
- Voce di servizio
- Servizio virtuale
- Certificati TLS (come secret)
- Regole della destinazione
In Cloud Shell, recupera l'indirizzo IP del gateway in entrata sul lato server eseguendo una query sull'indirizzo IP del bilanciatore del carico del servizio
istio-ingressgateway
utilizzando il contesto del gateway in entrata ($SERVER_CLUSTER
, che hai creato in precedenza):INGRESS_HOST=$(kubectl -n istio-system --context ${SERVER_CLUSTER} get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
Poiché
INGRESS_HOST
è solo la parte dell'indirizzo IP dell'host, devi creare un nome di dominio completo (FQDN). Questo passaggio è necessario perché, per funzionare correttamente, i certificati richiedono un nome di dominio.In questo tutorial utilizzerai il servizio DNS con caratteri jolly nip.io per creare un nome di dominio completo per l'indirizzo IP in entrata. Questo servizio consente di creare il nome di dominio completo senza possedere un dominio.
Archivia l'URL del servizio FQDN in una variabile di ambiente:
export SERVICE_URL="${INGRESS_HOST}.nip.io"
Ora, con
SERVICE_URL
definito come nome di dominio completo, puoi iniziare a definire la parte Istio del cluster client.
Crea il gateway in uscita
Per iniziare, crea il gateway in uscita per ascoltare il traffico destinato al servizio esterno.
In Cloud Shell, crea il seguente file YAML e assegnagli il nome
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
Applica il file YAML precedente al cluster client:
kubectl --context ${CLIENT_CLUSTER} apply -f client-egress-gateway.yaml
Fai attenzione alle porte. Hai utilizzato le porte
default
qui per lo switch dei server in uscita, che è15443
. Se vuoi utilizzare un'altra porta, devi modificare l'oggettoservice
del gateway in uscita per aggiungere le porte personalizzate.L'opzione
hosts
definisce l'endpoint, ovvero dove deve essere diretto il traffico.
Definisci la voce di servizio
Il passaggio successivo consiste nel comunicare al mesh di servizi il servizio esterno. Istio dispone di un proprio registry in cui archivia gli endpoint di servizio per il mesh. Se Istio viene installato su Kubernetes, i servizi definiti nel cluster vengono aggiunti automaticamente al registro Istio. Con la definizione della voce di servizio, aggiungi un nuovo endpoint al registro Istio, come mostrato nel diagramma seguente.
In Cloud Shell, crea il seguente file YAML e assegnagli il nome
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
Applica il file YAML precedente al cluster client:
kubectl --context ${CLIENT_CLUSTER} apply -f client-service-entry.yaml
La definizione del servizio client in questo file YAML indica al servizio il tipo di traffico previsto (MySQL L4 - livello di rete quattro, utilizzando la porta 3306). Definite anche che la comunicazione passerà alla rete "mesh esterna". Nella sezione degli endpoint, definisci che il flusso deve andare verso l'indirizzo di dominio completo
$SERVICE_URL
che hai impostato in precedenza e che è mappato al gateway in entrata nel cluster di server (kOps).
Definisci il servizio virtuale
Un servizio virtuale è un insieme di regole di routing del traffico da applicare quando viene indirizzato un host. Ogni regola di routing definisce i criteri di corrispondenza per il traffico di un protocollo specifico. Se il traffico ha una corrispondenza, viene inviato a un servizio di destinazione denominato (o a un sottoinsieme o a una versione dello stesso) definito nel registro. Per ulteriori informazioni, consulta la documentazione di Istio.
La definizione del servizio virtuale indica a Istio come applicare il routing per il traffico che raggiunge il servizio esterno. Con la definizione seguente, indichi al mesh di instradare il traffico dal client al gateway in uscita sulla porta 15443
. Dal gateway in uscita, instrada il traffico all'host $SERVICE_URL
sulla porta 13306
(dove è in ascolto il gateway in entrata lato server).
Crea il seguente file YAML e assegnagli il nome
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
Applica la definizione YAML al cluster client:
kubectl --context ${CLIENT_CLUSTER} apply -f client-virtual-service.yaml
Puoi specificare i gateway a cui applicare la configurazione modificando l'opzione
gateways
nel file YAML.La parte importante in questa definizione è l'uso della parola riservata
mesh
, che implica tutti i file collaterali nel mesh. In base alla documentazione di Istio, se questo campo viene omesso viene utilizzato il gateway predefinito (mesh) e la regola viene applicata a tutti i file collaterali nel mesh. Se fornisci un elenco di nomi di gateway, le regole si applicano solo a questi ultimi. Per applicare le regole a gateway e file collaterali, specificamesh
come nome di gateway.
Nella sezione successiva definirai come gestire il traffico in uscita dal proxy di produzione client, match.gateways.mesh
. Puoi anche definire come indirizzare il traffico dal traffico in uscita al servizio esterno utilizzando l'opzione match.gateways.istio-egressgateway-mysql
.
Definisci una regola di destinazione (dal client al gateway in uscita)
Ora che hai definito come instradare il traffico al servizio esterno, devi definire i criteri di traffico da applicare. Il servizio virtuale che hai appena definito gestisce contemporaneamente due casi di routing. Una gestisce il traffico dal proxy sidecar al gateway in uscita, mentre l'altra gestisce il traffico dal gateway in uscita al servizio esterno.
Per creare corrispondenze tra questi casi e le regole di destinazione, sono necessarie due regole distinte. Il seguente diagramma mostra la prima regola, che gestisce il traffico dal proxy al gateway in uscita. In questa definizione, indichi ad Anthos Service Mesh di utilizzare i certificati predefiniti per la comunicazione mTLS.
In Cloud Shell, crea il seguente file YAML e assegnagli il nome
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
Applica la definizione YAML precedente al cluster client:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-egress-gateway.yaml
Nel file YAML precedente, hai utilizzato l'opzione
hosts
per definire la modalità di routing del traffico dal proxy client al gateway in uscita. Inoltre, hai configurato il mesh in modo che utilizziISTIO_MUTUAL
sulla porta15443
, che è una delle porte aperte automaticamente al gateway in uscita.
Crea una regola di destinazione (dal gateway in uscita al servizio esterno)
Il seguente diagramma mostra la seconda regola di destinazione, che indica al mesh come gestire il traffico dal gateway in uscita al servizio esterno.
Devi indicare al mesh di utilizzare i certificati inseriti per la comunicazione TLS reciproca con il servizio esterno.
In Cloud Shell, dalla directory
anthos-service-mesh-samples/docs/mtls-egress-ingress
, crea i certificati:./create-keys.sh
Assicurati di fornire una password quando lo script la richiede.
Copia i file generati nella directory corrente:
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
Crea un secret Kubernetes che archivia i certificati in modo che possano essere utilizzati come riferimento in un secondo momento nel gateway:
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
Il comando precedente aggiunge i seguenti file di certificati al secret:
client-$SERVICE_URL.key.pem client-$SERVICE_URL.cert.pem ca-chain.cert.pem
La best practice attuale per la distribuzione dei certificati è seguita qui utilizzando il servizio di individuazione secret (SDS) anziché il montaggio di file. Questa pratica evita di riavviare i pod quando aggiungi un nuovo certificato. A partire da Istio 1.8/1.9, con questa tecnica non avrai più bisogno dei diritti di accesso in lettura (RBAC) per il secret dei gateway.
Aggiungi i certificati a
DestinationRule
e assegnagli il nomeclient-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
Applica la definizione YAML precedente al cluster client:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-external-service.yaml
Questa regola funziona solo se hai già creato il secret. Il secret assicura che i certificati vengano utilizzati per la crittografia mTLS dal gateway in uscita all'endpoint esterno.
Una volta completati questi passaggi, la configurazione lato client è completa e si presenta come nel diagramma seguente.
Configurazione lato server
Come discusso nella guida concettuale, per il lato server devi configurare il gateway in entrata in Anthos Service Mesh. Prima di creare i file necessari, è consigliabile rivedere quali componenti sono necessari per realizzare la parte server della soluzione.
Essenzialmente, vuoi identificare il traffico in entrata in base all'origine e al certificato. Inoltre, vuoi instradare specificamente solo quel traffico verso la sua destinazione, il database MySQL in un container. In genere per eseguire questa operazione viene utilizzato un servizio in Kubernetes, ma in questo esempio devi identificare il traffico in entrata all'interno della comunicazione mesh, quindi è necessaria una definizione speciale di un servizio che includa quanto segue:
- Certificati TLS (come secret)
- Gateway in entrata
- Servizio virtuale
Crea il secret per il gateway in entrata
Come hai fatto per il gateway in uscita, hai bisogno degli stessi certificati per proteggere la comunicazione per il gateway in entrata. A questo scopo, archivia i certificati in un secret e definisci questo secret con l'oggetto gateway in entrata.
In Cloud Shell, copia i file generati nella posizione da cui stai eseguendo il comando successivo:
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
Crea il 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
Hai appena aggiunto i seguenti file di certificato al secret:
server-$SERVICE_URL.key.pem server-$SERVICE_URL.cert.pem ca-chain.cert.pem
Definisci il gateway in entrata
Per ricevere il traffico dal cluster lato client, devi specificare un gateway in entrata che possa decriptare e verificare la comunicazione TLS utilizzando i certificati.
Questo diagramma mostra dove si trova il gateway in entrata nel cluster. Il traffico attraversa e viene ispezionato se soddisfa i criteri di sicurezza e di inoltro.
In Cloud Shell, usa il seguente file YAML e assegnagli il nome
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
Applica la definizione YAML precedente al cluster client:
kubectl --context ${SERVER_CLUSTER} apply -f server-ingress-gatway.yaml
Presta attenzione alla sezione
tls:
perché è particolarmente importante. In questa sezione devi specificare se vuoi utilizzare mTLS. Per assicurarti che questa operazione funzioni come previsto, devi fornire il secret che hai creato, che contiene i certificati.Abilita la porta
13306
applicando una patch al servizio in entrata. Per abilitare questa porta, crea il seguente file JSON e assegnagli il nomegateway-patch.json
:cat <<EOF > gateway-patch.json [{ "op": "add", "path": "/spec/ports/0", "value": { "name": "tls-mysql", "protocol": "TCP", "targetPort": 13306, "port": 13306 } }] EOF
Applica la patch al servizio gateway:
kubectl --context ${SERVER_CLUSTER} -n istio-system patch --type=json svc istio-ingressgateway -p "$(cat gateway-patch.json)"
Ora che hai aperto la porta sul gateway in entrata, devi recuperare il traffico proveniente dal nuovo gateway in entrata e indirizzarlo al pod del database. Per farlo, utilizza un oggetto interno mesh: il servizio virtuale.
Definisci il servizio virtuale
Come già detto, il servizio virtuale è una definizione di pattern di corrispondenza del traffico che modellano il traffico all'interno del tuo mesh. Devi identificare e inoltrare correttamente il traffico dal gateway in entrata verso il servizio DB MySQL, come illustrato nel diagramma seguente.
In Cloud Shell, crea il seguente file YAML e assegnagli il nome
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
È importante che questo servizio virtuale faccia riferimento al gateway in entrata da cui proviene il traffico. Il gateway è denominato
gateway-mysql
.Poiché questo servizio virtuale viene applicato sulla versione L4, devi fornire un flag
tcp
per descrivere il traffico MySQL. Questo flag indica fondamentalmente alla mesh che L4 viene utilizzato per questo traffico.Potresti aver notato che il servizio in entrata utilizza la porta
13306
per inoltrare il traffico. Il servizio virtuale lo acquisisce e lo traduce in3306
.Infine, inoltri il traffico al server MySQL nel cluster Kubernetes del server. Per questo esempio, il server è in ascolto sulla porta MySQL standard
3306
.Applica la definizione YAML al cluster di server:
kubectl --context ${SERVER_CLUSTER} apply -f server-virtual-service.yaml
Queste due definizioni decriptano la richiesta del client MySQL incapsulata in mTLS e la inoltrano al database MySQL all'interno del mesh.
È importante capire che anche l'inoltro interno del mesh viene eseguito utilizzando la crittografia, ma in questo caso la crittografia si basa su certificati interni del mesh. La terminazione di mTLS avviene al gateway.
Ora puoi disporre di un modo di comunicare completamente e reciprocamente con il tuo server MySQL. Questa forma di crittografia è trasparente per il client e il server MySQL, quindi non sono necessarie modifiche all'applicazione. Ciò semplifica le attività come la modifica o la rotazione dei certificati. Inoltre, questo metodo di comunicazione può essere utilizzato in molti scenari diversi.
Test della configurazione
Ora che hai configurato sia il lato client che il lato server, puoi provare la configurazione.
È il momento di generare traffico dal lato client al lato server. Devi seguire il flusso di traffico e assicurarti che venga instradato, criptato e decriptato come previsto.
In Cloud Shell, esegui il deployment del server MySQL nel cluster di server:
kubectl --context ${SERVER_CLUSTER} apply -f server/mysql-server/mysql.yaml
Avvia un client MySQL sul cluster client:
kubectl run --context ${CLIENT_CLUSTER} --env=SERVICE_URL=$SERVICE_URL -it --image=mysql:5.6 mysql-client-1 --restart=Never -- /bin/bash
All'avvio del container, viene visualizzata una shell, che dovrebbe avere il seguente aspetto:
root@mysql-client-1:/#
Connettiti al server MySQL:
mysql -pyougottoknowme -h $SERVICE_URL
Utilizza i seguenti comandi per aggiungere un database e una tabella:
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");
Dopo aver collegato e aggiunto la tabella, esci dalla connessione MySQL e dal pod:
exit exit
Devi digitare exit due volte: per prima cosa, per uscire dalla connessione DB, e per la seconda volta, per uscire dal pod. Se il pod smette di rispondere all'uscita, premi Ctrl+C per uscire dalla shell bash.
Seguendo questi passaggi, dovresti aver generato un output di logging significativo che ora puoi analizzare ulteriormente.
Nella sezione successiva, verificherai che il traffico lato client passi il proxy e il gateway in uscita. Puoi anche verificare se riesci a vedere il traffico che entra sul lato server attraverso il gateway in entrata.
Testare il proxy lato client e il gateway in uscita
In Cloud Shell, sul proxy lato client, verifica di poter visualizzare i log del proxy Istio:
kubectl --context ${CLIENT_CLUSTER} logs -l run=mysql-client-1 -c istio-proxy -f
L'output di debug è simile al seguente:
[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 - -
Premi Ctrl+C per uscire dall'output del log.
In questa voce di log puoi vedere che il client richiede il server in esecuzione sull'indirizzo IP
34.66.165.46
sulla porta3306
. La richiesta viene inoltrata (outbound
) aistio-egressgateway
in ascolto sulla porta15443
dell'indirizzo IP192.168.1.4
. Hai definito questo forwarding nel tuo servizio virtuale (client-virtual-service.yaml
).Leggi i log del proxy del gateway in uscita:
kubectl --context ${CLIENT_CLUSTER} logs -n istio-system -l app=istio-egressgateway -f
L'output di debug è simile al seguente:
[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 -
Premi Ctrl+C per uscire dall'output del log.
In questa voce di log, puoi vedere che la richiesta client instradata a
istio-egressgateway
in ascolto sulla porta192.168.1.4
dell'indirizzo IP15443
viene ulteriormente instradata all'esterno del mesh di servizi al servizio esterno in ascolto sull'indirizzo IP34.66.165.46
sulla porta13306.
Hai definito questo forwarding nella seconda parte del tuo servizio virtuale (client-virtual-service.yaml
).
Testa il gateway in entrata lato server
In Cloud Shell, sul lato server, visualizza i log del proxy del gateway in entrata:
kubectl --context ${SERVER_CLUSTER} logs -n istio-system -l app=istio-ingressgateway -f
L'output nel log è simile al seguente:
[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 -
Premi Ctrl+C per uscire dall'output del log.
In questa voce di log puoi vedere che la richiesta del client esterno instradata a
istio-ingressgateway
in ascolto sulla porta34.66.165.46
dell'indirizzo IP13306
è ulteriormente instradata al servizio MySQL all'interno del mesh identificato dal nome del serviziomysql.default.svc.cluster.local
sulla porta3306.
. Hai definito questo forwarding nel gateway in entrata (server-ingress-gateway.yaml
).Per il server MySQL, visualizza i log del proxy Istio:
kubectl --context ${SERVER_CLUSTER} logs -l app=mysql -c istio-proxy -f
L'output è simile al seguente:
[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 -
Premi Ctrl+C per uscire dall'output del log.
In questa voce di log puoi vedere la chiamata in entrata al server di database MySQL in ascolto sulla porta
3306
dell'indirizzo IP100.96.4.8
. La chiamata proviene dal pod in entrata con l'indirizzo IP100.96.1.3
.Per ulteriori informazioni sul formato di logging di Envoy, vedi Recupero dei log degli accessi di Envoy.
Testa il database per visualizzare l'input generato:
MYSQL=$(kubectl --context ${SERVER_CLUSTER} get pods -n default | tail -n 1 | awk '{print $1}') kubectl --context ${SERVER_CLUSTER} exec $MYSQL -ti -- /bin/bash
Verifica il database creato:
mysql -pyougottoknowme USE test_encrypted_connection; SELECT * from message;
L'output è simile al seguente:
+------+-----------+ | id | content | +------+-----------+ | 1 | Crypto Hi | +------+-----------+ 1 row in set (0.00 sec)
Esci dal database MySQL:
exit exit
Devi digitare
exit
due volte: per prima cosa, per uscire dalla connessione DB, e poi per uscire dal pod.
Verifica l'accesso omettendo i certificati
Ora che hai testato e verificato che l'accesso funzioni utilizzando i certificati inseriti, testa anche l'opposto: cosa succede se ometti il gateway in uscita e l'inserimento del certificato. Questo test è anche detto test negativo.
Puoi eseguire questo test avviando un altro pod in uno spazio dei nomi senza l'inserimento proxy laterale abilitato.
In Cloud Shell, crea un nuovo spazio dei nomi:
kubectl --context ${CLIENT_CLUSTER} create ns unencrypted
Crea un pod e avvia una shell interattiva all'interno del 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
Prova a connetterti al database dopo l'avvio della shell interattiva:
mysql -pyougottoknowme -h $SERVICE_URL
Dopo 30 secondi, viene visualizzato un output simile al seguente:
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)
Questo avviso è previsto perché questo pod omette il gateway in uscita e sta cercando di raggiungere il gateway in entrata (
$SERVICE_URL
) direttamente tramite internet.Prova a risolvere l'indirizzo IP del servizio:
resolveip $SERVICE_URL
L'output è simile al seguente. Il tuo indirizzo IP sarà diverso.
IP address of 104.154.164.12.nip.io is 104.154.164.12
Questo dimostra che il nome di dominio completo è risolvibile e che la connessione non riuscita è effettivamente dovuta all'inserimento del certificato mancante.
Esci dalla connessione MySQL e dal pod server MySQL:
exit exit
Ulteriori indagini
Un argomento non trattato in questo tutorial è che in genere le configurazioni in uscita sono di proprietà di un'organizzazione o un ruolo diverso nella tua azienda, perché sono ospitate nello spazio dei nomi istio-system
. Configura le autorizzazioni Kubernetes RBAC in modo che solo gli amministratori di rete possano creare e modificare direttamente le risorse illustrate in questo tutorial.
Ora che sai come utilizzare un mesh di servizi per garantire comunicazioni sicure, ti consigliamo di provarlo con un'applicazione che abbia bisogno di uno scambio sicuro di dati e in cui vuoi controllare la crittografia fino al livello del certificato. Per iniziare, puoi installare Anthos Service Mesh.
Prova a utilizzare due cluster GKE e combinali utilizzando la tecnica di questo tutorial. Questa tecnica funziona anche nella piattaforma GKE Enterprise tra due cluster Kubernetes esterni.
I mesh di servizi sono un modo eccellente per aumentare la sicurezza all'interno del cluster e dei servizi esterni. Un ultimo caso d'uso da provare è avere un endpoint mTLS che non sia un secondo cluster Kubernetes, ma un provider di terze parti (come un fornitore di servizi di pagamento).
Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, puoi eliminare il tuo progetto.
Elimina il progetto
- Nella console Google Cloud, vai alla pagina Gestisci risorse.
- Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
- Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.
Passaggi successivi
- Leggi la guida al concetto di companion.
- Per ulteriori best practice sulla configurazione del gateway in uscita, consulta Uso dei gateway in uscita di Anthos Service Mesh sui cluster GKE: tutorial.
- Consulta la guida alla protezione di GKE e il modulo Terraform allegato.
- Esplora le architetture di riferimento, i diagrammi e le best practice su Google Cloud. Dai un'occhiata al nostro Cloud Architecture Center.