确保 GKE Ingress 的流量安全

本页面介绍如何保护和优化 Google Kubernetes Engine (GKE) Ingress 的流量。您可以在客户端和负载均衡器之间配置 SSL 证书,并确保负载均衡器与后端应用之间的流量安全。在继续之前,请确保您熟悉 GKE 如何通过 HTTPS 保护 Ingress

本页面适用于为组织设计和架构网络以及安装、配置和支持网络设备的网络专家。如需详细了解我们在Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE 用户角色和任务

保护并优化客户端与负载均衡器之间的流量

如需接受来自客户端的 HTTPS 请求,负载均衡器必须具有证书,以便向客户端证明其身份。负载均衡器还必须具有私钥才能完成 HTTPS 握手。如需详细了解如何为 HTTP(S) 负载均衡器提供 SSL 证书,请参阅在客户端与负载均衡器之间配置 TLS

使用 Google 管理的证书

如需配置一个或多个由 Google 管理的 SSL 证书并将其与 Ingress 关联,您需要执行以下操作:

  • 在 Ingress 所在的命名空间中创建一个或多个 ManagedCertificate 对象。您可以为负载均衡器指定最多 15 个证书
  • 通过将 networking.gke.io/managed-certificates 注解添加到 Ingress,将 ManagedCertificate 对象与 Ingress 相关联。此注解一个是英文逗号分隔的 ManagedCertificate 对象列表。

限制

本部分介绍了 Google 管理的证书的限制。如果您需要自行管理的证书,或者您已经拥有要在 Ingress 上配置的 SSL 证书,请参阅在客户端和负载均衡器之间设置 HTTPS (TLS)

  • 由 Google 管理的证书不如由您获得和管理的证书灵活。Google 管理的证书最多支持 100 个非通配符网域。与自行管理的证书不同,Google 管理的证书不支持通配符网域。

  • Ingress 所支持证书的数量和类型由 Google 管理的 SSL 证书的限制定义。

  • 不支持对由 Google 管理的证书进行更新。 如需了解详情,请参阅手动更新由 Google 管理的证书

  • 如果证书直接由证书授权机构撤消,Google 不会自动轮替证书。您必须删除 ManagedCertificate,然后创建一个新证书。

  • GKE Ingress 不支持由 Certificate Manager 管理的证书。如需使用由 Certificate Manager 管理的证书,请使用 Gateway API

前提条件

  • 您必须拥有域名。域名长度不得超过 63 个字符。您可以使用任何域名注册商来获取域名。

  • 如果您使用 GKE Standard 集群,则必须启用 HttpLoadBalancing 插件。

  • 您的 Ingress 清单必须包含 kubernetes.io/ingress.class: "gce" 注解。ingressClassName 字段不受支持。

  • 您必须在同一项目和命名空间中应用 IngressManagedCertificate 资源。

  • 创建预留的(静态)外部 IP 地址。 预留静态 IP 地址可以确保该地址始终属于您,即使您删除 Ingress 也是如此。如果您不预留 IP 地址,则 IP 地址可能会更改,这样您需要重新配置您的网域的 DNS 记录。请使用 Google Cloud CLI 或 Google Cloud 控制台创建预留的 IP 地址。

    gcloud

    如需创建预留 IP 地址,请运行以下命令:

    gcloud compute addresses create ADDRESS_NAME --global
    

    ADDRESS_NAME 替换为您要创建的预留 IP 地址的名称。

    如需查找您创建的静态 IP 地址,请运行以下命令:

    gcloud compute addresses describe ADDRESS_NAME --global
    

    输出内容类似如下:

    address: 203.0.113.32
    ...
    

    控制台

    如需创建预留的 IP 地址,请执行以下步骤:

    1. 进入 Google Cloud 控制台中的外部 IP 地址页面。

      转到“外部 IP 地址”

    2. 为此 IP 地址指定名称(例如 example-ip-address)。

    3. 指定您需要 IPv4 还是 IPv6 地址。

    4. 选择类型对应的全球选项。

    5. 点击预留。 IP 地址在外部地址列中列出。

    Config Connector

    注意:此步骤需要使用 Config Connector。按照安装说明在您的集群上安装配置连接器。

    apiVersion: compute.cnrm.cloud.google.com/v1beta1
    kind: ComputeAddress
    metadata:
      name: example-ip-address
    spec:
      location: global
    如需部署此清单,请将它以 compute-address.yaml 的形式下载到您的机器上,然后运行以下命令:

    kubectl apply -f compute-address.yaml
    

