Configurar a limitação de taxa do Google Cloud Armor com o Envoy

Nesta página, mostramos como configurar a limitação de taxa global do lado do servidor para sua malha de serviço usando o Cloud Armor. Use esse recurso para aplicar a limitação de taxa de fairshare a todo o tráfego que chega ao seu serviço. Isso ajuda a compartilhar de maneira justa a capacidade disponível dos seus serviços e mitigar o risco de clientes maliciosos ou com comportamento inadequado sobrecarregarem seus serviços. Para mais informações sobre a limitação de taxa, leia a visão geral da limitação de taxa.

Configurar o Google Kubernetes Engine (GKE) para o Envoy

Antes de começar

Antes de começar, ative as seguintes APIs:

  • container.googleapis.com
  • compute.googleapis.com
  • trafficdirector.googleapis.com
  • networkservices.googleapis.com
  • meshconfig.googleapis.com
  • monitoring.googleapis.com

É possível ativar todas as APIs usando o seguinte comando da Google Cloud CLI:

gcloud services enable \
    container.googleapis.com \
    compute.googleapis.com \
    trafficdirector.googleapis.com \
    networkservices.googleapis.com \
    meshconfig.googleapis.com \
    monitoring.googleapis.com

Em seguida, crie as variáveis de ambiente usadas neste documento:

export PROJECT_ID=PROJECT_ID
export PROJECT_NUMBER="$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")"
export CLUSTER=CLUSTER
export ZONE=ZONE
export MESH_NAME=MESH_NAME
export MESH_URI=projects/${PROJECT_NUMBER}/locations/global/meshes/${MESH_NAME}

Substitua as seguintes variáveis por informações do seu projeto:

  • Substitua PROJECT_ID pelo ID do projeto.
  • Substitua ZONE pela zona em que você pretende criar o cluster do GKE.
  • Substitua CLUSTER pelo nome do cluster.
  • Substitua MESH_NAME pelo nome da malha.

Criar um cluster do GKE

  1. Use o comando a seguir para criar um cluster do GKE na zona especificada na seção anterior:

     gcloud container clusters create "CLUSTER" \
         --zone="ZONE" \
         --scopes="cloud-platform" \
         --tags="allow-envoy-health-checks" \
         --enable-ip-alias
    
  2. Receba as credenciais do novo cluster:

     gcloud container clusters get-credentials "CLUSTER" \
         --zone="ZONE"
    

