保护 Gateway 安全


本页面介绍如何使用各种安全功能保护 Gateway:

  • SSL 政策,可确保 Gateway 使用所需的安全协议和算法

  • 证书,可使用 TLS 保护客户端到网关和网关到后端的流量

  • Google Cloud Armor 安全政策,可保护 Service 免受 DDoS 攻击

  • Identity-Aware Proxy (IAP),在允许访问 Service 之前提供一道身份验证和授权防线。

如需详细了解 Gateway 安全性,请参阅 Gateway 安全性

准备工作

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

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

GKE Gateway Controller 要求

  • 对于标准版,需要 GKE 1.24 或更高版本。
  • 对于 Autopilot,需要 GKE 1.26 或更高版本。
  • Google Cloud CLI 407.0.0 版或更高版本。
  • VPC 原生集群支持 Gateway API。
  • 如果您使用的是内部 GatewayClass,则必须启用代理专用子网
  • 集群必须启用 HttpLoadBalancing 插件。
  • 如果您使用的是 Istio,则必须将 Istio 升级到以下版本之一:
    • 1.15.2 或更高版本
    • 1.14.5 或更高版本
    • 1.13.9 或更高版本。
  • 如果您使用的是共享 VPC,则需要在宿主项目中将 Compute Network User 角色分配给服务项目的 GKE 服务账号。

限制和局限

关于 Gateway 安全性,除了 GKE Gateway Controller 的限制和局限之外,还存在以下特定限制:

  • 您不能在同一 Gateway 资源上将 networking.gke.io/certmap 注释与 tls.certificateRefs 一起使用。如果您在 Gateway 中引用 CertificateMap,GKE 会将其视为错误。
  • Certificate Manager 支持自行管理和 Google 管理的证书。Google 管理的证书与区域网关(在预览版中可用)和全球网关兼容。
  • 使用 Google 管理的 SSL 证书时,您必须先在 GKE 外部创建 SSL 证书,然后才能将其附加到 Gateway。

  • Google 管理的 SSL 证书与区域 Gateway 不兼容。 如需详细了解每个 GatewayClass 的 TLS 终止方法,请参阅 GatewayClass TLS 支持

  • 如果您在 GCPBackendPolicy 中引用 Google Cloud Armor 后端安全政策,则无法将同一服务用作区域和全球网关的后端。您必须为此用例创建两个单独的服务和政策。

  • Gateway Controller 不支持 ManagedCertificate 资源。

  • Gateway Controller 不支持 networking.gke.io/managed-certificates 注解。

  • Service 配置中的 appProtocol 字段仅接受将大写字母用于协议值(HTTPHTTPSHTTP2)。使用小写字母会导致将 HTTP 作为协议来用于后端。

使用 Kubernetes Secret 保护 Gateway 安全

在此示例中,您将使用 Kubernetes Secret 配置 Gateway。

将证书存储在 Kubernetes Secret 中

您可以使用证书授权机构 (CA) 颁发并验证的证书,也可以创建自签名证书。以下步骤使用自签名证书。

  1. 创建私钥:

    openssl genrsa -out PRIVATE_KEY_FILE 2048
    

    PRIVATE_KEY_FILE 替换为您的私钥文件的名称,例如 private-key.pem。如需了解详情,请参阅选择或创建私钥

  2. 创建 OpenSSL 配置文件

    cat <<EOF >CONFIG_FILE
    [req]
    default_bits              = 2048
    req_extensions            = extension_requirements
    distinguished_name        = dn_requirements
    prompt                    = no
    
    [extension_requirements]
    basicConstraints          = CA:FALSE
    keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName            = @sans_list
    
    [dn_requirements]
    0.organizationName        = example
    commonName                = store.example.com
    
    [sans_list]
    DNS.1                     = store.example.com
    EOF
    

    CONFIG_FILE 替换为新配置文件的名称,例如 config-file.cnf

  3. 创建证书签名请求 (CSR) 文件:

    openssl req -new -key PRIVATE_KEY_FILE \
        -out CSR_FILE \
        -config CONFIG_FILE
    

    CSR_FILE 替换为新 CSR 文件的名称,例如 cert.pem。如需了解详情,请参阅创建 CSR

  4. 为 CSR 签名:

    openssl x509 -req \
        -signkey PRIVATE_KEY_FILE \
        -in CSR_FILE \
        -out CERTIFICATE_FILE \
        -extfile CONFIG_FILE \
        -extensions extension_requirements \
        -days 30
    

    CERTIFICATE_FILE 替换为命令生成的文件的路径和名称,例如 cert-file.pem。如需了解详情,请参阅为 CSR 签名

  5. 使用您创建的密钥和证书文件创建 Kubernetes TLS Secret:

    kubectl create secret tls store-example-com \
        --cert=CERTIFICATE_FILE \
        --key=PRIVATE_KEY_FILE
    

    GKE 会将证书和密钥保存为 Kubernetes 资源,您可以将其附加到 Gateway。

