Anthos Service Mesh 1.6

Como integrar o IAP com o Anthos Service Mesh

Neste guia, explicamos como integrar o Identity-Aware Proxy (IAP) ao Anthos Service Mesh. A integração do IAP ao Anthos Service Mesh permite acessar serviços de maneira segura com base nos princípios do BeyondCorp do Google. O IAP verifica a identidade do usuário e o contexto da solicitação para determinar se o usuário pode acessar um aplicativo ou recurso. A integração do IAP com o Anthos Service Mesh oferece as seguintes vantagens:

  • Controle total de acesso baseado no contexto das cargas de trabalho em execução no Anthos Service Mesh. É possível definir políticas de acesso detalhadas com base nos atributos da solicitação de origem, como identidade do usuário, endereço IP e tipo de dispositivo. É possível combinar políticas de acesso com restrições baseadas no nome do host e no caminho de um URL de solicitação.

  • Ativação do suporte para declarações contextuais na autorização do Anthos Service Mesh.

  • Acesso escalonável, seguro e altamente disponível ao aplicativo por meio de um balanceador de carga do Google Cloud. O balanceamento de carga de alto desempenho fornece proteção integrada contra ataques distribuídos de negação de serviço (DDoS, na sigla em inglês) e suporte para endereços IP anycast globais.

Pré-requisitos

Veja o que é necessário para seguir este guia:

Como configurar um cluster com o Anthos Service Mesh

Para configurar um cluster do GKE no Google Cloud, siga o guia Como instalar o Anthos Service Mesh no GKE no Google Cloud. Quando seguir o outro guia, siga estas etapas:

  1. Ao configurar o projeto, ative iap.googleapis.com ao ativar as outras APIs exigidas pelo Anthos Service Mesh.

  2. O cluster que você está atualizando precisa ter a opção --addons=HttpLoadBalancing definida. O complemento HttpLoadBalancing ativa um controlador de balanceamento de carga HTTP (L7) no cluster. Execute o seguinte comando para atualizar o cluster com as opções exigidas pelo Anthos Service Mesh:

     gcloud container clusters update ${CLUSTER_NAME} 
    --addons=HttpLoadBalancing

  3. Ao instalar o Anthos Service Mesh, execute o seguinte comando em vez do comando que está no guia:

    istioctl install -f asm/cluster/istio-operator.yaml \
      --set values.gateways.istio-ingressgateway.type=NodePort

    Especifique NodePort para istio-ingressgateway, que configura o Anthos Service Mesh para abrir uma porta específica na malha de serviço. Isso permite que você configure um balanceador de carga, que encaminha o tráfego enviado ao seu nome de domínio para essa porta.

Como reservar um endereço IP estático e configurar o DNS

Para integrar o Identity-Aware Proxy com o Anthos Service Mesh, configure um balanceador de carga do Google Cloud HTTP(S), que requer um nome de domínio que aponte para um endereço IP estático. É possível reservar um endereço IP externo estático, que atribui o endereço ao projeto de maneira indefinida até você liberá-lo explicitamente.

  1. Reserve um endereço IP externo estático.

    gcloud compute addresses create example-static-ip --global
    
  2. Consiga o endereço IP estático:

    gcloud compute addresses describe example-static-ip --global
    
  3. No registrador de domínios, configure um nome de domínio totalmente qualificado (FQDN, na sigla em inglês) com o endereço IP estático. Normalmente, você adiciona um registro A às configurações de DNS. As etapas de configuração e a terminologia para adicionar um registro A para um FQDN variam de acordo com o registrador de domínios.

  4. Defina o nome de domínio em uma variável de ambiente:

    export DOMAIN_NAME=YOUR_DOMAIN_NAME

    Pode levar de 24 a 48 horas para que a configuração de DNS seja propagada. Você pode continuar configurando tudo neste guia, mas não será possível testar a configuração até que as configurações de DNS sejam propagadas.

Como implantar um aplicativo de amostra

Antes de ativar o IAP, você precisa de um aplicativo em execução no cluster do GKE para verificar se todas as solicitações têm uma identidade. Neste guia, usamos a amostra do Bookinfo para demonstrar a configuração do balanceador de carga HTTP(S) e a ativação do IAP.

Siga as etapas para implantar o Bookinfo. Até que você implante o balanceador de carga, o aplicativo Bookinfo não poderá ser acessado fora do cluster do GKE (como em um navegador).

Solicitações externas

