Configura el límite de frecuencia de Google Cloud Armor con Envoy

En esta página, se muestra cómo configurar un límite de frecuencia global del servidor para tu malla de servicios con Cloud Armor. Puedes usar esta función para aplicar la límite de frecuencia de uso compartido equitativo a todo el tráfico que llega a tu servicio, lo que te ayudará a compartir de manera equitativa la capacidad disponible de tus servicios y mitigar el riesgo de que los clientes maliciosos o con comportamiento inadecuado sobrecarguen tus servicios. Para obtener más información sobre el límite de frecuencia, consulta la descripción general del límite de frecuencia.

Configura Google Kubernetes Engine (GKE) para Envoy

Antes de comenzar

Antes de comenzar, debes habilitar las siguientes APIs:

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

Puedes habilitar todas las APIs con el siguiente comando de Google Cloud CLI:

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

Luego, crea las variables de entorno que se usan en este 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}

Reemplaza las siguientes variables por la información de tu proyecto:

  • Reemplaza PROJECT_ID por el ID de tu proyecto.
  • Reemplaza ZONE por la zona en la que deseas crear tu clúster de GKE.
  • Reemplaza CLUSTER por el nombre del clúster.
  • Reemplaza MESH_NAME por el nombre de la malla.

Crea un clúster de GKE

  1. Usa el siguiente comando para crear un clúster de GKE en la zona que especificaste en la sección anterior:

     gcloud container clusters create "CLUSTER" \
         --zone="ZONE" \
         --scopes="cloud-platform" \
         --tags="allow-envoy-health-checks" \
         --enable-ip-alias
    
  2. Obtén las credenciales de tu clúster nuevo:

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

Habilita la inserción automática

  1. Usa el siguiente comando para aplicar el recurso MutatingWebhookConfiguration a tu clúster. Cuando se crea un Pod, se invoca el controlador de admisión en el clúster, que le indica al inyector de sidecar administrado que agregue el contenedor de Envoy al 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. Habilita la inserción de sidecar para el espacio de nombres predeterminado. El inyector de sidecar inserta contenedores de sidecar para los Pods creados en el espacio de nombres predeterminado.

    kubectl label namespace default td-injection=enabled
    
  3. Guarda la siguiente configuración de GKE para tu servicio 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. Aplica la muestra de servicio que creaste en el paso anterior:

    kubectl apply -f service_sample.yaml
    
  5. Guarda la siguiente configuración de GKE para tu 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. Aplica la muestra del cliente que creaste en el paso anterior:

    kubectl apply -f client_sample.yaml
    

Configura Cloud Service Mesh para el límite de frecuencia

Sigue los pasos de esta sección para preparar Cloud Service Mesh para la limitación de frecuencia.

  1. Crea la especificación de recursos Mesh y guárdala en un archivo llamado mesh.yaml:

    name: MESH_NAME
    interceptionPort: 15001
    
  2. Crea el recurso Mesh con la especificación mesh.yaml.

      gcloud network-services meshes import "MESH_NAME" \
          --source=mesh.yaml \
          --location=global
    
  3. Crea una verificación de estado de la siguiente forma:

      gcloud compute health-checks create http rate-limit-demo-hc \
          --use-serving-port
    
  4. Crea una regla de firewall que permita las conexiones de verificación de estado entrantes a las instancias de tu red.

      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. Crea un servicio de backend global con un esquema de balanceo de cargas de INTERNAL_SELF_MANAGED y agrega la verificación de estado.

      gcloud compute backend-services create rate-limit-demo-service \
          --global \
          --health-checks rate-limit-demo-hc \
          --load-balancing-scheme INTERNAL_SELF_MANAGED
    
  6. Agrega el NEG rate-limit-demo-neg al servicio de backend.

      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. Crea la especificación HTTPRoute y guárdala en un archivo llamado 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. Crea el recurso HTTPRoute con la especificación del archivo http_route.yaml.

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

Configura el límite de frecuencia con Envoy

En las siguientes secciones, se explica cómo configurar la limitación de frecuencia del servidor para tu malla de servicios. En la primera sección, se muestra cómo configurar un límite de frecuencia global del servidor para todos los clientes, y en la segunda, se explica cómo aplicar diferentes límites de frecuencia para diferentes grupos de clientes.