设置由 Google 管理的证书

  1. 创建一个 ManagedCertificate 对象。 此资源会指定 SSL 证书的网域。不支持通配符网域。

    以下清单描述了一个 ManagedCertificate 对象。将此清单保存为 managed-cert.yaml

    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: FIRST_CERT_NAME
    spec:
      domains:
        - FIRST_DOMAIN
    ---
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: SECOND_CERT_NAME
    spec:
      domains:
        - SECOND_DOMAIN
    

    替换以下内容:

    • FIRST_CERT_NAME:第一个 ManagedCertificate 对象的名称。
    • FIRST_DOMAIN:您拥有的第一个网域。
    • SECOND_CERT_NAME:第二个 ManagedCertificate 对象的名称。
    • SECOND_DOMAIN:您拥有的第二个网域。

    ManagedCertificate 对象的名称不同于其创建的实际证书的名称。您只需知道 ManagedCertificate 对象的名称,以在 Ingress 中使用它们。

  2. 将清单应用到您的集群:

    kubectl apply -f managed-cert.yaml
    
  3. 按照说明创建 Deployment 和 Service,以便在互联网上公开应用。

  4. 若要让此 ManagedCertificate 对象变为 Active,请使用 networking.gke.io/managed-certificates 注解将其关联到您的 Ingress,如以下示例所示。ManagedCertificate 不必为 Active 即可将其关联到 Ingress。

     apiVersion: networking.k8s.io/v1
     kind: Ingress
     metadata:
       name: my-gmc-ingress
       annotations:
         networking.gke.io/managed-certificates: "FIRST_CERT_NAME,SECOND_CERT_NAME"
     spec:
       rules:
       - host: FIRST_DOMAIN
         http:
           paths:
           - pathType: ImplementationSpecific
             backend:
               service:
                 name: my-mc-service
                 port:
                   number: 60001
       - host: SECOND_DOMAIN
         http:
           paths:
           - pathType: ImplementationSpecific
             backend:
               service:
                 name: my-mc-service
                 port:
                   number: 60002
     ```
    
    Replace <code><var>FIRST_DOMAIN</var></code> and
    <code><var>SECOND_DOMAIN</var></code> with your domain names.
    
    This manifest describes an Ingress that lists pre-shared certificate
    resources in an annotation.
    
    Note: It might take several hours for Google Cloud to provision the load
    balancer and the managed certificates, and for the load balancer to begin
    using the new certificates. For more information, see
    [Deploy a Google-managed certificate with load balancer authorization](/certificate-manager/docs/deploy-google-managed-lb-auth#wait_until_the_certificate_has_been_activated).
    
  5. 等待 Google 管理的证书完成预配。此过程最多可能需要 60 分钟。您可以使用以下命令检查证书的状态:

    kubectl describe managedcertificate managed-cert
    

    输出类似于以下内容:

    Name:         managed-cert
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    API Version:  networking.gke.io/v1
    Kind:         ManagedCertificate
    (...)
    Spec:
     Domains:
       FQDN_1
       FQDN_2
    Status:
     CertificateStatus: Active
    (...)
    

    Status.CertificateStatus 字段的值指示证书是否已预配。如果 Status.CertificateStatus 不是 Active,则表示证书尚未预配。

  6. 使用 https:// 前缀访问您的网域,验证 SSL 是否正常工作。您的浏览器会指示连接是否安全,您可以查看证书详细信息。

从自行管理的证书迁移到由 Google 管理的证书

将 Ingress 从使用自行管理的 SSL 证书迁移到 Google 管理的 SSL 证书时,在 Google 管理的 SSL 证书处于活跃状态之前,请不要删除任何自行管理的 SSL 证书。成功预配由 Google 管理的 SSL 证书后,它们会自动处于活跃状态。 由 Google 管理的 SSL 证书生效时,您可以删除自行管理的 SSL 证书。

使用以下说明从自行管理的 SSL 证书迁移到 Google 管理的 SSL 证书。

  1. 将由 Google 管理的新证书添加到 Ingress,如上一部分中所述。
  2. 等待由 Google 管理的证书资源的状态变为 Active。 使用以下命令检查证书的状态:

    kubectl describe managedcertificate managed-cert
    
  3. 状态为 Active 时,更新 Ingress,以移除对自行管理证书的引用。

移除由 Google 管理的证书

如需从集群中移除由 Google 管理的证书,您必须删除 ManagedCertificate 对象并移除引用它的 Ingress 注解。

  1. 删除 ManagedCertificate 对象:

    kubectl delete -f managed-cert.yaml
    

    输出内容类似如下:

    managedcertificate.networking.gke.io "managed-cert" deleted
    
  2. 从 Ingress 中移除注释:

    kubectl annotate ingress managed-cert-ingress networking.gke.io/managed-certificates-
    

    请注意命令末尾的减号 -

  3. 释放您为负载均衡器预留的静态 IP 地址。

    您可以使用 Google Cloud CLI、 Google Cloud 控制台或 Config Connector 释放预留的 IP 地址。

    gcloud

    使用以下命令释放预留的 IP 地址:

    gcloud compute addresses delete ADDRESS_NAME --global
    

    ADDRESS_NAME 替换为该 IP 地址的名称。

    控制台

    如需释放预留的 IP 地址,请执行以下步骤:

    1. 进入 Google Cloud 控制台中的外部 IP 地址页面。

      转到“外部 IP 地址”

    2. 选中要释放的 IP 地址旁边的复选框。

    3. 点击释放 IP 地址

    Config Connector

    注意:此步骤需要使用 Config Connector。按照安装说明在您的集群上安装配置连接器。

    apiVersion: compute.cnrm.cloud.google.com/v1beta1
    kind: ComputeAddress
    metadata:
      name: example-ip-address
    spec:
      location: global

    如需部署此清单,请将它以 compute-address.yaml 的形式下载到您的机器上,然后运行以下命令:

    kubectl delete -f compute-address.yaml
    

创建证书和密钥

如需使用预共享证书或 Kubernetes Secret,您首先需要一个或多个证书以及相应的私钥。每个证书的公用名 (CN) 必须与您拥有的域名一致。如果您的两个证书文件的公用名都有适当的值,可跳转至下一部分。

  1. 创建第一个密钥:

    openssl genrsa -out test-ingress-1.key 2048
    
  2. 创建第一个证书签名请求:

    openssl req -new -key test-ingress-1.key -out test-ingress-1.csr \
        -subj "/CN=FIRST_DOMAIN"
    

    FIRST_DOMAIN 替换为您拥有的域名,例如 example.com

  3. 创建第一个证书:

    openssl x509 -req -days 365 -in test-ingress-1.csr -signkey test-ingress-1.key \
        -out test-ingress-1.crt
    
  4. 创建第二个密钥:

    openssl genrsa -out test-ingress-2.key 2048
    
  5. 创建第二个证书签名请求:

    openssl req -new -key test-ingress-2.key -out test-ingress-2.csr \
        -subj "/CN=SECOND_DOMAIN"
    

    SECOND_DOMAIN 替换为您拥有的另一个域名,例如 examplepetstore.com

  6. 创建第二个证书:

    openssl x509 -req -days 365 -in test-ingress-2.csr -signkey test-ingress-2.key \
        -out test-ingress-2.crt
    

如需详细了解证书和密钥,请参阅 SSL 证书概览

您现在有了 2 个证书文件和 2 个密钥文件。

其余任务使用以下占位符来引用您的网域、证书和密钥:

  • FIRST_CERT_FILE:第一个证书文件的路径。
  • FIRST_KEY_FILE:与第一个证书对应的密钥文件的路径。
  • FIRST_DOMAIN:您拥有的一个域名。
  • FIRST_SECRET_NAME:包含第一个证书和密钥的 Secret 的名称。
  • SECOND_CERT_FILE:第二个证书文件的路径。
  • SECOND_KEY_FILE:与第二个证书对应的密钥文件的路径。
  • SECOND_DOMAIN:您拥有的另一个域名。
  • SECOND_SECRET_NAME:包含第二个证书和密钥的 Secret 的名称。

使用预共享证书

您可以使用上传到 Google Cloud 项目的自行管理的 SSL 证书。这些证书称为预共享证书。您可以为 Ingress 指定一个或多个预共享证书。

如需使用多个预共享证书,请按以下步骤操作:

  1. 为每个证书和密钥对在 Google Cloud中创建一个公开可见的 SSL 证书资源。

     gcloud compute ssl-certificates create FIRST_CERT_NAME \
         --certificate=FIRST_CERT_FILE \
         --private-key=FIRST_KEY_FILE
     ```
    
    ```sh
     gcloud compute ssl-certificates create SECOND_CERT_NAME \
         --certificate=SECOND_CERT_FILE \
         --private-key=SECOND_KEY_FILE
     ```
    
    Replace the following:
    
    • FIRST_CERT_NAMESECOND_CERT_NAME:第一个和第二个证书的名称。
    • FIRST_CERT_FILESECOND_CERT_FILE:您的第一个和第二个证书文件
    • FIRST_KEY_FILE:和 SECOND_KEY_FILE:您的第一个和第二个密钥文件。
  2. 在 Ingress 清单中,添加 ingress.gcp.kubernetes.io/pre-shared-cert 注解。该注解的值是以英文逗号分隔的证书名称列表。此外,在 spec.rules 部分中,添加 host 字段以指定服务的网域。

     apiVersion: networking.k8s.io/v1
     kind: Ingress
     metadata:
       name: my-psc-ingress
       annotations:
         ingress.gcp.kubernetes.io/pre-shared-cert: "FIRST_CERT_NAME,SECOND_CERT_NAME"
     spec:
       rules:
       - host: FIRST_DOMAIN
         http:
           paths:
           - pathType: ImplementationSpecific
             backend:
               service:
                 name: my-mc-service
                 port:
                   number: 60001
       - host: SECOND_DOMAIN
         http:
           paths:
           - pathType: ImplementationSpecific
             backend:
               service:
                 name: my-mc-service
                 port:
                   number: 60002
     ```
    
    Replace <code><var>FIRST_DOMAIN</var></code> and
    <code><var>SECOND_DOMAIN</var></code> with your domain names.
    
    This manifest describes an Ingress that lists pre-shared certificate
    resources in an annotation.
    

使用 Kubernetes Secret

如需为 HTTP(S) 负载均衡器提供您自己创建的证书和密钥,请创建一个或多个 Kubernetes Secret 对象。每个 Secret 都包含一个证书和密钥。您将 Secret 添加到 Ingress 清单的 tls 字段中。负载均衡器使用服务器名称指示 (SNI),根据 TLS 握手中的域名确定要向客户端提供哪个证书。

如需使用多个证书,请按以下步骤操作:

  1. 为每个证书和密钥对创建一个 Secret:

     kubectl create secret tls FIRST_SECRET_NAME \
         --cert=FIRST_CERT_FILE \
         --key=FIRST_KEY_FILE
     ```
    
    ```sh
     kubectl create secret tls SECOND_SECRET_NAME \
         --cert=SECOND_CERT_FILE \
         --key=SECOND_KEY_FILE
     ```
    
  2. 在 Ingress 清单的 spec.tls 部分中,列出您创建的 Secret。此外,在 spec.rules 部分中,添加 host 字段以指定服务的网域。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-mc-ingress
    spec:
      tls:
      - secretName: FIRST_SECRET_NAME
      - secretName: SECOND_SECRET_NAME
      rules:
      - host: FIRST_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60001
      - host: SECOND_DOMAIN
        http:
          paths:
          - pathType: ImplementationSpecific
            backend:
              service:
                name: my-mc-service
                port:
                  number: 60002
    

    FIRST_DOMAINSECOND_DOMAIN 替换为您拥有的域名,例如 example.comexamplepetstore.com