O recurso Gateway do Bookinfo, definido em samples/bookinfo/networking/bookinfo-gateway.yaml, usa o istio-ingressgateway pré-configurado. Lembre-se de que, ao implantar o Anthos Service Mesh, você especificou NodePort para istio-ingressgateway, o que abre uma porta específica na malha de serviço. Embora os nós do cluster tenham endereços IP externos, as solicitações provenientes de fora do cluster são bloqueadas pelas regras de firewall do Google Cloud. Com o IAP, a maneira correta de expor aplicativos na Internet pública é usando um balanceador de carga. Não exponha os endereços de nós usando regras de firewall, que ignoram o IAP.

Para encaminhar solicitações ao Bookinfo, configure um balanceador de carga HTTP(S) no projeto do Cloud. Como o balanceador de carga está no projeto, ele está dentro do firewall e pode acessar os nós do cluster. Depois de configurar o balanceador de carga com o endereço IP estático e o nome de domínio, envie solicitações para o nome de domínio, e o balanceador de carga encaminhará as solicitações para os nós do cluster.

Como implantar o balanceador de carga

É possível usar um recurso da Entrada para criar um balanceador de carga HTTP(S) com certificados SSL configurados automaticamente. Os certificados SSL gerenciados pelo Google são provisionados, renovados e gerenciados para seu domínio.

  1. Crie um recurso ManagedCertificate. Este recurso especifica o domínio do certificado SSL. A lista spec.domains precisa conter apenas um domínio. Domínios com caracteres curinga não são compatíveis.

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.gke.io/v1beta1
    kind: ManagedCertificate
    metadata:
      name: example-certificate
      namespace: istio-system
    spec:
      domains:
        - ${DOMAIN_NAME}
    EOF
  2. Para criar o balanceador de carga, defina o recurso da Entrada.

    • Defina a anotação networking.gke.io/managed-certificates como o nome do certificado criado na etapa anterior, example-certificate.

    • Defina a anotação kubernetes.io/ingress.global-static-ip-name como o nome do endereço IP estático reservado, example-static-ip.

    • Defina serviceName como istio-ingressgateway, que é usado no recurso Gateway para a amostra Bookinfo.

    cat <<EOF | kubectl create -f -
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: istio-system
      annotations:
        kubernetes.io/ingress.global-static-ip-name: example-static-ip
        networking.gke.io/managed-certificates: example-certificate
    spec:
      backend:
        serviceName: istio-ingressgateway
        servicePort: 80
    EOF
  3. No Console do Cloud, acesse a página Kubernetes Engine > Serviços e Entrada.

    Acessar a página "Serviços e Entrada"

    Você verá a mensagem "Criando entrada" na coluna Status. Aguarde até que o GKE provisione totalmente a Entrada antes de continuar. Atualize a página periodicamente para ver o status mais atualizado da Entrada. Depois que a Entrada for provisionada, você verá o status "Ok" ou o erro "Todos os serviços de back-end estão no estado NÃO ÍNTEGRO". Um dos recursos provisionados pelo GKE é uma verificação de integridade padrão. Se você vir a mensagem de erro, isso indica que a Entrada foi provisionada e que a verificação de integridade padrão foi executada. Quando aparecer o status "Ok" ou o erro, passe para a próxima seção para configurar as verificações de integridade do balanceador de carga.

Configurar verificações de integridade para o balanceador de carga.

