Neste tutorial, descrevemos como usar os gateways de saída e entrada do Anthos Service Mesh para proteger o tráfego entre clusters usando o Transport Layer Security mútuo (mTLS). O tutorial é destinado a administradores de clusters do Kubernetes responsáveis por aspectos da rede, segurança e plataforma. Os controles descritos aqui podem ser especialmente úteis para organizações com requisitos de segurança mais rigorosos ou para cumprir pré-requisitos regulamentares. Este tutorial é acompanhado por um guia de conceito complementar.
Neste tutorial, presumimos que você esteja familiarizado com o Kubernetes e o Anthos Service Mesh.
Objetivos
- Usar o Terraform para configurar a infraestrutura:
- Criar uma rede VPC personalizada com duas sub-redes particulares
- Criar dois clusters do Kubernetes com o Anthos Service Mesh ativado:
- Um cluster do GKE
- Um cluster do Kubernetes Operations (kOps) (em inglês) em execução na rede VPC personalizada
- Registrar clusters no GKE Hub
- Implantar um cliente MySQL no cluster do GKE
- Implantar um servidor MySQL em um cluster do kOps
- Configurar gateways de saída e entrada para expor um servidor usando mTLS
- Testar o acesso a um servidor MySQL usando um cliente MySQL em execução em diferentes clusters ou VPCs
Custos
Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:
- Google Kubernetes Engine (GKE)
- Compute Engine
- Container Registry
- Anthos Service Mesh
- Rede na nuvem e balanceamento de carga
Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços.
Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.
Antes de começar
Para este tutorial, você precisa de um projeto do Google Cloud. É possível criar um novo projeto ou selecionar um que já foi criado:
-
No console do Google Cloud, acesse a página do seletor de projetos.
-
Selecione ou crie um projeto do Google Cloud.
-
Verifique se a cobrança está ativada para o seu projeto do Google Cloud.
No console do Google Cloud, acesse o Cloud Shell.
Na parte inferior do console do Google Cloud, uma sessão do Cloud Shell é aberta e exibe um prompt de linha de comando. O Cloud Shell é um ambiente com a Google Cloud CLI já instalada, incluindo a Google Cloud CLI. A inicialização da sessão pode levar alguns segundos.
- No Cloud Shell, verifique se você está trabalhando no projeto
criado ou selecionado:
export PROJECT_ID=PROJECT_ID gcloud config set project ${PROJECT_ID}
Substitua
PROJECT_ID
pela ID do seu projeto. - Crie uma variável de ambiente para o endereço de e-mail que você usa no
Google Cloud:
export GOOGLE_CLOUD_EMAIL_ADDRESS=GOOGLE_CLOUD_EMAIL_ADDRESS
Substitua
GOOGLE_CLOUD_EMAIL_ADDRESS
pelo endereço de e-mail que você usa no Google Cloud. - Defina a região e a zona para seus recursos de computação:
export REGION=us-central1 export ZONE=us-central1-b gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE}
Este tutorial usa
us-central1
para a região eus-central1-b
para a zona. É possível implantar em uma região de sua escolha. - Defina os papéis necessários de gerenciamento de identidade e acesso (IAM, na sigla em inglês). Se você for
um proprietário do projeto, já terá todas as permissões necessárias para concluir a
instalação. Caso contrário, peça ao administrador para conceder a você
papéis do Identity and Access Management (IAM) executando o seguinte comando no
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
- Ative as APIs necessárias para o 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
Como preparar o ambiente
No Cloud Shell, clone o seguinte repositório:
git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples cd anthos-service-mesh-samples/docs/mtls-egress-ingress
Atualize o Terraform para o ambiente. Por padrão, o console do Google Cloud vem com o Terraform 0.12. Neste tutorial, é preciso que você tenha o Terraform 0.13.5 ou posterior instalado. É possível usar temporariamente outra versão do Terraform executando os seguintes comandos:
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/
Acesse a subpasta
terraform
e inicialize o Terraform:cd terraform/ ~/bin/terraform init
Crie um arquivo
terraform.tfvars
com base nas variáveis de ambiente que você criou anteriormente:cat << EOF > terraform.tfvars project_id = "${PROJECT_ID}" region = "${REGION}" zones = ["${ZONE}"] EOF
Na próxima etapa, você criará a infraestrutura inicial. Para isso, crie e aplique o plano de execução do Terraform nessa configuração. Os scripts e módulos nesse plano criam o seguinte:
- Uma rede VPC personalizada com duas sub-redes particulares
- Dois clusters do Kubernetes com o Anthos Service Mesh ativado
- Um cluster do GKE
- Um cluster do kOps em execução na rede VPC personalizada
O plano de execução também registra clusters no GKE Hub.
Executar o plano de execução:
~/bin/terraform plan -out mtls-terraform-plan ~/bin/terraform apply "mtls-terraform-plan"
A resposta será semelhante a:
Apply complete! Resources: 27 added, 0 changed, 0 destroyed. Outputs: server_token = <sensitive>
A parte
<sensitive>
é uma variável de saída do Terraform que não é exibida no console, mas pode ser consultada. Por exemplo:~/bin/terraform output server_token
.Consiga o arquivo
kubeconfig
do cluster de servidor no diretórioterraform
. Em seguida, mescle-o com o arquivo de configuraçãoclient-cluster
:cd .. export KUBECONFIG=client-server-kubeconfig cp ./terraform/server-kubeconfig $KUBECONFIG gcloud container clusters get-credentials client-cluster --zone ${ZONE} --project ${PROJECT_ID}
O arquivo
client-server-kubeconfig
agora contém a configuração dos dois clusters, que pode ser verificada executando o seguinte comando:kubectl config view -ojson | jq -r '.clusters[].name'
A saída é esta:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Conseguir o contexto dos três clusters para uso posterior:
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}"
A saída é, novamente, esta:
gke_PROJECT_ID_us-central1-c_client-cluster server-cluster.k8s.local
Agora é possível usar esses nomes de cluster como contexto para outros comandos
kubectl
.Fazer referência ao cluster de cliente:
kubectl --context ${CLIENT_CLUSTER} get pods -n istio-system
Fazer referência ao cluster do servidor:
kubectl --context ${SERVER_CLUSTER} get pods -n istio-system
Como configurar o lado do cliente
Conforme mencionado no guia de conceito, o lado do cliente requer que você configure o gateway de saída no Anthos Service Mesh.
Nesta seção, você configura os elementos do Anthos Service Mesh para identificar o tráfego externo com base na origem dele e usar um certificado personalizado na criptografia da comunicação. Além disso, convém rotear especificamente apenas esse tráfego para o destino dele (o banco de dados MySQL em um contêiner). Normalmente, você usa um serviço no Kubernetes para fazer isso. Nesse caso, é necessário capturar esse tráfego dentro da comunicação da malha. Para capturar o tráfego, use elementos do Istio para criar uma definição especial do serviço. Defina os seguintes elementos:
- Gateway de saída
- Entrada de serviço
- Serviço virtual
- Certificados TLS (como um secret)
- Regras de destino
No Cloud Shell, consiga o endereço IP do gateway de entrada no lado do servidor. Para isso, consulte o endereço IP do balanceador de carga do serviço
istio-ingressgateway
usando o contexto do lado do servidor ($SERVER_CLUSTER
que você criou anteriormente):INGRESS_HOST=$(kubectl -n istio-system --context ${SERVER_CLUSTER} get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
Como
INGRESS_HOST
é apenas a parte do endereço IP do host, você precisa criar um nome de domínio totalmente qualificado (FQDN, na sigla em inglês). Essa etapa é necessária porque os certificados exigem um nome de domínio para funcionar corretamente.Neste tutorial, você usa o serviço de DNS curinga nip.io para criar um FQDN para o endereço IP de entrada. Esse serviço permite criar o FQDN sem ter um domínio.
Armazene o URL do serviço FQDN em uma variável de ambiente:
export SERVICE_URL="${INGRESS_HOST}.nip.io"
Agora, com o
SERVICE_URL
definido como um FQDN, é possível começar a definir a parte do Istio do cluster de cliente.
Criar o gateway de saída
Comece criando o gateway de saída para detectar o tráfego destinado ao serviço externo.
No Cloud Shell, crie o seguinte arquivo YAML e nomeie-o como
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
Aplique o arquivo YAML anterior ao cluster do cliente:
kubectl --context ${CLIENT_CLUSTER} apply -f client-egress-gateway.yaml
Preste atenção às portas. Você usou as portas
default
aqui para a chave dos servidores de saída, que é15443
. Se você quiser usar uma porta diferente, edite o objetoservice
do gateway de saída para adicionar portas personalizadas.A chave
hosts
define o endpoint, que é aonde o tráfego precisa ir.
Definir a entrada de serviço
A próxima etapa é informar a malha de serviço sobre o serviço externo. O Istio tem um registro próprio em que armazena endpoints de serviço para a malha. Se o Istio for instalado sobre o Kubernetes, os serviços definidos no cluster serão adicionados automaticamente ao registro do Istio. Com a definição de entrada de serviço, você adiciona um novo endpoint ao registro do Istio, conforme mostrado no diagrama a seguir.
No Cloud Shell, crie o seguinte arquivo YAML e nomeie-o como
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
Aplique o arquivo YAML anterior ao cluster do cliente:
kubectl --context ${CLIENT_CLUSTER} apply -f client-service-entry.yaml
A definição do serviço de cliente neste arquivo YAML informa ao serviço que tipo de tráfego esperar (MySQL L4 - camada de rede 4, usando porta 3306; link em inglês). Você também define que a comunicação será "malha externa". Na seção de endpoints, você define que o fluxo precisa ir para o endereço FQDN
$SERVICE_URL
que você definiu anteriormente e que é mapeado para o gateway de entrada no cluster de servidor (kOps).
Definir o serviço virtual
Um serviço virtual é um conjunto de regras de roteamento de tráfego a serem aplicadas quando um host é resolvido. Cada regra de roteamento define critérios correspondentes para o tráfego de um protocolo específico. Se o tráfego for correspondido, ele será enviado para um serviço de destino nomeado, ou para um subconjunto ou versão dele, definido no registro. Para mais informações, consulte a documentação do Istio (em inglês).
A definição do serviço virtual informa ao Istio como aplicar o roteamento para o
tráfego que está chegando ao serviço externo. Com a definição a seguir, você
configura a malha para rotear o tráfego do cliente ao gateway de saída na porta
15443
. No gateway de saída, você roteia o tráfego para o host
$SERVICE_URL
na porta 13306
(onde o gateway de entrada do lado do servidor está
detectando).
Crie o seguinte arquivo YAML e nomeie-o como
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
Aplique a definição de YAML ao cluster de cliente:
kubectl --context ${CLIENT_CLUSTER} apply -f client-virtual-service.yaml
É possível especificar em quais gateways aplicar a configuração editando a chave
gateways
no arquivo YAML.A parte importante nesta definição é o uso da palavra reservada
mesh
, que abrange todos os arquivos secundários na malha. De acordo com a documentação do Istio, quando esse campo é omitido, o gateway padrão (malha) é usado, aplicando a regra a todos os arquivos secundários na malha. Se você fornecer uma lista de nomes de gateway, as regras serão aplicadas apenas aos gateways. Para aplicar as regras a gateways e arquivos secundários, especifiquemesh
como um dos nomes de gateway.
Na próxima seção, você define como processar o tráfego que está saindo
do proxy do produto do cliente match.gateways.mesh
. Você também define como
rotear o tráfego da saída para o serviço externo usando a
chave match.gateways.istio-egressgateway-mysql
.
Definir uma regra de destino (do cliente ao gateway de saída)
Agora que você já definiu como rotear o tráfego para o serviço externo, defina quais políticas de tráfego devem ser aplicadas. O serviço virtual que você acabou de definir está processando dois casos de roteamento de uma só vez. Um processa o tráfego do proxy sidecar ao gateway de saída e o outro processa o tráfego do gateway de saída ao serviço externo.
Para corresponder esses casos às regras de destino, são necessárias duas regras separadas. O diagrama a seguir mostra a primeira regra, que processa o tráfego do proxy ao gateway de saída. Nessa definição, você configura o Anthos Service Mesh para usar os certificados padrão da comunicação mTLS.
No Cloud Shell, crie o seguinte arquivo YAML e nomeie-o como
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
Aplique a definição YAML anterior ao cluster do cliente:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-egress-gateway.yaml
No arquivo YAML anterior, você usou a chave
hosts
para definir como rotear o tráfego do proxy do cliente ao gateway de saída. Além disso, você configurou a malha para usarISTIO_MUTUAL
na porta15443
, que é uma das portas abertas automaticamente no gateway de saída.
Criar uma regra de destino (do gateway de saída ao serviço externo)
O diagrama a seguir mostra a segunda regra de destino, que informa à malha como processar o tráfego do gateway de saída ao serviço externo.
É necessário configurar a malha para usar seus certificados injetados para comunicação TLS mútua com o serviço externo.
No Cloud Shell, no diretório
anthos-service-mesh-samples/docs/mtls-egress-ingress
, crie os certificados:./create-keys.sh
Forneça uma senha quando o script pedir.
Copie os arquivos gerados para o diretório atual:
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
Crie um secret do Kubernetes que armazena os certificados para serem consultados posteriormente no 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
O comando anterior adiciona os seguintes arquivos de certificado ao secret:
client-$SERVICE_URL.key.pem client-$SERVICE_URL.cert.pem ca-chain.cert.pem
A prática recomendada atual para distribuir certificados é seguida aqui usando o serviço de descoberta de secret (SDS) (em inglês) em vez da montagem de arquivos. Essa prática evita a reinicialização dos pods ao adicionar um novo certificado. A partir do Istio 1.8/1.9, com essa técnica, você não precisa mais dos direitos de acesso de leitura (RBAC, na sigla em inglês) no secret dos gateways.
Adicione os certificados ao
DestinationRule
e nomeie-o comoclient-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
Aplique a definição YAML anterior ao cluster do cliente:
kubectl --context ${CLIENT_CLUSTER} apply -f client-destination-rule-to-external-service.yaml
Essa regra só funciona se você tiver criado o secret com antecedência. O secret garante que os certificados sejam usados para a criptografia do mTLS do gateway de saída ao endpoint externo.
Depois de concluir essas etapas, a configuração do lado do cliente está concluída, e é semelhante ao diagrama a seguir.
Como configurar o lado do servidor
Conforme mencionado no no guia de conceito, você precisa configurar o gateway de entrada no Anthos Service Mesh no lado do servidor. Antes de criar os arquivos necessários, é recomendável revisar quais componentes são necessários para realizar a parte do servidor da solução.
Resumidamente, você quer identificar o tráfego de entrada com base na origem e no certificado dele. Você também quer rotear especificamente esse tráfego ao destino dele: o banco de dados MySQL em um contêiner. Normalmente, você usa um serviço no Kubernetes para fazer isso, mas neste exemplo, você identifica o tráfego de entrada dentro da comunicação da malha. Portanto, você precisa de uma definição especial de um serviço que inclua o seguinte:
- Certificados TLS (como um secret)
- Gateway de entrada
- Serviço virtual
Criar o secret para o gateway de entrada
Assim como no gateway de saída, os mesmos certificados são necessários para proteger a comunicação do gateway de entrada. Para fazer isso, armazene os certificados em um secret e defina-o com o objeto de gateway de entrada.
No Cloud Shell, copie os arquivos gerados para o local em que você está executando o próximo comando:
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
Crie o secret do servidor:
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
Você adicionou os seguintes arquivos de certificado ao secret:
server-$SERVICE_URL.key.pem server-$SERVICE_URL.cert.pem ca-chain.cert.pem
Definir o gateway de entrada
Para receber o tráfego do cluster do lado do cliente, especifique um gateway de entrada que possa descriptografar e verificar a comunicação TLS usando os certificados.
Esse diagrama mostra onde o gateway de entrada se encontra no cluster. O tráfego passará e será inspecionado se atender aos critérios de segurança e encaminhamento.
No Cloud Shell, use o seguinte arquivo YAML e nomeie-o como
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
Aplique a definição YAML anterior ao cluster do cliente:
kubectl --context ${SERVER_CLUSTER} apply -f server-ingress-gatway.yaml
Preste atenção à seção
tls:
porque ela é especialmente importante. Nesta seção, você define que quer o mTLS. Para garantir que isso funcione como esperado, informe o secret criado que contém os certificados.Ative a porta
13306
aplicando o patch do serviço de entrada. Para ativar essa porta, crie o seguinte arquivo JSON e nomeie-o comogateway-patch.json
:cat <<EOF > gateway-patch.json [{ "op": "add", "path": "/spec/ports/0", "value": { "name": "tls-mysql", "protocol": "TCP", "targetPort": 13306, "port": 13306 } }] EOF
Aplique o patch ao serviço do gateway:
kubectl --context ${SERVER_CLUSTER} -n istio-system patch --type=json svc istio-ingressgateway -p "$(cat gateway-patch.json)"
Agora que você abriu a porta no gateway de entrada, será necessário escolher o tráfego proveniente do novo gateway de entrada e direcioná-lo para o pod do banco de dados. Faça isso usando um objeto interno de malha: o serviço virtual.
Definir o serviço virtual
Conforme discutido anteriormente, o serviço virtual é uma definição de padrões de correspondência de tráfego que moldam o tráfego dentro da malha. É necessário identificar e encaminhar corretamente o tráfego do gateway de entrada em direção ao serviço do banco de dados MySQL, conforme mostrado no diagrama a seguir.
No Cloud Shell, crie o seguinte arquivo YAML e nomeie-o como
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 que esse serviço virtual faça referência ao gateway de entrada de origem do tráfego. O gateway é chamado de
gateway-mysql
.Como esse serviço virtual é aplicado na L4, você precisa fornecer um sinalizador
tcp
para descrever o tráfego do MySQL. Basicamente, essa sinalização diz que a L4 é usada para esse tráfego.Você pode ter notado que o serviço de entrada está usando a porta
13306
para encaminhar o tráfego. O serviço virtual o seleciona e o traduz de volta para3306
.Por fim, você está encaminhando o tráfego para o servidor MySQL no cluster do servidor do Kubernetes. Para este exemplo, o servidor está detectando na porta padrão
3306
do MySQL.Aplique a definição YAML ao cluster do servidor:
kubectl --context ${SERVER_CLUSTER} apply -f server-virtual-service.yaml
Essas duas definições descriptografam a solicitação do cliente MySQL encapsulado em mTLS e a encaminham para o banco de dados MySQL dentro da malha.
É importante entender que o encaminhamento interno da malha também é feito usando criptografia, mas, neste caso, a criptografia é baseada em certificados internos da malha. O encerramento do mTLS ocorre no gateway.
Agora você tem uma forma completa e mutuamente criptografada de se comunicar com seu servidor MySQL. Essa forma de criptografia é transparente para o cliente e o servidor MySQL. Portanto, nenhuma alteração de aplicativo é necessária. Isso simplifica tarefas como alterar ou fazer rotação de certificados. Além disso, essa forma de comunicação pode ser usada em muitos cenários diferentes.
Testar a configuração
Agora que os lados do cliente e do servidor estão ativos, teste a configuração.
É hora de gerar tráfego do lado do cliente ao lado do servidor. É recomendável seguir o fluxo do tráfego e garantir que ele seja roteado, criptografado e descriptografado como esperado.
No Cloud Shell, implante o servidor MySQL no cluster do servidor:
kubectl --context ${SERVER_CLUSTER} apply -f server/mysql-server/mysql.yaml
Inicie um cliente MySQL no cluster de cliente:
kubectl run --context ${CLIENT_CLUSTER} --env=SERVICE_URL=$SERVICE_URL -it --image=mysql:5.6 mysql-client-1 --restart=Never -- /bin/bash
Quando o contêiner for iniciado, você verá um shell, que será semelhante ao seguinte:
root@mysql-client-1:/#
Conecte-se ao servidor MySQL:
mysql -pyougottoknowme -h $SERVICE_URL
Use os seguintes comandos para adicionar um banco de dados e uma tabela:
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");
Depois de conectar e adicionar a tabela, saia da conexão do MySQL e do pod:
exit exit
Você precisa digitar "exit" duas vezes: primeiro para sair da conexão de banco de dados e, depois, para sair do pod. Se o pod parar de responder após a saída, pressione Control+C para cancelar o shell bash.
Ao seguir essas etapas, você terá gerado uma saída de geração de registros significativa que agora pode ser analisada.
Na próxima seção, você verificará se o tráfego do lado do cliente está passando pelo proxy e pelo gateway de saída. Teste também se o tráfego está entrando no lado do servidor pelo gateway de entrada.
Testar o proxy do lado do cliente e o gateway de saída
No Cloud Shell, no proxy do cliente, verifique se é possível ver os registros do proxy do Istio:
kubectl --context ${CLIENT_CLUSTER} logs -l run=mysql-client-1 -c istio-proxy -f
A resposta será semelhante a:
[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 - -
Pressione Control+C para sair da saída de registros.
Nesta entrada de registro, é possível ver que o cliente solicita o servidor em execução no endereço IP
34.66.165.46
na porta3306
. A solicitação é encaminhada (outbound
) paraistio-egressgateway
que detecta o endereço IP192.168.1.4
na porta15443
. Você definiu esse encaminhamento no serviço virtual (client-virtual-service.yaml
).Leia os registros de proxy do gateway de saída:
kubectl --context ${CLIENT_CLUSTER} logs -n istio-system -l app=istio-egressgateway -f
A saída de depuração é semelhante a esta:
[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 -
Pressione Control+C para sair da saída de registros.
Nesta entrada de registro, é possível ver que a solicitação do cliente roteada para
istio-egressgateway
que detecta no endereço IP192.168.1.4
, porta15443
é roteada para fora da malha de serviço até o serviço externo que detecta no endereço IP34.66.165.46
, porta13306.
Você definiu esse encaminhamento na segunda parte do serviço virtual (client-virtual-service.yaml
).
Testar o gateway de entrada do lado do servidor
No Cloud Shell, no lado do servidor, para ver os registros de proxy do gateway de entrada:
kubectl --context ${SERVER_CLUSTER} logs -n istio-system -l app=istio-ingressgateway -f
A saída no registro é semelhante a esta:
[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 -
Pressione Control+C para sair da saída de registros.
Nesta entrada de registro, é possível ver que a solicitação do cliente externo roteada para
istio-ingressgateway
que detecta no endereço IP34.66.165.46
, porta13306
é roteada para o serviço MySQL dentro da malha identificada pelo nome do serviçomysql.default.svc.cluster.local
na porta3306.
Você definiu esse encaminhamento no gateway de entrada (server-ingress-gateway.yaml
).No servidor MySQL, para ver os registros de proxy do Istio:
kubectl --context ${SERVER_CLUSTER} logs -l app=mysql -c istio-proxy -f
A resposta será semelhante a:
[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 -
Pressione Control+C para sair da saída de registros.
Nesta entrada de registro, é possível ver a chamada de entrada ao servidor de banco de dados MySQL que detecta no endereço IP
100.96.4.8
, porta3306
. A chamada é proveniente do pod de entrada com o endereço IP100.96.1.3
.Para mais informações sobre o formato de geração de registros do Envoy, consulte Como receber registros de acesso do Envoy (em inglês).
Teste o banco de dados para ver a entrada gerada:
MYSQL=$(kubectl --context ${SERVER_CLUSTER} get pods -n default | tail -n 1 | awk '{print $1}') kubectl --context ${SERVER_CLUSTER} exec $MYSQL -ti -- /bin/bash
Verifique o banco de dados criado:
mysql -pyougottoknowme USE test_encrypted_connection; SELECT * from message;
A resposta será semelhante a:
+------+-----------+ | id | content | +------+-----------+ | 1 | Crypto Hi | +------+-----------+ 1 row in set (0.00 sec)
Para sair do banco de dados MySQL:
exit exit
É necessário digitar
exit
duas vezes: primeiro para sair da conexão do banco de dados e, depois, para sair do pod.
Testar o acesso ao omitir os certificados
Agora que você testou e verificou se o acesso funciona usando os certificados injetados, teste também o oposto: o que acontece se você omitir o gateway de saída e a injeção de certificado. Esse teste também é chamado de teste negativo.
Para executar esse teste, inicie outro pod em um namespace sem a injeção de proxy secundário ativada.
No Cloud Shell, crie um novo namespace:
kubectl --context ${CLIENT_CLUSTER} create ns unencrypted
Crie um pod e inicie um shell interativo dentro do contêiner:
kubectl --context ${CLIENT_CLUSTER} run -it --image=mysql:5.6 \ mysql-client-2 --env=SERVICE_URL=$SERVICE_URL \ -n unencrypted --restart=Never -- /bin/bash
Tente se conectar ao banco de dados quando o shell interativo for iniciado:
mysql -pyougottoknowme -h $SERVICE_URL
Após 30 segundos, você verá uma saída semelhante a esta:
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)
Esse aviso é esperado porque esse pod está omitindo o gateway de saída e tenta alcançar o gateway de entrada (o
$SERVICE_URL
) diretamente pela Internet.Tentar resolver o endereço IP do serviço:
resolveip $SERVICE_URL
A resposta será semelhante a esta: O endereço IP será diferente.
IP address of 104.154.164.12.nip.io is 104.154.164.12
Isso prova que o FQDN pode ser resolvido e que a conexão com falha é realmente devido à injeção de certificado ausente.
Para sair da conexão do MySQL e do pod do servidor MySQL:
exit exit
Investigação detalhada
Um tópico não abordado neste tutorial é que, normalmente, as configurações de saída
pertencem a um papel ou uma organização diferente na sua empresa, porque estão
hospedados no namespace istio-system
. Configure as permissões do RBAC do Kubernetes para
que apenas os administradores de rede possam criar e modificar diretamente os recursos
discutidos neste tutorial.
Agora que você sabe como usar uma malha de serviço para garantir a comunicação segura, teste-a com um aplicativo que precisa trocar dados com segurança e onde você quer controlar a criptografia na camada de certificado. Para começar, instale o Anthos Service Mesh.
Tente usar dois clusters do GKE e combiná-los usando a técnica neste tutorial. Essa técnica também funciona na plataforma Anthos entre dois clusters externos do Kubernetes.
As malhas de serviço são uma excelente maneira de aumentar a segurança no cluster, assim como com os serviços externos. Um último caso de uso a ser testado é ter um endpoint mTLS que não seja um segundo cluster do Kubernetes, mas um provedor terceirizado (como um provedor de pagamento).
Limpeza
Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, exclua o projeto.
Exclua o projeto
- No Console do Google Cloud, acesse a página Gerenciar recursos.
- Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
- Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.
A seguir
- Leia o guia do conceito complementar.
- Para mais práticas recomendadas sobre como configurar o gateway de saída, consulte Como usar gateways de saída do Anthos Service Mesh em clusters do GKE: tutorial.
- Consulte o guia de aumento da proteção do GKE e o módulo do Terraform (em inglês) associado.
- Confira arquiteturas de referência, diagramas e práticas recomendadas do Google Cloud. Confira o Centro de arquitetura do Cloud.