Configurar la limitación de frecuencia de Google Cloud Armor con Envoy

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

Configurar Google Kubernetes Engine (GKE) para Envoy

Antes de empezar

Antes de empezar, 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 la CLI de Google Cloud:

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

A continuación, 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}

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

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

Crear un clúster de GKE

  1. Usa el siguiente comando para crear un clúster de GKE en la zona que has especificado 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 nuevo clúster:

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

Habilitar la inyecció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 del clúster, que indica al inyector de sidecar gestionado que añada el contenedor 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 inyección de sidecar para el espacio de nombres predeterminado. El inyector de sidecar inserta contenedores sidecar en 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 el ejemplo de servicio que has creado 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 de cliente que has creado en el paso anterior:

    kubectl apply -f client_sample.yaml
    

Configurar Cloud Service Mesh para limitar la frecuencia

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

  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 comprobación del estado:

      gcloud compute health-checks create http rate-limit-demo-hc \
          --use-serving-port
    
  4. Crea una regla de cortafuegos para permitir las conexiones de comprobación del 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 carga INTERNAL_SELF_MANAGED y añade la comprobación del estado.

      gcloud compute backend-services create rate-limit-demo-service \
          --global \
          --health-checks rate-limit-demo-hc \
          --load-balancing-scheme INTERNAL_SELF_MANAGED
    
  6. Añade 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
    

Configurar la limitación de frecuencia con Envoy

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

Configurar la limitación de frecuencia global del lado del servidor

En este ejemplo, se crea una regla de limitación de frecuencia del lado del servidor que aplica la limitación 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 de 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, cree una política de endpoint que haga referencia a la política de seguridad que ha creado en el paso anterior. En estos ejemplos, el 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 de endpoint llamada rate-limit-ep:

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

Configurar diferentes límites de frecuencia del lado del servidor para distintos grupos de clientes

En este ejemplo, se crean diferentes reglas de limitación de frecuencia del lado del servidor que aplican umbrales de limitación de frecuencia distintos a grupos de clientes.

  1. Crea una política de seguridad de Cloud Armor con el tipo CLOUD_ARMOR_INTERNAL_SERVICE con varias reglas de limitación 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 la limitación 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 1000 solicitudes de este tipo en un periodo de 60 segundos. 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 periodo 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 endpoint que haga referencia a la política de seguridad que has creado en el paso anterior, como la que se define en el siguiente archivo. En este ejemplo, el 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 endpoint llamada rate-limit-ep:

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

Validar la configuración

Puedes usar la herramienta de prueba de carga Nighthawk para generar tráfico y comprobar si tus reglas de limitación 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 gestión, consulta Acceder a los registros.

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

  • Se tarda unos cinco minutos en aplicar la limitación de frecuencia.
  • Después del periodo de calentamiento inicial, verás entre 15 y 21 QPS en el contador benchmark.http_2xx de la salida del cliente de Nighthawk. Esto significa que Cloud Armor permite unas 1000 solicitudes por minuto.

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

Inhabilitar el límite de frecuencia

Puedes inhabilitar la limitación de la frecuencia mediante uno de los siguientes métodos:

  • Puedes eliminar las políticas de endpoint y las políticas de seguridad que hayas configurado con tus reglas de limitación de frecuencia.
  • Para desvincular la política de seguridad de tu política de endpoints, actualiza esta última para eliminar el campo securityPolicies.

En las siguientes secciones se explica cómo inhabilitar la limitación de la frecuencia con cada método.

Eliminar una política de endpoint y una política de seguridad

Primero, usa el siguiente comando gcloud para eliminar la política de endpoint llamada rate-limit-ep. Si has usado el nombre proporcionado en el primer o segundo ejemplo de esta página, la política de endpoint se llamará endpoints-policies o per-client-endpoints-policies, respectivamente.

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

A continuación, usa el siguiente comando gcloud para eliminar una política de seguridad. Sustituye per-client-security-policy por el nombre de tu política de seguridad. Si has usado 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 endpoint.

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

Desvincular una política de seguridad de tu política de endpoint

Primero, actualiza el 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

A continuación, usa el siguiente comando para actualizar la política de endpoint llamada rate-limit-ep con los cambios del archivo endpoint-policy.yaml:

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