Para configurar as verificações de integridade, você precisa conseguir o ID da verificação de integridade padrão criada pela Entrada e atualizar a verificação de integridade para que use o caminho e a porta de verificação de integridade do istio-ingress.

  1. Consiga novas credenciais de usuário que serão usadas no Application Default Credentials:

      gcloud auth application-default login

  2. Consiga o ID da verificação de integridade padrão criada pela Entrada:

    1. Configure as variáveis de ambiente a seguir:

      • Serviço de back-end: vincula vários grupos de instâncias em um determinado NodePort do serviço.

        BACKEND_SERVICE=$(gcloud compute url-maps list | grep example-ingress | awk '{print $2}' | cut -d'/' -f 2)

      • Verificação de integridade: essa é a verificação de integridade padrão criada automaticamente quando a Entrada é implantada.

        HC=$(gcloud compute backend-services describe ${BACKEND_SERVICE} --global | grep healthChecks | cut -d'/' -f 10 | tail -n 1)

      • Porta de entrada da verificação de integridade: é a porta da verificação de integridade do istio-ingress.

        export HC_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')

      • Caminho de entrada da verificação de integridade: é o caminho de verificação de integridade do istio-ingress.

        export HC_INGRESS_PATH=$(kubectl -n istio-system get deployments istio-ingressgateway -o jsonpath='{.spec.template.spec.containers[?(@.name=="istio-proxy")].readinessProbe.httpGet.path}')

      • API Health check: é a API que você chama para configurar a verificação de integridade.
        export HC_API=https://compute.googleapis.com/compute/v1/projects/${PROJECT_ID}/global/healthChecks/${HC}

    2. Para conseguir a verificação de integridade padrão em um arquivo JSON, chame a API healthChecks:

      curl --request GET  --header "Authorization: Bearer $(gcloud auth application-default print-access-token)" ${HC_API} > health_check.json
  3. Atualize a verificação de integridade para usar o caminho e a porta da verificação de integridade do istio-ingress:

    1. Atualize o arquivo health_check.json da seguinte forma:

      • Defina httpHealthCheck.port como o valor de ${HC_INGRESS_PORT}.
      • Defina httpHealthCheck.requestPath como o valor de ${HC_INGRESS_PATH}.
      • Adicione o seguinte atributo e defina-o como uma string vazia: httpHealthCheck.portSpecification=""

      A maneira mais fácil de fazer isso é usando jq, que vem pré-instalado no Cloud Shell:

      jq ".httpHealthCheck.port=${HC_INGRESS_PORT} | .httpHealthCheck.requestPath=\"${HC_INGRESS_PATH}\" | .httpHealthCheck.portSpecification=\"\"" health_check.json > updated_health_check.json

      Se você executar cat no arquivo updated_health_check.json resultante, ele ficará mais ou menos assim:

      {
      "id": "5062913090021441698",
      "creationTimestamp": "2019-11-12T10:47:41.934-08:00",
      "name": "${HC}",
      "description": "Default kubernetes L7 Loadbalancing health check.",
      "checkIntervalSec": 60,
      "timeoutSec": 60,
      "unhealthyThreshold": 10,
      "healthyThreshold": 1,
      "type": "HTTP",
      "httpHealthCheck": {
        "port": 32394,
        "requestPath": "/healthz/ready",
        "proxyHeader": "NONE",
        "portSpecification": ""
      },
      "selfLink": "https://www.googleapis.com/compute/v1/projects/${PROJECT_ID}/global/healthChecks/${HC}",
      "kind": "compute#healthCheck"
      }
      

      Se você tiver editado o arquivo JSON manualmente, e não usando o comando jq, salve o arquivo como updated_health_check.json para que corresponda ao nome de arquivo no próximo comando.

    2. Atualize a verificação de integridade:

      curl --request PATCH --header "Authorization: Bearer $(gcloud auth application-default print-access-token)" --header "Content-Type: application/json" --data @updated_health_check.json ${HC_API}

    O GKE leva vários minutos para atualizar a verificação de integridade. No Console do Cloud, atualize a página Kubernetes Engine > Serviços e Entrada a cada minuto até que o status da Entrada mude para "Ok".

  4. Teste o balanceador de carga. Aponte seu navegador para:

    http://YOUR_DOMAIN_NAME/productpage

    em que YOUR_DOMAIN_NAME é o nome de domínio que você configurou com o endereço IP estático externo.

    Você verá a productpage do aplicativo Bookinfo. Se você atualizar a página várias vezes, verá diferentes versões das avaliações, apresentadas em estilo round-robin: estrelas vermelhas, estrelas pretas, sem estrelas.

    Teste também o acesso https ao Bookinfo.

Como ativar o IAP

Veja nas etapas a seguir como ativar o IAP.

  1. Verifique se você já tem uma marca usando o comando list. É possível ter apenas uma marca por projeto.

    gcloud alpha iap oauth-brands list
    

    Veja um exemplo de resposta do gcloud, se a marca existir:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    
  2. Se não houver marca, use o comando create:

    gcloud alpha iap oauth-brands create --applicationTitle=APPLICATION_TITLE --supportEmail=SUPPORT_EMAIL
    

    Os campos acima são obrigatórios ao chamar esta API:

    • supportEmail: o e-mail de suporte exibido na tela de consentimento do OAuth. Esse endereço de e-mail pode ser um endereço de usuário ou um alias dos Grupos do Google. Embora as contas de serviço também tenham um endereço de e-mail, elas não são endereços de e-mail válidos e não podem ser usadas ao criar uma marca. No entanto, uma conta de serviço pode ser a proprietária de um Grupo do Google. Crie um novo Grupo do Google ou configure um grupo existente e defina a conta de serviço desejada como proprietário do grupo.

    • applicationTitle: o nome do aplicativo exibido na tela de consentimento do OAuth.

    A resposta contém os seguintes campos:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_NAME]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    

Como criar um cliente OAuth do IAP

  1. Use o comando create para criar um cliente. Use a marca name da etapa anterior.

    gcloud alpha iap oauth-clients create projects/PROJECT-ID/brands/BRAND-ID --display_name=NAME
    

    A resposta contém os seguintes campos:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_NAME]/identityAwareProxyClients/[CLIENT_ID]
    secret: [CLIENT_SECRET]
    displayName: [NAME]
    