系统会定期获取对 Secret 的更改,因此如果您修改了 Secret 内的数据,则最多需要 10 分钟就能将这些更改应用于负载平衡器。

要为您的 GKE 集群保护 HTTPS 加密的 Ingress,请参阅保护 Ingress 示例。

停用 HTTP

如果您希望客户端和负载均衡器之间的所有流量都使用 HTTPS,则可以通过在 Ingress 清单中添加 kubernetes.io/ingress.allow-http 注解来停用 HTTP。请将注释的值设置为 "false"

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress-2
  annotations:
    kubernetes.io/ingress.allow-http: "false"
spec:
  tls:
  - secretName: SECRET_NAME
  ...

此清单包含 SECRET_NAME,即您创建的 Secret 的名称。

客户端和负载平衡器之间的 HTTP/2

客户端可以使用 HTTP/2 向负载平衡器发送请求。无需配置。

保护和优化负载均衡器与应用之间的流量

您可以配置负载均衡器与应用 Pod 之间用于通信的协议,以确保端到端安全性或优化内部流量性能。虽然负载均衡器默认对后端连接使用未加密的 HTTP/1.1,但您可以启用 HTTPS 或 HTTP/2 来满足应用的特定要求。

负载均衡器和应用之间的 HTTPS

如果在 GKE Pod 中运行的应用能够接收 HTTPS 请求,您可以将负载均衡器配置成使用 HTTPS 将请求转发给应用。如需了解详情,请参阅负载均衡器和应用之间的 HTTPS (TLS)