创建 Gateway 和 HTTPRoute

  1. 将以下清单保存为 external-gateway.yaml

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          certificateRefs:
          - name: store-example-com
    

    此清单描述了具有以下属性的 Gateway:

    • gatewayClassName: gke-l7-global-external-managed:部署全球外部应用负载均衡器。
    • protocol: HTTPSport: 443:启用 TLS 时需要。
    • tls:引用上一步创建的 Kubernetes Secret。
  2. 将清单应用于集群:

    kubectl apply -f external-gateway.yaml
    
  3. 将以下清单保存为 store-external-route.yaml

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    

    此清单描述了一个 HTTPRoute,它将流量匹配到 store.example.com 并将其发送到 store-v1 Service。

  4. 将清单应用于集群:

    kubectl apply -f store-external-route.yaml
    

验证 Gateway

通过互联网发送请求来验证 Gateway 是否正常工作。

  1. 获取 Gateway 的 IP 地址:

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    输出类似于以下内容:

    203.0.113.12
    

    此输出是一个公共 IP 地址,这意味着任何可以访问互联网的客户端都可以连接到该 IP 地址。

  2. 使用 curl 访问 Gateway 的网域:

    curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -v
    

    请替换以下内容:

    • GATEWAY_IP_ADDRESS:Gateway 负载均衡器的 IP 地址。
    • CERTIFICATE_FILE:您生成的证书文件。您必须将此文件保存在用于连接到 Gateway 的机器上。由于 Gateway 使用自签名证书,因此需要证书来对 Gateway 进行身份验证。

    --resolve 选项会将域名解析为网关的 IP 地址,因为此网域未配置 DNS,因此您必须执行此操作

    输出类似于以下内容:

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08"
      # Several lines of output omitted here.
    }
    

    此输出包括成功的 TLS 握手,然后是来自应用的响应。TLS 连接在 Gateway 上终止,并且应用会安全地响应客户端。

使用 SSL 证书保护 Gateway 安全

在此示例中,您将使用 Google 管理的 SSL 证书配置 Gateway。

创建 SSL 证书

  1. 创建 Google 管理的全局 SslCertificate 资源:

    gcloud compute ssl-certificates create store-example-com \
        --domains=store.example.com \
        --global
    

创建 Gateway 和 HTTPRoute

  1. 将以下清单保存为 external-gateway.yaml

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          options:
            networking.gke.io/pre-shared-certs: store-example-com
    

    此清单描述了具有以下属性的 Gateway:

    • gatewayClassName: gke-l7-global-external-managed:部署全球外部应用负载均衡器。
    • protocol:HTTPSport:443:启用 TLS 时需要。
    • tls.mode:Terminate:使用您的 SSL 证书终止 TLS。
  2. 将清单应用到您的集群:

    kubectl apply -f external-gateway.yaml
    
  3. 将以下 HTTPRoute 清单保存为 store-external-route.yaml

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    
  4. 在集群中部署 HTTPRoute:

    kubectl apply -f store-external-route.yaml
    

    GKE 部署 Gateway 可能需要几分钟时间。