Configura la limitación global de frecuencia del servidor

En este ejemplo, crearás una regla de límite de frecuencia del servidor que aplique la límite de frecuencia a todos los clientes.

  1. En un archivo YAML llamado rate-limit-policy.yaml, crea una política de seguridad de Cloud Armor con el 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. Crea la política de seguridad llamada rate-limit-policy:

      gcloud beta compute security-policies create rate-limit-policy \
          --global \
          --file-name=rate-limit-policy.yaml
    
  3. En un archivo YAML, crea una política de extremos que haga referencia a la política de seguridad que creaste en el paso anterior. En estos ejemplos, este archivo se llama 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. Crea una política para el extremo llamada rate-limit-ep:

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

Configura diferentes límites de frecuencia del servidor para diferentes grupos de clientes

En este ejemplo, crearás diferentes reglas de límite de frecuencia del servidor que apliquen diferentes umbrales de límite de frecuencia para grupos de clientes.

  1. Crea una política de seguridad de Cloud Armor con el tipo CLOUD_ARMOR_INTERNAL_SERVICE y varias reglas de límite de frecuencia, como la que se define en el siguiente archivo. En estos ejemplos, este archivo se llama 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"
    

    Esta política aplica un límite de frecuencia a las solicitudes que contienen un encabezado HTTP con el nombre user y el valor demo si Cloud Service Mesh recibe más de 1,000 solicitudes de este tipo en un período de 60 segundos. En cambio, las solicitudes que no tienen este encabezado HTTP se limitan si Cloud Service Mesh recibe más de 10,000 solicitudes de este tipo en un período de 60 segundos.

  2. Usa el siguiente comando para crear la política, que se llama per-client-security-policy:

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

    Crea una política de extremos que haga referencia a la política de seguridad que creaste en el paso anterior, como la que se define en el siguiente archivo. En este ejemplo, este archivo se llama 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
    

    Usa el siguiente comando para crear una política de extremos llamada rate-limit-ep:

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

Valida tu configuración

Puedes usar la herramienta de prueba de carga Nighthawk para generar tráfico y probar si tus reglas de límite de frecuencia funcionan como esperas. Usa el siguiente comando para generar tráfico con 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

A continuación, usa el siguiente comando para habilitar los registros de depuración de Envoy:

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

Para ver los informes de uso que Envoy envía al servidor de administración, consulta Cómo acceder a tus registros.

En los resultados de la prueba, verás lo siguiente:

  • El límite de frecuencia tarda aproximadamente cinco minutos en surtir efecto.
  • Después del período de calentamiento inicial, verás entre 15 y 21 QPS en el contador benchmark.http_2xx del cliente de Nighthawk. Esto significa que Cloud Armor permite alrededor de 1,000 solicitudes por minuto.

Para ver la eficacia de las reglas de tu política de seguridad de Cloud Armor, consulta Cómo ver el panel de supervisión.

Inhabilita el límite de frecuencia

Puedes inhabilitar el límite de frecuencia con cualquiera de los siguientes métodos:

  • Puedes borrar las políticas de endpoint y las políticas de seguridad que configuraste con tus reglas de límite de frecuencia.
  • Puedes separar la política de seguridad de tu política de extremos actualizando esta última para quitar el campo securityPolicies.

En las siguientes secciones, se explica cómo inhabilitar la límite de frecuencia con cada método.

Borra una política de extremos y una política de seguridad

Primero, usa el siguiente comando gcloud para borrar tu política de extremo llamada rate-limit-ep. Si usaste el nombre proporcionado en el primer o segundo ejemplo de esta página, la política de extremo se llama endpoints-policies o per-client-endpoints-policies, respectivamente.

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

Luego, usa el siguiente comando gcloud para borrar una política de seguridad y reemplaza per-client-security-policy por el nombre de tu política de seguridad. Si usaste el nombre proporcionado en el primer o segundo ejemplo de esta página, tu política de seguridad tendrá el mismo nombre que tu política de extremos.

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

Desconecta una política de seguridad de tu política de extremo

Primero, actualiza tu archivo endpoint-policy.yaml para quitar el campo securityPolcies:

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

Luego, usa el siguiente comando para actualizar la política de extremos llamada rate-limit-ep con los cambios en el archivo endpoint-policy.yaml:

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