Ativar a injeção automática

  1. Use o comando a seguir para aplicar o recurso MutatingWebhookConfiguration ao cluster. Quando um pod é criado, o controlador de admissão no cluster é invocado e instrui o injetor de sidecar gerenciado a adicionar o contêiner Envoy ao pod.

    cat <<EOF | kubectl apply -f -
    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
     labels:
       app: sidecar-injector
     name: td-mutating-webhook
    webhooks:
    - admissionReviewVersions:
      - v1beta1
      - v1
      clientConfig:
        url: https://meshconfig.googleapis.com/v1internal/projects/PROJECT_ID/locations/ZONE/clusters/CLUSTER/channels/rapid/targets/${MESH_URI}:tdInject
      failurePolicy: Fail
      matchPolicy: Exact
      name: namespace.sidecar-injector.csm.io
      namespaceSelector:
        matchExpressions:
        - key: td-injection
          operator: Exists
      reinvocationPolicy: Never
      rules:
      - apiGroups:
        - ""
        apiVersions:
        - v1
        operations:
        - CREATE
        resources:
        - pods
        scope: '*'
      sideEffects: None
      timeoutSeconds: 30
    EOF
    
  2. Ative a injeção de sidecar no namespace padrão. O injetor de sidecar injeta contêineres de sidecar para pods criados no namespace padrão.

    kubectl label namespace default td-injection=enabled
    
  3. Salve a seguinte configuração do GKE para seu serviço como service_sample.yaml.

    apiVersion: v1
    kind: Service
    metadata:
     name: service-test
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"80":{"name": "rate-limit-demo-neg"}}}'
    spec:
     ports:
     - port: 80
       name: service-test
       targetPort: 8000
     selector:
       run: app1
     type: ClusterIP
    
    ---
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: app1
     labels:
       run: app1
    spec:
     replicas: 1
     selector:
       matchLabels:
         run: app1
     template:
       metadata:
         labels:
           run: app1
         annotations:
           cloud.google.com/proxyMetadata: '{"app": "rate-limit-demo"}'
           cloud.google.com/includeInboundPorts: "8000"
           cloud.google.com/sidecarProxyVersion: "1.34.1-gke.1"
       spec:
         containers:
         - image: mendhak/http-https-echo:37
           name: app1
           ports:
           - containerPort: 8000
           env:
           - name: VALIDATION_NONCE
             value: "http"
           - name: HTTP_PORT
             value: "8000"
         securityContext:
           fsGroup: 1337
    
  4. Aplique o exemplo de serviço que você criou na etapa anterior:

    kubectl apply -f service_sample.yaml
    
  5. Salve a seguinte configuração do GKE para seu cliente como client_sample.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
     labels:
       run: client
     name: load-generator
    spec:
     replicas: 1
     selector:
       matchLabels:
         run: client
     template:
       metadata:
         labels:
           run: client
       spec:
         containers:
         - name: load-generator
           image: envoyproxy/nighthawk-dev
           command: ["/bin/sh", "-c"]
           args: ["echo 'Nighthawk client pod is running' && sleep infinity"]
           resources:
             requests:
               cpu: 200m
               memory: 256Mi
             limits:
               cpu: 1
               memory: 512Mi
         securityContext:
           fsGroup: 1337
    
  6. Aplique a amostra de cliente que você criou na etapa anterior:

    kubectl apply -f client_sample.yaml
    

Configurar o Cloud Service Mesh para limitação de taxa

Siga as etapas nesta seção para preparar o Cloud Service Mesh para a limitação de taxa.

  1. Crie a especificação do recurso Mesh e salve-a em um arquivo chamado mesh.yaml:

    name: MESH_NAME
    interceptionPort: 15001
    
  2. Crie o recurso Mesh usando a especificação mesh.yaml.

      gcloud network-services meshes import "MESH_NAME" \
          --source=mesh.yaml \
          --location=global
    
  3. Crie uma verificação de integridade:

      gcloud compute health-checks create http rate-limit-demo-hc \
          --use-serving-port
    
  4. Crie uma regra de firewall para permitir conexões de verificação de integridade de entrada com instâncias na sua rede.

      gcloud compute firewall-rules create rate-limit-demo-fw-allow-hc \
          --action ALLOW \
          --direction INGRESS \
          --source-ranges 35.191.0.0/16,130.211.0.0/22 \
          --target-tags allow-envoy-health-checks \
          --rules tcp
    
  5. Crie um serviço de back-end global com um esquema de balanceamento de carga de INTERNAL_SELF_MANAGED e adicione a verificação de integridade.

      gcloud compute backend-services create rate-limit-demo-service \
          --global \
          --health-checks rate-limit-demo-hc \
          --load-balancing-scheme INTERNAL_SELF_MANAGED
    
  6. Adicione o NEG rate-limit-demo-neg ao serviço de back-end.

      gcloud compute backend-services add-backend rate-limit-demo-service \
          --global \
          --network-endpoint-group rate-limit-demo-neg \
          --network-endpoint-group-zone "ZONE" \
          --balancing-mode RATE \
          --max-rate-per-endpoint 5
    
  7. Crie a especificação HTTPRoute e salve-a em um arquivo chamado http_route.yaml:

    name: rate-limit-demo-http-route
    hostnames:
    - service-test
    - service-test:80
    meshes:
    - projects/PROJECT_ID/locations/global/meshes/MESH_NAME
    rules:
    - action:
       destinations:
       - serviceName: "projects/PROJECT_ID/locations/global/backendServices/rate-limit-demo-service"
    
  8. Crie o recurso HTTPRoute usando a especificação no arquivo http_route.yaml.

      gcloud network-services http-routes import rate-limit-demo-http-route \
          --source=http_route.yaml \
          --location=global
    