验证 Gateway

  1. 获取 Gateway 的 IP 地址:

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    输出类似于以下内容:

    203.0.113.12
    

    此输出是一个公共 IP 地址,这意味着任何可以访问互联网的客户端都可以连接到该 IP 地址。

  2. 更新 A 或 AAAA 记录,将您的网域定向到 Gateway 的 IP 地址。

    只有在配置 Google 管理的 SSL 证书时才需要执行此步骤。如果要配置自行管理的证书,则可以跳过此步骤。

    更新 DNS 记录后,负载均衡器最多可能需要 10 分钟才能开始使用 Google 管理的证书。

  3. 使用 curl 通过互联网发送请求来验证 Gateway 是否正常工作:

    curl https://store.example.com -v
    

    输出类似于以下内容:

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    此输出包含成功的 TLS 握手和来自应用的响应。TLS 在 Gateway 上正确终止,并且应用会安全地响应客户端。

使用 Certificate Manager 保护 Gateway 安全

在此示例中,您将使用 Certificate Manager 配置 Gateway。

创建 Certificate

全球网关

如需创建全球网关,您需要引用包含一个或多个证书的证书映射资源。您必须至少创建一个证书,并将其作为条目添加到证书映射。

  1. 如需创建证书,请先创建私钥和证书文件

  2. 通过加载自行管理的证书和密钥来创建 Certificate 资源:

    gcloud certificate-manager certificates create store-example-com-cert \
        --certificate-file="cert.pem" \
        --private-key-file="PRIVATE_KEY_FILE"
    
  3. 创建 CertificateMap

    gcloud certificate-manager maps create store-example-com-map
    
  4. 创建用于将证书分配给 CertificateMapCertificateMapEntry

    gcloud certificate-manager maps entries create store-example-com-map-entry \
        --map=store-example-com-map \
        --hostname=store.example.com \
        --certificates=store-example-com-cert
    

区域网关

对于区域网关,您需要创建 Certificate,在创建网关时直接指定。与全球网关不同,您无需创建将证书分配给的 CertificateMap

  1. 创建私钥和证书文件

  2. 通过上传证书文件和密钥来创建 Certificate 资源:

gcloud certificate-manager certificates create "CERTIFICATE_NAME" \
    --certificate-file="CERTIFICATE_FILE" \
    --private-key-file="PRIVATE_KEY_FILE" \
    --location="REGION"

替换以下内容:

  • CERTIFICATE_NAME:您的证书的名称,例如 store-example-com-cert
  • CERTIFICATE_FILE:证书文件的名称,例如 cert.pem
  • PRIVATE_KEY_FILE:您的私钥文件的名称,例如 private-key.pem。如需了解详情,请参阅选择或创建私钥
  • REGION:要在其中配置网关的区域的名称,例如 us-central1

创建 Gateway 和 HTTPRoute

全球网关

如需创建全球网关,请完成以下步骤:

  1. 将以下清单保存为 cert-map-gateway.yaml

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      annotations:
        networking.gke.io/certmap: store-example-com-map
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
    

    此清单描述了具有以下属性的 Gateway:

    • gatewayClassName: gke-l7-global-external-managed:部署全球外部应用负载均衡器。
    • protocol: HTTPSport: 443:启用 TLS 时需要。

    没有 TLS 部分,因为 TLS 是使用注释 networking.gke.io/certmap 来配置 Certificate Manager 的。

  2. 将清单应用于集群:

    kubectl apply -f cert-map-gateway.yaml
    

    GKE 部署 Gateway 可能需要几分钟时间。

  3. 如需创建 HTTPRoute,请将以下清单保存为 cert-map-http-route.yaml

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: foo
      namespace: default
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - foo.example.com
      rules:
      - matches:
        - path:
            value: /
        backendRefs:
        - name: foo-v1
          port: 8080
    
  4. 将清单应用于集群:

    kubectl apply -f cert-map-http-route.yaml
    

区域网关

