Configura Google Cloud Armor a través de Ingress

beta

En esta página, se muestra cómo usar un recurso personalizado BackendConfig para configurar Google Cloud Armor en Google Kubernetes Engine (GKE).

Descripción general

En un clúster de GKE, el tráfico entrante se controla mediante el balanceo de cargas HTTP(S) externo, que es un componente de Cloud Load Balancing. Por lo general, el balanceador de cargas HTTP(S) se configura con un controlador de Ingress de GKE, que obtiene la información de configuración de un objeto Ingress de Kubernetes. El objeto Ingress se asocia a uno o más objetos de servicio. Cada objeto de servicio contiene información de enrutamiento que se usa para direccionar una solicitud entrante a un pod o puerto específico.

A partir de la versión 1.10.5-gke.3 de Kubernetes, puedes asociar un puerto de servicio con un recurso personalizado llamado BackendConfig con la configuración adicional del balanceador de cargas externo.

El controlador de Ingress de GKE lee la información de configuración de BackendConfig y configura el balanceador de cargas externo según corresponde. Un BackendConfig tiene información de configuración específica de Cloud Load Balancing. Los recursos de Ingress y servicio de Kubernetes no ofrecen una manera de configurar funciones específicas de los proveedores, como Google Cloud Armor. BackendConfig te permite establecer esa configuración.

A continuación, se detalla el panorama general de cómo configurar un BackendConfig en este ejercicio:

  1. Crea un BackendConfig.
  2. Crea un servicio y asocia uno de sus puertos al BackendConfig.
  3. Crea un Ingress y asócialo con el par (servicio, puerto).

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

Establece la configuración de gcloud predeterminada mediante uno de los siguientes métodos:

  • Usa gcloud init si quieres ver una introducción sobre cómo configurar parámetros predeterminados.
  • Usa gcloud config para establecer de forma individual el ID de tu proyecto, la zona y la región.

Usa gcloud init

  1. Ejecuta gcloud init y sigue las instrucciones:

    gcloud init

    Si usas SSH en un servidor remoto, usa la marca --console-only para evitar que el comando inicie un navegador:

    gcloud init --console-only
  2. Sigue las instrucciones a fin de autorizar a gcloud para que use tu cuenta de Google Cloud.
  3. Crea una configuración nueva o selecciona una existente.
  4. Elige un proyecto de Google Cloud.
  5. Elige una zona predeterminada de Compute Engine.

Usa la configuración de gcloud.

  • Establece tu ID del proyecto predeterminado:
    gcloud config set project project-id
  • Si trabajas con clústeres zonales, establece tu zona de procesamiento predeterminada:
    gcloud config set compute/zone compute-zone
  • Si trabajas con clústeres regionales, establece tu región de procesamiento predeterminada:
    gcloud config set compute/region compute-region
  • Actualiza gcloud a la versión más reciente:
    gcloud components update

Crea un espacio de nombres

Crea un espacio de nombres de Kubernetes para los objetos en esta guía:

kubectl create namespace cloud-armor-how-to
    

Crea una implementación

En este manifiesto de implementación, se declara que quieres ejecutar dos réplicas de la aplicación web hello-app:

apiVersion: apps/v1
    kind: Deployment
    metadata:
      namespace: cloud-armor-how-to
      name: my-deployment
    spec:
      selector:
        matchLabels:
          app: hello-app
      replicas: 2
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-app-container
            image: gcr.io/google-samples/hello-app:1.0
            ports:
            - containerPort: 8080
    

Copia el manifiesto en un archivo llamado my-deployment.yaml y crea la implementación:

kubectl apply -f my-deployment.yaml
    

Crea una regla y una política de seguridad de Google Cloud Armor

Las políticas de seguridad de Google Cloud Armor admiten lo siguiente:

  • Listas de IP denegadas y permitidas
  • Código de región denegados y permitidos (Beta)
  • Reglas preconfiguradas para mitigar los ataques de inyección SQL (SQLi) y de secuencia de comandos entre sitios (XSS) (Beta)
  • Lenguaje de reglas personalizadas (Beta)

Crea una política de seguridad de Google Cloud Armor:

gcloud beta compute security-policies create ca-how-to-security-policy \
        --description "policy for Google Cloud Armor how-to topic"
    

Crea una regla para la política de seguridad:

gcloud beta compute security-policies rules create 1000 \
        --security-policy ca-how-to-security-policy \
        --description "Deny traffic from 192.0.2.0/24." \
        --src-ip-ranges "192.0.2.0/24" \
        --action "deny-404"
    

Observa la política de seguridad:

gcloud beta compute security-policies describe ca-how-to-security-policy
    

Resultado:

...
    kind: compute#securityPolicy
    name: ca-how-to-security-policy
    rules:
    - action: deny(404)
      description: Deny traffic from 192.0.2.0/24.
      kind: compute#securityPolicyRule
      match:
        config:
          srcIpRanges:
          - 192.0.2.0/24
        versionedExpr: SRC_IPS_V1
      preview: false
      priority: 1000
      ...
    

Cómo crear un BackendConfig

A continuación, se detalla un manifiesto para un BackendConfig. El manifiesto especifica una política de seguridad:

apiVersion: cloud.google.com/v1beta1
    kind: BackendConfig
    metadata:
      namespace: cloud-armor-how-to
      name: my-backend-config
    spec:
      securityPolicy:
        name: "ca-how-to-security-policy"
    

Copia el manifiesto en un archivo denominado my-backend-config.yaml y crea el BackendConfig:

kubectl apply -f my-backend-config.yaml
    

Observa el BackendConfig:

kubectl get backendconfig my-backend-config --namespace cloud-armor-how-to --output yaml
    

El resultado muestra la política de seguridad especificada:

apiVersion: cloud.google.com/v1beta1
    kind: BackendConfig
    metadata:
      name: my-backend-config
      namespace: cloud-armor-how-to
      ...
    spec:
      securityPolicy:
        name: ca-how-to-security-policy
    

Cómo crear un servicio

Aquí hay un manifiesto para un servicio:

apiVersion: v1
    kind: Service
    metadata:
      namespace: cloud-armor-how-to
      name: my-service
      labels:
        app: hello-app
      annotations:
        beta.cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
    spec:
      type: NodePort
      selector:
        app: hello-app
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
    

Guarda el manifiesto en un archivo denominado my-service.yaml y crea el servicio:

kubectl apply -f my-service.yaml
    

Observa el servicio:

kubectl get service my-service --namespace cloud-armor-how-to --output yaml
    

El resultado es similar al siguiente ejemplo:

apiVersion: v1
    kind: Service
    metadata:
      annotations:
        beta.cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
      labels:
        app: hello-app
      name: my-service
      namespace: cloud-armor-how-to
      ...
    spec:
      clusterIP: 10.19.249.137
      externalTrafficPolicy: Cluster
      ports:
      - nodePort: 32629
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: hello-app
      sessionAffinity: None
      type: NodePort
    status:
      loadBalancer: {}
    

A los fines de este ejercicio, estos son los aspectos importantes que debes tener en cuenta sobre tu servicio:

  • El puerto 80 del servicio está asociado a un BackendConfig con el nombre my-backend-config. Esto se especifica en la anotación beta.cloud.google.com/backend-config.

  • El servicio tiene el tipo NodePort. Este es el tipo requerido para los servicios que se van a asociar a un Ingress.

  • Cualquier pod que tenga la etiqueta app: hello-app es miembro del servicio. Esto se especifica en el campo selector.

  • El tráfico dirigido al servicio en el puerto TCP 80 se enruta al puerto TCP 8080 de uno de los pods miembros. Esto se especifica en los campos port y targetPort.

Cómo reservar una dirección IP externa estática

Reserva una dirección IP externa estática:

gcloud compute addresses create cloud-armor-how-to-address --global
    

Observa una dirección IP externa estática:

gcloud compute addresses list --filter "name=cloud-armor-how-to-address"
    

Resultado:

NAME                        REGION  ADDRESS        STATUS
    cloud-armor-how-to-address          203.0.113.2    RESERVED
    

Cómo crear un Ingress

Este es un manifiesto para un Ingress:

apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      namespace: cloud-armor-how-to
      name: my-ingress
      annotations:
        kubernetes.io/ingress.global-static-ip-name: "cloud-armor-how-to-address"
    spec:
      backend:
        serviceName: my-service
        servicePort: 80
    

Copia el manifiesto en un archivo con el nombre my-ingress.yaml y crea el Ingress:

kubectl create -f my-ingress.yaml
    

Espera unos minutos a que el controlador de Ingress de Kubernetes configure un balanceador de cargas de Cloud y, luego, observa el Ingress:

kubectl get ingress my-ingress --output yaml --namespace cloud-armor-how-to
    

Resultado:

apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: my-ingress
      namespace: cloud-armor-how-to
      ...
    spec:
      backend:
        serviceName: my-service
        servicePort: 80
    status:
      loadBalancer:
        ingress:
        - ip: 203.0.113.2
    

A los fines de este ejercicio, estas son las cuestiones importantes que debes tener en cuenta sobre tu Ingress:

  • La dirección IP para el tráfico entrante aparece en loadBalancer:ingress:.

  • El Ingress tiene una regla que se aplica a las solicitudes HTTP entrantes desde cualquier host. Esto se debe a que no existe un campo host en la regla. Por eso, de forma predeterminada, se aplica la regla a todos los hosts.

  • Todas las solicitudes entrantes se tratan de la misma manera, independientemente de la ruta de URL. Esto se especifica mediante el valor path /*.

  • Las solicitudes entrantes se enrutan a un pod miembro de my-service. En este ejercicio, los pods miembros tienen la etiqueta app: hello-app.

  • Las solicitudes se enrutan al pod en el puerto de destino especificado en my-service. En este ejercicio, el puerto de destino del pod es 8080.

Cómo ver la aplicación web

Espera unos minutos. Luego, en tu navegador ingresa tu dirección IP externa estática.

En la página, se muestra la respuesta de la aplicación web de hello-app que se está ejecutando en uno de los pods de la implementación:

Hello, world!
    Version: 1.0.0
    Hostname: my-deployment-574ddbdf88-f9fbj
    

Usa curl para visualizar la aplicación web:

curl -v static-address
    

En el ejemplo anterior, se muestra que static-address es tu dirección IP externa estática.

El resultado es la respuesta de hello-app:

Hello, world!
    Version: 1.0.0
    Hostname: my-deployment-574ddbdf88-zpb94
    

Desvincula la política de seguridad

Para desvincular la política de seguridad desde un Ingress, deja vacío el nombre de la política en BackendConfig. A continuación, se muestra un ejemplo de la desvinculación de una política de seguridad:

apiVersion: cloud.google.com/v1beta1
    kind: BackendConfig
    metadata:
      namespace: cloud-armor-how-to
      name: my-backend-config
    spec:
      securityPolicy:
        name: ""
    

Soluciona problemas

No se encontró el BackendConfig

Este error ocurre cuando un BackendConfig para un puerto de servicio se especifica en la anotación del servicio, pero no se pudo encontrar ese recurso BackendConfig en sí. Esto puede ocurrir si no creaste el recurso BackendConfig en absoluto, si lo creaste en el espacio de nombres equivocado o si escribiste mal la referencia en la anotación del servicio.

kubectl get event
    
KIND    ... SOURCE
    Ingress ... loadbalancer-controller

    MESSAGE
    Error during sync: error getting BackendConfig for port 80 on service "default/my-service":
    no BackendConfig for service port exists
    

No se encontró la política de seguridad

Después de crear el objeto Ingress, si la política de seguridad no está asociada de forma correcta al servicio de balanceador de cargas, evalúa el evento de Kubernetes para ver si hay un error de configuración. En particular, si tu BackendConfig especifica una política inexistente, se emitirá un evento de advertencia de forma periódica. Para solucionar este problema, asegúrate de especificar la política de seguridad correcta por nombre en tu BackendConfig.

kubectl get event
    
KIND    ... SOURCE
    Ingress ... loadbalancer-controller

    MESSAGE
    Error during sync: The given security policy "my-policy" does not exist.
    

Realiza una limpieza

Luego de completar los ejercicios de esta página, sigue estos pasos para quitar los recursos y evitar cargos no deseados en tu cuenta:

Borra los objetos Kubernetes que creaste para este ejercicio:

kubectl delete ingress my-ingress --namespace cloud-armor-how-to
    kubectl delete service my-service --namespace cloud-armor-how-to
    kubectl delete backendconfig my-backend-config --namespace cloud-armor-how-to
    kubectl delete deployment my-deployment --namespace cloud-armor-how-to
    kubectl delete namespace cloud-armor-how-to
    

Borra tu dirección IP externa estática:

gcloud compute addresses delete cloud-armor-how-to-address --global
    

Borra la política de seguridad:

gcloud beta compute security-policies delete ca-how-to-security-policy
    

Qué sigue