Cloud Service Mesh por exemplo: mTLS

No Cloud Service Mesh 1.5 e posterior, o TLS mútuo automático (mTLS automático) está ativado por predefinição. Com o mTLS automático, um proxy sidecar do lado do cliente deteta automaticamente se o servidor tem um sidecar. O sidecar do cliente envia mTLS para cargas de trabalho com sidecars e envia texto simples para cargas de trabalho sem sidecars. No entanto, os serviços aceitam tráfego de texto simples e mTLS. À medida que injeta proxies sidecar nos seus pods, recomendamos que também configure os seus serviços para aceitarem apenas tráfego mTLS.

Com a malha de serviços na nuvem, pode aplicar o mTLS, fora do código da sua aplicação, através da aplicação de um único ficheiro YAML. O Cloud Service Mesh oferece-lhe a flexibilidade de aplicar uma política de autenticação a toda a malha de serviços, a um espaço de nomes ou a uma carga de trabalho individual.

mTLS mútuo

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Quando terminar este tutorial, pode evitar custos contínuos eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

Antes de começar

Implemente um gateway de entrada

  1. Defina o contexto atual de kubectl para o cluster:

    gcloud container clusters get-credentials CLUSTER_NAME  \
    --project=PROJECT_ID \
    --zone=CLUSTER_LOCATION 
    
  2. Crie um espaço de nomes para o gateway de entrada:

    kubectl create namespace asm-ingress
    
  3. Ative o espaço de nomes para injeção. Os passos dependem da sua implementação do plano de controlo.

    Gerido (TD)

    Aplique a etiqueta de injeção predefinida ao espaço de nomes:

    kubectl label namespace asm-ingress \
        istio.io/rev- istio-injection=enabled --overwrite
    

    Gerido (Istiod)

    Recomendado: execute o seguinte comando para aplicar a etiqueta de injeção predefinida ao espaço de nomes:

      kubectl label namespace asm-ingress \
          istio.io/rev- istio-injection=enabled --overwrite
    

    Se for um utilizador existente com o plano de controlo do Istiod gerido: recomendamos que use a injeção predefinida, mas a injeção baseada em revisões é suportada. Siga as instruções abaixo:

    1. Execute o seguinte comando para localizar os canais de lançamento disponíveis:

      kubectl -n istio-system get controlplanerevision
      

      O resultado é semelhante ao seguinte:

      NAME                AGE
      asm-managed-rapid   6d7h
      

      Na saída, o valor na coluna NAME é a etiqueta de revisão que corresponde ao canal de lançamento disponível para a versão do Cloud Service Mesh.

    2. Aplique a etiqueta de revisão ao espaço de nomes:

      kubectl label namespace asm-ingress \
          istio-injection- istio.io/rev=REVISION_LABEL --overwrite
      
  4. Implemente o gateway de exemplo no repositório anthos-service-mesh-samples:

    kubectl apply -n asm-ingress \
    -f docs/shared/asm-ingress-gateway
    

    Resultado esperado:

    serviceaccount/asm-ingressgateway configured
    service/asm-ingressgateway configured
    deployment.apps/asm-ingressgateway configured
    gateway.networking.istio.io/asm-ingressgateway configured
    

Implemente a aplicação de exemplo Online Boutique

  1. Se ainda não o fez, defina o contexto atual de kubectl para o cluster:

      gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. Crie o espaço de nomes para a aplicação de exemplo:

      kubectl create namespace onlineboutique
    
  3. Etiquete o espaço de nomes onlineboutique para injetar automaticamente proxies do Envoy. Siga os passos para ativar a injeção automática de sidecar.

  4. Implemente a app de exemplo, o VirtualService para o front-end e as contas de serviço para as cargas de trabalho. Para este tutorial, vai implementar a Online Boutique, uma app de demonstração de microsserviços.

      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/virtual-service.yaml
      kubectl apply \
      -n onlineboutique \
      -f docs/shared/online-boutique/service-accounts
    

