通过 Ingress 配置 Google Cloud Armor

本页面介绍如何使用 BackendConfig 自定义资源在 Google Kubernetes Engine (GKE) 中配置 Google Cloud Armor

概览

在 GKE 集群中,传入流量由外部 HTTP(S) 负载平衡处理,该服务是 Cloud Load Balancing 的一个组件。 通常 HTTP(S) 负载平衡器由 GKE Ingress 控制器配置,该控制器从 Kubernetes Ingress 对象获取配置信息。Ingress 与一个或多个 Service 对象相关联。每个 Service 对象包含用于将传入请求定向到特定 Pod 和端口的路由信息。

从 Kubernetes 1.10.5-gke.3 版本开始,您可以为外部负载平衡器提供其他配置,方法是将 Service 端口与名为 BackendConfig自定义资源相关联。

GKE Ingress 控制器会从 BackendConfig 读取配置信息并相应地设置外部负载平衡器。BackendConfig 包含特定于 Cloud Load Balancing 的配置信息。 Kubernetes Ingress 和 Service 资源不支持配置特定于提供方的功能(如 Google Cloud Armor);您可以通过 BackendConfig 来执行这项配置。

下面简要介绍如何在本练习中设置 BackendConfig:

  1. 创建一个 BackendConfig。
  2. 创建一个 Service,并将它的一个端口与 BackendConfig 关联。
  3. 创建一个 Ingress,并将该 Ingress 与(Service, 端口)对关联。

准备工作

在开始之前,请确保您已执行以下任务:

使用以下任一方法设定默认的 gcloud 设置:

  • 使用 gcloud init(如果您想要在系统引导下完成默认设置)。
  • 使用 gcloud config(如果您想单独设置项目 ID、区域和地区)。

使用 gcloud init

如果您收到 One of [--zone, --region] must be supplied: Please specify location 错误,请完成本部分。

  1. 运行 gcloud init 并按照说明操作:

    gcloud init

    如果您要在远程服务器上使用 SSH,请使用 --console-only 标志来防止命令启动浏览器:

    gcloud init --console-only
  2. 按照说明授权 gcloud 使用您的 Google Cloud 帐号。
  3. 创建新配置或选择现有配置。
  4. 选择 Google Cloud 项目。
  5. 选择默认的 Compute Engine 区域。

使用 gcloud config

  • 设置默认项目 ID
    gcloud config set project project-id
  • 如果您使用的是区域级集群,请设置默认计算区域
    gcloud config set compute/zone compute-zone
  • 如果您使用的是地区级集群,请设置默认计算地区
    gcloud config set compute/region compute-region
  • gcloud 更新到最新版本:
    gcloud components update

创建命名空间

为本指南中的对象创建 Kubernetes 命名空间:

kubectl create namespace cloud-armor-how-to

创建 Deployment

此 Deployment 清单声明您要运行 hello-app Web 应用的两个副本:

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

将此清单复制到名为 my-deployment.yaml 的文件,然后创建该 Deployment:

kubectl apply -f my-deployment.yaml

创建 Google Cloud Armor 安全政策和规则

Google Cloud Armor 安全政策支持以下内容:

  • IP 地址拒绝列表和允许列表
  • 区域代码拒绝列表和允许列表(Beta 版)
  • 可缓解跨站脚本攻击 (XSS) 和 SQL 注入攻击 (SQLi) 的预配置规则(Beta 版)
  • 自定义规则语言(Beta 版)

创建 Google Cloud Armor 安全政策:

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

为您的安全政策创建规则:

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"

查看安全政策:

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

输出:

...
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
  ...

创建 BackendConfig

以下是 BackendConfig 的清单。该清单指定了安全政策:

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

将此清单复制到名为 my-backend-config.yaml 的文件,然后创建该 BackendConfig:

kubectl apply -f my-backend-config.yaml

查看 BackendConfig:

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

输出会显示指定的安全政策:

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

创建 Service

以下是 Service 的清单:

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

将此清单保存到名为 my-service.yaml 的文件,然后创建该 Service:

kubectl apply -f my-service.yaml

查看 Service:

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

输出结果类似如下所示:

apiVersion: v1
kind: Service
metadata:
  annotations:
    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: {}

在本练习中,您需要注意有关 Service 的以下重要事项:

  • Service 的端口 80 与名为 my-backend-config 的 BackendConfig 相关联。这是由 cloud.google.com/backend-config 注释指定的。

  • Service 类型为 NodePort。对于要与 Ingress 关联的 Service,必须使用此类型。

  • 具有 app: hello-app 标签的任何 Pod 都是 Service 的成员。这是由 selector 字段指定的。

  • 定向至 TCP 端口 80 上的服务的流量被路由到 TCP 端口 8080 上的其中一个成员 Pod。这是由 porttargetPort 字段指定的。

保留静态外部 IP 地址

保留静态外部 IP 地址:

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

查看静态外部 IP 地址:

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

输出:

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

创建 Ingress

以下是 Ingress 的清单:

apiVersion: networking.k8s.io/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

将此清单复制到名为 my-ingress.yaml 的文件,然后创建该 Ingress:

kubectl create -f my-ingress.yaml

请等待几分钟,让 Kubernetes Ingress 控制器配置 Cloud Load Balancing 负载平衡器,然后查看 Ingress:

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

输出:

apiVersion: networking.k8s.io/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

在本练习中,您需要注意有关 Ingress 的以下重要事项:

  • 传入流量的 IP 地址列在 loadBalancer:ingress: 下。

  • Ingress 具有一条规则,该规则适用于来自任何主机的传入 HTTP 请求。这是因为该规则中没有 host 字段。因此,在默认情况下,该规则适用于所有主机。

  • 无论网址路径为何,所有传入的请求都被视为相同。这是由 path/* 指定的。

  • 传入请求被路由到 my-service 的一个成员 Pod。在本练习中,该成员 Pod 具有 app: hello-app 标签。

  • 请求被路由到 my-service 中指定的目标端口上的 Pod。在此练习中,Pod 目标端口为 8080。

查看网页应用

请等待几分钟。然后在浏览器中输入静态外部 IP 地址。

该页面会显示在 Deployment 的其中一个 Pod 中运行的 hello-app Web 应用返回的响应:

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

使用 curl 查看该 Web 应用:

curl -v static-address

其中,static-address 是您的静态外部 IP 地址。

输出是 hello-app 返回的响应:

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

分离安全政策

要从 Ingress 分离安全政策,请在 BackendConfig 中将安全政策名称留空。以下是一个有关分离安全政策的示例:

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

问题排查

找不到 BackendConfig

如果在 Service 注释中指定了 Service 端口的 BackendConfig,但找不到实际 BackendConfig 资源,那么就会发生这种错误。 如果您根本没有创建 BackendConfig 资源,或在错误的命名空间中创建了该资源,或在 Service 注释中拼错了引用,则会发生这种情况。

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

找不到安全政策

Ingress 对象创建完毕后,如果安全政策未与负载平衡器服务正确关联,请评估 Kubernetes 事件以了解是否存在配置错误。具体来说,如果 BackendConfig 指定了不存在的政策,则系统会定期发出警告事件。 如需解决此问题,请确保在 BackendConfig 中按名称指定正确的安全政策。

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

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

清理

完成本页中的练习后,请按照以下步骤移除资源,以防止您的帐号产生不必要的费用:

删除您针对此练习创建的 Kubernetes 对象:

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

删除静态外部 IP 地址:

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

删除安全政策:

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

后续步骤