如何为 GKE 上的 Kubernetes Ingress 强制使用 SSL

How to force SSL for Kubernetes Ingress on GKE

有没有办法强制对入口负载平衡器上的传入连接进行 SSL 升级?或者,如果这不可能,我可以禁用端口 :80 吗?我还没有找到一个很好的文档页面来概述 YAML 文件中的此类选项。提前致谢!

https://github.com/kubernetes/ingress-gce#frontend-https

您可以通过注释 kubernetes.io/ingress.allow-http: "false" 阻止 HTTP 或通过指定自定义后端将 HTTP 重定向到 HTTPS。不幸的是,GCE 还没有直接为您处理 L7 层的重定向或重写。 (参见 https://github.com/kubernetes/ingress-gce#ingress-cannot-redirect-http-to-https

更新:GCP now handles redirection rules for load balancers,包括 HTTP 到 HTTPS。似乎还没有通过 Kubernetes YAML 创建这些的方法。

注释已更改:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
    kubernetes.io/ingress.allow-http: "false"
spec:
...

这是注释更改 PR: https://github.com/kubernetes/contrib/pull/1462/files

如果您没有绑定到 GCLB Ingress Controller,您可以查看 Nginx Ingress Controller。该控制器在多个方面与内置控制器不同。首先,您需要自己部署和管理一个。但如果您愿意这样做,您将获得不依赖于 GCE LB(20 美元/月)并获得 IPv6/websockets.

支持的好处

documentation 状态:

By default the controller redirects (301) to HTTPS if TLS is enabled for that ingress . If you want to disable that behaviour globally, you can use ssl-redirect: "false" in the NGINX config map.

最近发布的 0.9.0-beta.3 附带了一个额外的注释,用于明确执行此重定向:

Force redirect to SSL using the annotation ingress.kubernetes.io/force-ssl-redirect

在 Kubernetes 中重定向到 HTTPS 有点复杂。根据我的经验,您可能希望使用 Ambassador or ingress-nginx 之类的入口控制器来控制到您服务的路由,而不是让您的负载均衡器直接路由到您的服务。

假设您使用的是入口控制器,那么:

  • 如果您要在外部负载均衡器上终止 TLS,并且 LB 在 L7 模式下是 运行(即 HTTP/HTTPS),那么您的入口控制器需要使用 X-Forwarded-Proto ,并相应地发出重定向。
  • 如果您在外部负载均衡器上终止 TLS,并且 LB 在 TCP/L4 模式下处于 运行,那么您的入口控制器需要使用 PROXY 协议来进行重定向。
  • 您也可以直接在入口控制器中终止 TLS,在这种情况下,它具有执行重定向所需的所有信息。

这里是关于如何在 Ambassador 中执行此操作的tutorial

Google 已响应我们的请求并正在其负载平衡器上测试 HTTP->HTTPS SSL 重定向。 Their latest answer 说它应该在 2020 年 1 月结束之前的某个时候处于 Alpha 阶段。

他们的评论:

Thank you for your patience on this issue. The feature is currently in testing and we expect to enter Alpha phase before the end of January. Our PM team will have an announcement with more details as we get closer to the Alpha launch.

我很高兴在不久的将来我们将有一个简单的解决方案来解决这个非常常见的功能。


更新(2020 年 4 月)

不幸的是,

HTTP(S) 重写现在是 Generally Available feature. It's still a bit rough around the edges and does not work out-of-the-box with the GCE Ingress Controller。但时间会证明一切,希望会出现原生解决方案。

您可以 disable HTTP on your cluster (note that you'll need to recreate your cluster for this change to be applied on the load balancer) and then set HTTP-to-HTTPS redirect 通过在同一 IP 地址上创建额外的负载平衡器。

我在同一个问题上花了几个小时,最后做了我刚才描述的事情。它完美运行。

为此工作了很长时间。以防有人不清楚上面的 post。你会用注释重建你的入口 -- kubernetes.io/ingress.allow-http: "false" -- 然后删除您的入口并重新部署。注释将使入口只为 443 创建一个 LB,而不是同时为 443 和 80 创建 LB。

然后你做一个计算 HTTP LB,而不是 GKE。

向导说明: 创建负载均衡器并选择 HTTP(S) 负载均衡 -- 开始配置。

选择 - 从 Internet 到我的虚拟机并继续

为 LB 选择一个名称

将后端配置留空。

在主机和路径规则下,select 高级主机和路径规则的操作设置为 将客户端重定向到不同的 host/path。 将主机重定向字段留空。 Select Prefix Redirect 并将 Path 值留空。 选择重定向响应代码为 308。 勾选启用 HTTPS 重定向框。

对于前端配置,保留 http 和端口 80,对于 ip 地址 select 静态 用于您的 GKE 入口的 IP 地址。

创建此 LB。

您现在将所有 http 流量都转到此,并将 308 重定向到 GKE 的 https 入口。超级简单的配置设置并且运行良好。

注意:如果您只是尝试删除 GKE 创建的端口 80 LB(不进行注释更改和重建入口),然后添加新的重定向计算 LB,它确实有效,但您会开始看到错误Ingress 上的消息说错误 400 字段 'resource.ipAddress 的无效值“”正在使用并且会导致冲突,无效。它试图启动端口 80 LB 但不能,因为您已经在使用相同 IP 的端口 80 上有一个 LB。它确实有效,但错误很烦人,GKE 一直在尝试构建它(我认为)。

快速更新。 Here

现在可以创建 FrontEndConfig 来配置入口。希望对您有所帮助。

示例:

apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: my-frontend-config
spec:
  redirectToHttps:
    enabled: true
    responseCodeName: 301

您需要确保您的负载均衡器支持 HTTP 和 HTTPS

已通过对已接受答案的评论正确回答了这个问题。但是由于评论被埋没了我错过了好几次

从 GKE 版本 1.18.10-gke.600 开始,您可以添加 k8s 前端配置以从 http 重定向到 https。

https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-features#https_redirect

apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: ssl-redirect
spec:
  redirectToHttps:
    enabled: true

# add below to ingress
# metadata:
#   annotations:
#     networking.gke.io/v1beta1.FrontendConfig: ssl-redirect

感谢@Andrej Palicka 的评论和他提供的页面:https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-features#https_redirect 现在我有了一个更新的有效解决方案。

首先我们需要定义一个 FrontendConfig 资源,然后我们需要告诉 Ingress 资源使用这个 前端配置.

示例:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-app-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: myapp-prd
    networking.gke.io/managed-certificates: managed-cert
    kubernetes.io/ingress.class: "gce"
    networking.gke.io/v1beta1.FrontendConfig: myapp-frontend-config
spec:
  defaultBackend:
    service:
      name: myapp-app-service
      port:
        number: 80
---
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: myapp-frontend-config
spec:
  redirectToHttps:
    enabled: true
    responseCodeName: MOVED_PERMANENTLY_DEFAULT