Veja os seus serviços

  1. Veja os pods no espaço de nomes onlineboutique:

    kubectl get pods -n onlineboutique
    

    Resultado esperado:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    Todos os pods da sua aplicação devem estar em funcionamento, com um 2/2 na coluna READY. Isto indica que os pods têm um proxy sidecar do Envoy injetado com êxito. Se não for apresentado 2/2 após alguns minutos, visite o guia de resolução de problemas.

  2. Obtenha o IP externo e defina-o para uma variável:

    kubectl get services -n asm-ingress
    export FRONTEND_IP=$(kubectl --namespace asm-ingress \
    get service --output jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}' \
    )
    

    Vê um resultado semelhante ao seguinte:

    NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                      AGE
    asm-ingressgateway   LoadBalancer   10.19.247.233   35.239.7.64   80:31380/TCP,443:31390/TCP,31400:31400/TCP   27m
    
    
  3. Visite o endereço EXTERNAL-IP no seu navegador de Internet. Deve ver a loja Online Boutique no seu navegador.

    Interface de loja online

Crie um pod TestCurl

Crie um pod TestCurl para enviar tráfego de texto simples para testes.

  apiVersion: v1
  kind: Pod
  metadata:
    name: testcurl
    namespace: default
    annotations:
      sidecar.istio.io/inject: "false"
  spec:
    containers:
    - name: curl
      image: curlimages/curl
      command: ["sleep", "600"]

Aceda à boutique online

  1. Defina o contexto atual de kubectl para o cluster onde implementou a Online Boutique:

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  2. Liste os serviços no espaço de nomes frontend:

    kubectl get services -n frontend
    

    Repare que frontend-external é um LoadBalancer e tem um endereço IP externo. A aplicação de exemplo inclui um serviço que é um balanceador de carga para que possa ser implementado no GKE sem a malha de serviços da nuvem.

  3. Visite a aplicação no navegador através do endereço IP externo do serviço frontend-external:

    http://FRONTEND_EXTERNAL_IP/
    
  4. O Cloud Service Mesh oferece-lhe a capacidade de implementar um gateway de entrada. Também pode aceder à Online Boutique através do endereço IP externo do gateway de entrada. Obtenha o IP externo do gateway. Substitua os marcadores de posição pelas seguintes informações:

    • GATEWAY_SERVICE_NAME : O nome do serviço de gateway de entrada. Se implementou o gateway de exemplo sem modificações ou se implementou o gateway de entrada predefinido, o nome é istio-ingressgateway.
    • GATEWAY_NAMESPACE: o espaço de nomes no qual implementou a gateway de entrada. Se implementou o gateway de entrada predefinido, o espaço de nomes é istio-system.
    kubectl get service GATEWAY_NAME -n GATEWAY_NAMESPACE
    
  5. Abra outro separador no navegador e visite a aplicação através do endereço IP externo do gateway de entrada:

    http://INGRESS_GATEWAY_EXTERNAL_IP/
    
  6. Execute o seguinte comando para curl o serviço frontend com HTTP simples a partir de outro pod. Como os serviços estão em espaços de nomes diferentes, tem de usar o comando curl no nome DNS do serviço frontend.

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    O seu pedido é bem-sucedido com o estado 200, porque, por predefinição, o tráfego TLS e de texto simples é aceite.

Ative o TLS mútuo por espaço de nomes