创建区域级网关时,您可以指定由 Certificate Manager 管理的证书和由 Compute Engine 管理的证书。

  1. 如需创建区域级外部网关,请将以下清单保存为 external-gateway.yaml

       kind: Gateway
       apiVersion: gateway.networking.k8s.io/v1beta1
       metadata:
         name: gateway
         namespace: corp
       spec:
         gatewayClassName: gke-17-regional-external-managed
         listeners:
         - name: gateway-pre-shared-certmap
           protocol: HTTPS
           port: 443
           tsl:
             mode: Terminate
             options:
               networking.gke.io/cert-manager-certs: store-example-com-cert1, store-example-com-cert2
           allowedRoutes:
             kinds:
             - kind: HTTPRoute
             namespaces:
               from: All
    

    此清单描述了具有以下属性的 Gateway:

    • gatewayClassNamegke-l7-regional-external-managed:部署区域级外部应用负载均衡器。
    • protocol: HTTPSport: 443:启用 TLS 时需要。
    • options
      • networking.gke.io/cert-manager-certs:由 Certificate Manager 管理的证书。

    如需创建区域级内部网关,请在前面的示例中将 gatewayClassName 的值更改为 gke-17-rilb。这将部署内部应用负载均衡器。

  2. 将清单应用于集群:

    kubectl apply -f external-gateway.yaml
    
  3. 如需创建 HTTPRoute,请将以下清单保存为 store-external-route.yaml

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
        backendRefs:
        - name: store-v1
          port: 8080
    

    此清单描述了一个与 store.example.com 的流量匹配并将流量转发到 store-v1 Service 的 HTTPRoute。

  4. 将清单应用于集群:

    kubectl apply -f store-external-route.yaml
    

验证 Gateway

  1. 获取 Gateway 的 IP 地址:

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    输出类似于以下内容:

    203.0.113.12
    

    此输出是一个公共 IP 地址,这意味着任何可以访问互联网的客户端都可以连接到该 IP 地址。

  2. 更新 A 或 AAAA 记录,将您的网域定向到 Gateway 的 IP 地址。

    只有在配置 Google 管理的 SSL 证书时才需要执行此步骤。如果要配置自行管理的证书,则可以跳过此步骤。

    更新 DNS 记录后,负载均衡器最多可能需要 10 分钟才能开始使用 Google 管理的证书。

  3. 使用 curl 访问 Gateway 的网域:

    curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -v
    

    请替换以下内容:

    • GATEWAY_IP_ADDRESS:Gateway 负载均衡器的 IP 地址。
    • CERTIFICATE_FILE:您生成的证书文件。您必须将此文件保存在用于连接到 Gateway 的机器上。由于 Gateway 使用自签名证书,因此需要证书来对 Gateway 进行身份验证。

    输出类似于以下内容:

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    此输出包含成功的 TLS 握手和来自应用的响应。TLS 在 Gateway 上正确终止,并且应用会安全地响应客户端。

使用 TLS 保护负载均衡器到应用的流量

您可以使用 ports[].appProtocol 字段加密从负载均衡器到后端 Pod 的流量。支持的 appProtocol 字段为:HTTPHTTPSHTTP2

以下清单描述了一个指定负载均衡器必须使用 HTTPS 流量与后端 Pod 通信的 Service:

apiVersion: v1
kind: Service
metadata:
  name: store-v2
spec:
  selector:
    app: store
    version: v2
  ports:
  - port: 8080
    targetPort: 8080
    appProtocol: HTTPS

负载均衡器不会验证后端 Pod 使用的证书。您需要负责确保后端 Pod 上使用的证书有效。

使用 SSL 政策保护客户端到负载均衡器的流量

当您的应用通过使用 HTTPS 的外部 Gateway 公开时,请务必使用最新协议或指定最低 SSL 或 TLS 版本。您可以使用 SSL 政策保护客户端到负载均衡器的流量。

如需详细了解可附加到 Gateway 的 SSL 政策以及如何创建这些政策,请参阅配置 SSL 政策以保护客户端到负载均衡器的流量

使用 Google Cloud Armor 保护您的后端

Google Cloud Armor 安全政策可帮助保护您的负载均衡应用免遭 Web 攻击。配置 Google Cloud Armor 安全政策后,您可以在应用于 Kubernetes Service 的 GCPBackendPolicy 中引用该政策。

如需使用 Gateway 配置 Google Cloud Armor 政策,请参阅配置 Google Cloud Armor 安全政策以保护后端服务

使用 Identity-Aware Proxy 对发送到后端的请求进行身份验证

Identity-Aware Proxy 会对向您的应用发送请求的客户端进行身份验证并强制执行基于角色的流量授权,从而帮助您保护后端免受不必要的流量的影响。启用 Identity-Aware Proxy for GKE 后,您可以在应用于 Kubernetes 服务的 GCPBackendPolicy 中引用您的 OAuth 凭据。

如需使用 Gateway 配置 Identity-Aware Proxy,请参阅配置 Identity-Aware Proxy

后续步骤