Configurar a limitação de taxa com o Envoy

As seções a seguir explicam como configurar a limitação de taxa do lado do servidor para sua malha de serviço. A primeira seção mostra como configurar um limite global de taxa do lado do servidor para todos os clientes, e a segunda seção mostra como aplicar limites de taxa diferentes para diferentes grupos de clientes.

Configurar a limitação de taxa global do lado do servidor

Neste exemplo, você cria uma regra de limitação de taxa do lado do servidor que aplica a limitação de taxa a todos os clientes.

  1. Em um arquivo YAML chamado rate-limit-policy.yaml, crie uma política de segurança do Cloud Armor com o tipo CLOUD_ARMOR_INTERNAL_SERVICE.

    name: "rate-limit-policy"
    type: CLOUD_ARMOR_INTERNAL_SERVICE
    rules:
    - priority: 2147483647
      match:
        config:
          srcIpRanges: ["*"]
        versionedExpr: SRC_IPS_V1
      action: "fairshare"
      rateLimitOptions:
        rateLimitThreshold:
          count: 10000
          intervalSec: 60
        exceedAction: "deny(429)"
        conformAction: "allow"
        enforceOnKey: "ALL"
    
  2. Crie a política de segurança chamada rate-limit-policy:

      gcloud beta compute security-policies create rate-limit-policy \
          --global \
          --file-name=rate-limit-policy.yaml
    
  3. Em um arquivo YAML, crie uma política de endpoint que faça referência à política de segurança criada na etapa anterior. Nesses exemplos, o arquivo é chamado de endpoints-policies.yaml.

    name: "rate-limit-ep"
    endpointMatcher:
     metadataLabelMatcher:
       metadataLabelMatchCriteria: MATCH_ALL
       metadataLabels:
       - labelName: app
         labelValue: rate-limit-demo
    type: SIDECAR_PROXY
    securityPolicy: projects/PROJECT_ID/locations/global/securityPolicies/rate-limit-policy
    
  4. Crie uma política de endpoint chamada rate-limit-ep:

      gcloud beta network-services endpoint-policies import rate-limit-ep \
          --source=endpoints-policies.yaml \
          --location=global
    

Configurar diferentes limites de taxa do lado do servidor para diferentes grupos de clientes

Neste exemplo, você cria diferentes regras de limitação de taxa do lado do servidor que impõem diferentes limites para grupos de clientes.

  1. Crie uma política de segurança do Cloud Armor com o tipo CLOUD_ARMOR_INTERNAL_SERVICE e várias regras de limitação de taxa, como a definida no arquivo a seguir. Nesses exemplos, o arquivo é chamado per-client-security-policy.yaml.

    name: "per-client-security-policy"
    type: CLOUD_ARMOR_INTERNAL_SERVICE
    rules:
    - priority: 0
      match:
        expr:
          expression: "request.headers['user'] == 'demo'"
      action: "fairshare"
      rateLimitOptions:
        rateLimitThreshold:
          count: 1000
          intervalSec: 60
        exceedAction: "deny(429)"
        conformAction: "allow"
        enforceOnKey: "ALL"
    - priority: 2147483647
      match:
        config:
          srcIpRanges: ["*"]
        versionedExpr: SRC_IPS_V1
      action: "fairshare"
      rateLimitOptions:
        rateLimitThreshold:
          count: 10000
          intervalSec: 60
        exceedAction: "deny(429)"
        conformAction: "allow"
        enforceOnKey: "ALL"
    

    Essa política aplica a limitação de taxa a solicitações que contêm um cabeçalho HTTP com o nome user e o valor demo se o Cloud Service Mesh receber mais de 1.000 solicitações desse tipo em um período de 60 segundos. As solicitações que não têm esse cabeçalho HTTP são limitadas por taxa se o Cloud Service Mesh receber mais de 10.000 solicitações desse tipo em um período de 60 segundos.

  2. Use o comando a seguir para criar a política, chamada per-client-security-policy:

      gcloud beta compute security-policies create per-client-security-policy \
          --global \
          --file-name=per-client-security-policy.yaml
    

    Crie uma política de endpoint que faça referência à política de segurança criada na etapa anterior, como a definida no arquivo a seguir. Neste exemplo, o arquivo é chamado de per-client-endpoints-policies.yaml.

    name: "rate-limit-ep"
    endpointMatcher:
     metadataLabelMatcher:
       metadataLabelMatchCriteria: MATCH_ALL
       metadataLabels:
       - labelName: app
         labelValue: rate-limit-demo
    type: SIDECAR_PROXY
    securityPolicy: projects/PROJECT_ID/locations/global/securityPolicies/per-client-security-policy
    

    Use o comando a seguir para criar uma política de endpoint chamada rate-limit-ep:

      gcloud beta network-services endpoint-policies import rate-limit-ep \
          --source=per-client-endpoints-policies.yaml \
          --location=global
    