Aplica o mTLS aplicando uma política PeerAuthentication com kubectl.

  1. Guarde a seguinte política de autenticação como mtls-namespace.yaml.

    cat <<EOF > mtls-namespace.yaml
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "namespace-policy"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    A linha mode: STRICT no YAML configura os serviços para aceitarem apenas mTLS. Por predefinição, o valor é PERMISSIVE, o que configura os serviços para aceitarem texto simples e mTLS.mode

  2. Aplique a política de autenticação para configurar todos os serviços da Online Boutique de modo a aceitarem apenas mTLS:

    for ns in ad cart checkout currency email frontend loadgenerator \
         payment product-catalog recommendation shipping; do
    kubectl apply -n $ns -f mtls-namespace.yaml
    done
    

    Resultado esperado:

    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created
    peerauthentication.security.istio.io/namespace-policy created

  3. Aceda ao separador no navegador que acede à Online Boutique através do endereço IP externo do serviço frontend-external:

    http://FRONTEND_EXTERNAL_IP/
    
  4. Atualize a página. O navegador apresenta o seguinte erro:

    Não é possível aceder ao site

    A atualização da página faz com que o texto simples seja enviado para o serviço frontend. Devido à STRICTpolítica de autenticação, o proxy sidecar bloqueia o pedido ao serviço.

  5. Aceda ao separador no navegador que acede à loja online através do endereço IP externo do istio-ingressgateway e atualize a página, que é apresentada com êxito. Quando acede à Online Boutique através do gateway de entrada, o pedido segue o seguinte caminho:

    mTLS mútuo

    Fluxo de autenticação mTLS:

    1. O navegador envia um pedido HTTP de texto simples para o servidor.
    2. O contentor do proxy do gateway de entrada interceta o pedido.
    3. O proxy de gateway de entrada faz um handshake TLS com o proxy do lado do servidor (o serviço de front-end neste exemplo). Esta negociação inclui uma troca de certificados. Estes certificados são pré-carregados nos contentores de proxy pelo Cloud Service Mesh.
    4. O proxy do gateway de entrada faz uma verificação de nomenclatura segura no certificado do servidor, validando se uma identidade autorizada está a executar o servidor.
    5. O gateway de entrada e os proxies do servidor estabelecem uma ligação TLS mútua, e o proxy do servidor encaminha o pedido para o contentor da aplicação do servidor (o serviço de frontend).
  6. Execute o seguinte comando para curl o serviço frontend com HTTP simples a partir de outro pod.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    O seu pedido falha porque estamos a enviar tráfego de texto simples a partir de uma carga de trabalho sem sidecar onde é aplicada a política STRICT peerAuthentication.

Encontre e elimine políticas de autenticação

  1. Para ver uma lista de todas as PeerAuthenticationpolíticas na malha de serviços:

    kubectl get peerauthentication --all-namespaces
    

    O resultado é semelhante ao seguinte:

    NAMESPACE         NAME               MODE     AGE
    ad                namespace-policy   STRICT   17m
    cart              namespace-policy   STRICT   17m
    checkout          namespace-policy   STRICT   17m
    currency          namespace-policy   STRICT   17m
    email             namespace-policy   STRICT   17m
    frontend          namespace-policy   STRICT   17m
    loadgenerator     namespace-policy   STRICT   17m
    payment           namespace-policy   STRICT   17m
    product-catalog   namespace-policy   STRICT   17m
    recommendation    namespace-policy   STRICT   17m
    shipping          namespace-policy   STRICT   17m
    
  2. Elimine a política de autenticação de todos os espaços de nomes da Online Boutique:

    for ns in ad cart checkout currency email frontend loadgenerator payment \
      product-catalog recommendation shipping; do
        kubectl delete peerauthentication -n $ns namespace-policy
    done;
    

    Resultado esperado:

    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    peerauthentication.security.istio.io "namespace-policy" deleted
    
  3. Aceda à Online Boutique através do endereço IP externo do serviço frontend-external e atualize a página. A página é apresentada conforme esperado.

  4. Execute o seguinte comando para curl o serviço frontend com HTTP simples a partir de outro pod.

    kubectl debug --image istio/base --target istio-proxy -it \
      $(kubectl get pod -l app=productcatalogservice -n product-catalog -o jsonpath={.items..metadata.name}) \
      -n product-catalog -- \
      curl http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    O seu pedido é bem-sucedido com o estado 200, porque, por predefinição, o tráfego TLS e de texto simples é aceite.

Se atualizar a página na Google Cloud consola que apresenta a lista de Workloads, esta mostra agora que o estado do mTLS é Permissive.

Ative o TLS mútuo por carga de trabalho