如需配置负载均衡器和应用之间使用的协议,请在 Service 清单中使用 cloud.google.com/app-protocols 注释。 除非您使用容器原生负载均衡,否则此 Service 清单必须包含 type: NodePort。如果您使用容器原生负载均衡,请使用 type: ClusterIP

以下 Service 清单指定了两个端口。注释表明,如果 HTTP(S) 负载均衡器以 Service 的端口 80 作为目标,则应该使用 HTTP。如果负载均衡器以 Service 的端口 443 作为目标,则应该使用 HTTPS。

Service 清单必须在端口注解中包含一个 name 值。您只能通过引用 Service 已分配的 name 端口(而不是通过其 targetPort 值)来修改 Service 端口。

apiVersion: v1
kind: Service
metadata:
  name: my-service-3
  annotations:
    cloud.google.com/app-protocols: '{"my-https-port":"HTTPS","my-http-port":"HTTP"}'
spec:
  type: NodePort
  selector:
    app: metrics
    department: sales
  ports:
  - name: my-https-port
    port: 443
    targetPort: 8443
  - name: my-http-port
    port: 80
    targetPort: 50001

在负载均衡器和应用之间使用 HTTP/2

如果在 GKE Pod 中运行的应用能够接收 HTTP/2 请求,则可以将负载均衡器配置为在将请求转发给应用时使用 HTTP/2。

如需启用 HTTP/2,您必须在 Kubernetes Service 清单中使用 cloud.google.com/app-protocols 注解。此注解用于指定负载均衡器用于与应用通信的协议。为了确保负载平衡器可以向后端发出正确的 HTTP/2 请求,后端必须通过 SSL 进行配置。

以下是为 HTTP/2 配置的 Service 清单示例:

apiVersion: v1
kind: Service
metadata:
  name: my-http2-service
  annotations:
    cloud.google.com/app-protocols: '{"my-port":"HTTP2"}'
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - name: my-port
    protocol: TCP
    port: 443
    targetPort: 8443

请注意以下几点:

  • cloud.google.com/app-protocols 注解设置为 '{"my-port":"HTTP2"}',这会指示负载均衡器对发送到名为 my-port 的端口的流量使用 HTTP/2。
  • 端口设置为 443,并将流量定向到 targetPort 8443 上的 Pod。