Validar sua configuração

Use a ferramenta de teste de carga Nighthawk para gerar tráfego e verificar se as regras de limitação de taxa estão funcionando como esperado. Use o comando a seguir para gerar tráfego com o Nighthawk:

kubectl exec -it deploy/load-generator -c load-generator -- \
    nighthawk_client http://service-test \
    --open-loop --no-default-failure-predicates \
    --rps 60 \
    --duration 360 \
    --connections 10 \
    --protocol http1 \
    --request-header user:demo

Em seguida, use o comando a seguir para ativar os registros de depuração do Envoy:

kubectl exec -it deploy/app1 -c app1 -- wget -q -O - \
    --post-data="" 'http://localhost:15000/logging?level=debug'

Para ver os relatórios de uso que o Envoy envia ao servidor de gerenciamento, consulte Como acessar seus registros.

Os resultados do teste podem mostrar o seguinte:

  • Leva cerca de cinco minutos para que a limitação de taxa entre em vigor.
  • Após o período inicial de aquecimento, você verá cerca de 15 a 21 QPS na saída do cliente Nighthawk contador benchmark.http_2xx. Isso significa que o Cloud Armor permite cerca de 1.000 solicitações por minuto.

Para conferir a eficácia das regras da política de segurança do Cloud Armor, consulte Como acessar o painel de monitoramento.

Desativar a limitação de taxa

É possível desativar a limitação de taxa usando um dos seguintes métodos:

  • É possível excluir as políticas de endpoint e de segurança que você configurou com suas regras de limitação de taxa.
  • É possível separar a política de segurança da política de endpoint atualizando a política de endpoint para remover o campo securityPolicies.

As seções a seguir mostram como desativar a limitação de taxa usando cada método.

Excluir uma política de endpoint e uma política de segurança

Primeiro, use o seguinte comando gcloud para excluir a política de endpoint chamada rate-limit-ep. Se você usou o nome fornecido no primeiro ou segundo exemplo desta página, a política de endpoint será chamada de endpoints-policies ou per-client-endpoints-policies, respectivamente.

gcloud beta network-services endpoint-policies delete --location=global rate-limit-ep

Em seguida, use o comando gcloud a seguir para excluir uma política de segurança, substituindo per-client-security-policy pelo nome da sua política de segurança. Se você usou o nome fornecido no primeiro ou segundo exemplo desta página, sua política de segurança tem o mesmo nome da política de endpoint.

gcloud beta compute security-policies delete --global per-client-security-policy

Remover uma política de segurança da política de endpoint

Primeiro, atualize o arquivo endpoint-policy.yaml para remover o campo securityPolcies:

name: "rate-limit-ep"
endpointMatcher:
  metadataLabelMatcher:
    metadataLabelMatchCriteria: MATCH_ALL
    metadataLabels:
    - labelName: app
      labelValue: rate-limit-demo
type: SIDECAR_PROXY

Em seguida, use o comando a seguir para atualizar a política de endpoint chamada rate-limit-ep com as mudanças no arquivo endpoint-policy.yaml:

gcloud beta network-services endpoint-policies import rate-limit-ep \
    --source=endpoints-policies.yaml \
    --location=global