Para definir uma política de PeerAuthentication para uma carga de trabalho específica, tem de configurar a secção selector e especificar as etiquetas que correspondem à carga de trabalho pretendida. No entanto, a Cloud Service Mesh não pode agregar políticas ao nível da carga de trabalho para tráfego mTLS de saída para um serviço. Tem de configurar uma regra de destino para gerir esse comportamento.

  1. Aplique uma política de autenticação a uma carga de trabalho específica. Repare como a política seguinte usa etiquetas e seletores para segmentar a implementação específica.frontend

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "frontend"
      namespace: "frontend"
    spec:
      selector:
        matchLabels:
          app: frontend
      mtls:
        mode: STRICT
    EOF
    

    Resultado esperado:

    peerauthentication.security.istio.io/frontend created
  2. Configure uma regra de destino correspondente.

    cat <<EOF | kubectl apply -n frontend -f -
    apiVersion: "networking.istio.io/v1alpha3"
    kind: "DestinationRule"
    metadata:
      name: "frontend"
    spec:
      host: "frontend.demo.svc.cluster.local"
      trafficPolicy:
        tls:
          mode: ISTIO_MUTUAL
    EOF
    

    Resultado esperado:

    destinationrule.networking.istio.io/frontend created
  3. Aceda à Online Boutique através do endereço IP externo do serviço frontend-external e atualize a página. A página não é apresentada porque o frontend service está definido como STRICT mTLS e o proxy sidecar bloqueia o pedido.

  4. Execute o seguinte comando para curl o serviço frontend com HTTP simples a partir de outro pod.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    O seu pedido falha porque estamos a enviar tráfego de texto simples a partir de uma carga de trabalho sem sidecar onde é aplicada a política STRICT peerAuthentication.

  5. Elimine a política de autenticação:

    kubectl delete peerauthentication -n frontend frontend
    

    Resultado esperado:

    peerauthentication.security.istio.io "frontend" deleted
    
  6. Elimine a regra de destino:

    kubectl delete destinationrule -n frontend frontend
    

    Resultado esperado:

    destinationrule.networking.istio.io "frontend" deleted
    

Aplicar mTLS em toda a malha

Para impedir que todos os seus serviços na malha aceitem tráfego de texto simples, defina uma política ao nível da malha com o modo mTLS definido como STRICT.PeerAuthentication A política PeerAuthentication ao nível da malha não deve ter um seletor e tem de ser aplicada no espaço de nomes raiz, istio-system. Quando implementa a política, o plano de controlo aprovisiona automaticamente certificados TLS para que as cargas de trabalho possam autenticar-se entre si.

  1. Aplique o mTLS em toda a malha:

    kubectl apply -f - <<EOF
    apiVersion: "security.istio.io/v1beta1"
    kind: "PeerAuthentication"
    metadata:
      name: "mesh-wide"
      namespace: "istio-system"
    spec:
      mtls:
        mode: STRICT
    EOF
    

    Resultado esperado:

    peerauthentication.security.istio.io/mesh-wide created

  2. Aceda à Online Boutique através do endereço IP externo do serviço frontend-external e atualize a página. A página não é apresentada.

  3. Execute o seguinte comando para curl o serviço frontend com HTTP simples a partir de outro pod.

    kubectl exec testcurl -n default -- curl \
      http://frontend.frontend.svc.cluster.local:80/ -o /dev/null -s -w '%{http_code}\n'
    

    O seu pedido falha porque estamos a enviar tráfego de texto simples a partir de uma carga de trabalho sem sidecar onde é aplicada a política STRICT peerAuthentication.

  4. Elimine a política mesh-wide:

    kubectl delete peerauthentication -n istio-system mesh-wide
    

    Resultado esperado:

    peerauthentication.security.istio.io "mesh-wide" deleted
    

Limpar

Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

  • Se quiser evitar cobranças adicionais, elimine o cluster:

    gcloud container clusters delete  CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    
  • Se quiser manter o cluster e remover o exemplo da loja online:

    1. Elimine os espaços de nomes da aplicação:
      kubectl delete -f online-boutique/kubernetes-manifests/namespaces
    

    Resultado esperado:

    namespace "ad" deleted
    namespace "cart" deleted
    namespace "checkout" deleted
    namespace "currency" deleted
    namespace "email" deleted
    namespace "frontend" deleted
    namespace "loadgenerator" deleted
    namespace "payment" deleted
    namespace "product-catalog" deleted
    namespace "recommendation" deleted
    namespace "shipping" deleted
    
    1. Elimine as entradas de serviço:
      kubectl delete -f online-boutique/istio-manifests/allow-egress-googleapis.yaml
    

    Resultado esperado:

    serviceentry.networking.istio.io "allow-egress-googleapis" deleted
    serviceentry.networking.istio.io "allow-egress-google-metadata" deleted
    

O que se segue?