Como ativar o IAP para o serviço

Use o comando a seguir para ativar o IAP para seu serviço. Substitua CLIENT_ID e CLIENT_SECRET pelo ID do cliente OAuth e pela chave secreta do cliente criados anteriormente.

gcloud beta iap web enable \
    --oauth2-client-id=CLIENT_ID \
    --oauth2-client-secret=CLIENT_SECRET \
    --resource-type=backend-services \
    --service=${BACKEND_SERVICE}

Configurar a lista de acesso do IAP

Adicione um usuário à política de acesso do IAP:

gcloud beta iap web add-iam-policy-binding \
    --member=user:EMAIL_ADDRESS \
    --role=roles/iap.httpsResourceAccessor \
    --resource-type=backend-services \
    --service=$BACKEND_SERVICE

em que EMAIL_ADDRESS é o endereço de e-mail completo do usuário, como alice@example.com.

Ativar o suporte ao RCToken na malha de serviço

Por padrão, o IAP gera um JSON Web Token (JWT) com escopo para o cliente OAuth. No Anthos Service Mesh, é possível configurar o IAP para gerar um RequestContextToken (RCToken), que é um JWT, mas com um público configurável. O RCToken permite configurar o público do JWT para uma string arbitrária, que pode ser usada nas políticas do Anthos Service Mesh para autorização refinada.

Para configurar o RCToken:

  1. Crie uma variável de ambiente para o número do projeto. Esse é o número que foi gerado e atribuído automaticamente ao projeto quando você o criou. Ele não é o mesmo que o ID do projeto.

    export PROJECT_NUMBER=YOUR_PROJECT_NUMBER
  2. Crie uma variável de ambiente para o público do RCToken. Pode ser qualquer string que você quiser.

    export RCTOKEN_AUD="your-rctoken-aud"
    
  3. Busque as configurações existentes do IAP

    gcloud beta iap settings get --format json \
    --project=${PROJECT_NUMBER} --resource-type=compute \
    --service=${BACKEND_SERVICE} > iapSettings.json
    
  4. Atualize IapSettings com o público do RCToken.

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR $RCTOKEN_AUD \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > updatedIapSettings.json
    
    gcloud beta iap settings set updatedIapSettings.json --format json \
    --project=${PROJECT_NUMBER} --resource-type=compute --service=${BACKEND_SERVICE}
    
  5. Ative a autenticação RCToken no gateway de entrada do Istio.

    cat <<EOF | kubectl apply -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "RequestAuthentication"
    metadata:
      name: "ingressgateway-jwt-policy"
      namespace: "istio-system"
    spec:
      selector:
        matchLabels:
          app: istio-ingressgateway
      jwtRules:
      - issuer: "https://cloud.google.com/iap"
        jwksUri: "https://www.gstatic.com/iap/verify/public_key-jwk"
        audiences:
        - $RCTOKEN_AUD
        fromHeaders:
        - name: ingress-authorization
          prefix: "Istio "
        outputPayloadToHeader: "verified-jwt"
        forwardOriginalToken: true
    
  6. Verifique se as solicitações para a productpage do Bookinfo ainda estão bem-sucedidas:

    http://DOMAIN_NAME/productpage

Para testar a política:

  1. Crie um objeto de solicitação IapSettings, mas defina rctokenAud como uma string diferente:

    echo $(cat <<EOF
    {
       "name": "projects/${PROJECT_NUMBER}/iap_web/compute/services/${BACKEND_SERVICE}",
       "applicationSettings": {
         "csmSettings": {
           "rctokenAud": "some-other-arbitrary-string"
         }
       }
     }
    EOF
    ) > request.txt
  2. Chame a API IapSettings para definir o público do RCtoken.

    curl --request PATCH --header "Authorization: Bearer $(gcloud beta auth application-default print-access-token)" ${IAP_SETTINGS_API}
  3. Faça uma solicitação para o Bookinfo productpage e ela falhará:

    http://DOMAIN_NAME/productpage

Como fazer a limpeza

Depois de concluir este tutorial, remova os seguintes recursos para evitar cobranças indesejadas na sua conta:

  1. Exclua o certificado gerenciado:

    kubectl delete managedcertificates example-certificate
  2. Exclua a Entrada, que desaloca os recursos de balanceamento de carga:

    kubectl -n istio-system delete ingress example-ingress

  3. Exclua o endereço IP estático:

    gcloud compute addresses delete example-static-ip --global

    Se fizer isso, exclua o endereço IP do registrador de domínio.

  4. Exclua o cluster, o que exclui os recursos que compõem o cluster, como instâncias de computação, discos e recursos de rede:

    gcloud container clusters delete ${CLUSTER_NAME}