IBM Cloud Kubernetes Service Ingress 到 Istio Ingress Gateway 的直接加密流量
配置 IBM Cloud Kubernetes Service 应用程序负载均衡器,以使用双向 TLS 将流量引导到 Istio Ingress 网关。
在本博文中,我将展示如何配置 Ingress 应用程序负载均衡器 (ALB) 在 IBM Cloud Kubernetes Service (IKS) 上将流量引导到 Istio Ingress 网关,同时使用 双向 TLS 身份验证 来保护它们之间的流量。
当您在没有 Istio 的情况下使用 IKS 时,可以使用提供的 ALB 控制您的入口流量。此入口流量路由使用 Kubernetes Ingress 资源和 ALB 特定的注释 进行配置。IKS 提供 DNS 域名、与域名匹配的 TLS 证书以及证书的私钥。IKS 将证书和私钥存储在 Kubernetes 密钥 中。
当您在 IKS 集群中开始使用 Istio 时,将流量发送到已启用 Istio 的工作负载的推荐方法是使用 Istio Ingress 网关,而不是使用 Kubernetes Ingress。使用 Istio Ingress 网关的主要原因之一是,当您启用 STRICT 双向 TLS 时,IKS 提供的 ALB 将无法直接与网格内的服务通信。在您过渡到仅将 Istio Ingress 网关作为主要入口点的过程中,您可以继续对非 Istio 服务使用传统的 Ingress,同时对属于网格一部分的服务使用 Istio Ingress 网关。
IKS 为客户端提供了一种便捷的方式来访问 Istio Ingress 网关,允许您使用 IKS 命令 注册 Istio 网关 IP 的新 DNS 子域名。该域名的格式如下 格式:<cluster_name>-<globally_unique_account_HASH>-0001.<region>.containers.appdomain.cloud
,例如 mycluster-a1b2cdef345678g9hi012j3kl4567890-0001.us-south.containers.appdomain.cloud
。与 ALB 域相同,IKS 提供证书和私钥,并将它们存储在另一个 Kubernetes 密钥中。
此博客介绍了如何将 IKS Ingress ALB 和 Istio Ingress 网关链接在一起,以便将流量发送到已启用 Istio 的工作负载,同时能够继续使用 ALB 特定的功能和 ALB 子域名。您配置 IKS Ingress ALB 以通过 Istio Ingress 网关将流量引导到 Istio 服务网格内的服务,同时在 ALB 和网关之间使用双向 TLS 身份验证。对于双向 TLS 身份验证,您将配置 ALB 和 Istio Ingress 网关以使用 IKS 为 ALB 和 NLB 子域名提供的证书和密钥。使用 IKS 提供的证书可以节省您管理 ALB 和 Istio Ingress 网关之间连接的自有证书的开销。
您将按预期使用 NLB 子域名证书作为 Istio Ingress 网关的服务器证书。NLB 子域名证书代表为特定 NLB 子域名提供服务的服务器的身份,在本例中,即 Ingress 网关。
您将使用 ALB 子域名证书作为 ALB 和 Istio Ingress 之间双向 TLS 身份验证中的客户端证书。当 ALB 充当服务器时,它会向客户端呈现 ALB 证书,以便客户端可以验证 ALB。当 ALB 充当 Istio Ingress 网关的客户端时,它会向 Istio Ingress 网关呈现相同的证书,以便 Istio Ingress 网关可以验证 ALB。
没有 Istio sidecar 的服务的流量可以像以前一样直接从 ALB 流向。
下图举例说明了所描述的设置。它显示了集群中的两个服务,service A
和 service B
。service A
注入了一个 Istio sidecar 并需要双向 TLS。service B
没有 Istio sidecar。客户端可以通过 ALB 访问 service B
,ALB 直接与 service B
通信。客户端也可以通过 ALB 访问 service A
,但在这种情况下,流量必须通过 Istio Ingress 网关。ALB 和网关之间的双向 TLS 身份验证基于 IKS 提供的证书。客户端也可以直接访问 Istio Ingress 网关。IKS 为 ALB 和 Ingress 网关注册了不同的 DNS 域名。
初始设置
创建
httptools
命名空间并启用 Istio sidecar 注入$ kubectl create namespace httptools $ kubectl label namespace httptools istio-injection=enabled namespace/httptools created namespace/httptools labeled
将
httpbin
示例部署到httptools
$ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n httptools service/httpbin created deployment.apps/httpbin created
为 ALB 和 Istio Ingress 网关创建密钥
当您使用 ibmcloud ks nlb-dns-create
命令为外部 IP 注册 DNS 域名时,IKS 会生成 TLS 证书和私钥,并将它们作为密钥存储在默认命名空间中。IKS 还将 ALB 的证书和私钥作为密钥存储在默认命名空间中。您需要这些凭据来建立 ALB 和 Istio Ingress 网关在它们之间的双向 TLS 身份验证期间将呈现的身份。您将配置 ALB 和 Istio Ingress 网关以交换这些证书,以信任彼此的证书,并使用其私钥加密和签名流量。
将集群名称存储在
CLUSTER_NAME
环境变量中$ export CLUSTER_NAME=<your cluster name>
将 ALB 的域名存储在
ALB_INGRESS_DOMAIN
环境变量中$ ibmcloud ks cluster get --cluster $CLUSTER_NAME | grep Ingress Ingress Subdomain: <your ALB ingress domain> Ingress Secret: <your ALB secret>
$ export ALB_INGRESS_DOMAIN=<your ALB ingress domain> $ export ALB_SECRET=<your ALB secret>
将
istio-ingressgateway
服务的外部 IP 存储在环境变量中。$ export INGRESS_GATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') $ echo INGRESS_GATEWAY_IP = $INGRESS_GATEWAY_IP
为 Istio Ingress Gateway 服务的 IP 创建 DNS 域名和证书
$ ibmcloud ks nlb-dns create classic --cluster $CLUSTER_NAME --ip $INGRESS_GATEWAY_IP --secret-namespace istio-system Host name subdomain is created as <some domain>
将来自上一个命令的域名存储在环境变量中
$ export INGRESS_GATEWAY_DOMAIN=<the domain from the previous command>
列出已注册的域名
$ ibmcloud ks nlb-dnss --cluster $CLUSTER_NAME Retrieving host names, certificates, IPs, and health check monitors for network load balancer (NLB) pods in cluster <your cluster>... OK Hostname IP(s) Health Monitor SSL Cert Status SSL Cert Secret Name Secret Namespace <your ingress gateway hostname> <your ingress gateway IP> None created <the matching secret name> istio-system ...
等待新域名的证书(第四个字段)的状态变为
enabled
(最初为pending
)。存储新域名的密钥的名称
$ export INGRESS_GATEWAY_SECRET=<the secret's name as shown in the SSL Cert Secret Name column>
从为 ALB 提供的密钥中提取证书和密钥
$ mkdir alb_certs $ kubectl get secret $ALB_SECRET --namespace=default -o yaml | grep 'tls.key:' | cut -f2 -d: | base64 --decode > alb_certs/client.key $ kubectl get secret $ALB_SECRET --namespace=default -o yaml | grep 'tls.crt:' | cut -f2 -d: | base64 --decode > alb_certs/client.crt $ ls -al alb_certs -rw-r--r-- 1 user staff 3738 Sep 11 07:57 client.crt -rw-r--r-- 1 user staff 1675 Sep 11 07:57 client.key
下载 Let’s Encrypt 证书的发行者证书,它是 IKS 提供的证书的发行者。您将此证书指定为要信任的证书颁发机构的证书,用于 ALB 和 Istio Ingress 网关。
$ curl https://letsencrypt.openssl.ac.cn/certs/trustid-x3-root.pem --output trusted.crt
创建一个 Kubernetes 密钥,供 ALB 用于建立双向 TLS 连接。
$ kubectl create secret generic alb-certs -n istio-system --from-file=trusted.crt --from-file=alb_certs/client.crt --from-file=alb_certs/client.key secret "alb-certs" created
对于双向 TLS,Ingress 网关需要一个名为
<tls-cert-secret>-cacert
且具有cacert
密钥的单独密钥。$ kubectl create -n istio-system secret generic $INGRESS_GATEWAY_SECRET-cacert --from-file=ca.crt=trusted.crt secret/cluster_name-hash-XXXX-cacert created
配置双向 TLS Ingress 网关
在本节中,您将配置 Istio Ingress 网关以在外部客户端和网关之间执行双向 TLS。您将使用为 Ingress 网关和 ALB 提供的证书和密钥。
定义一个
Gateway
以仅允许在端口 443 上访问,并使用双向 TLS$ kubectl apply -n httptools -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: default-ingress-gateway spec: selector: istio: ingressgateway # use istio default ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: MUTUAL credentialName: $INGRESS_GATEWAY_SECRET hosts: - "$INGRESS_GATEWAY_DOMAIN" - "httpbin.$ALB_INGRESS_DOMAIN" EOF
配置通过
Gateway
进入的流量的路由$ kubectl apply -n httptools -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: default-ingress spec: hosts: - "$INGRESS_GATEWAY_DOMAIN" - "httpbin.$ALB_INGRESS_DOMAIN" gateways: - default-ingress-gateway http: - match: - uri: prefix: /status route: - destination: port: number: 8000 host: httpbin.httptools.svc.cluster.local EOF
通过 curl 向
httpbin
发送请求,并将客户端证书(--cert
选项)和私钥(--key
选项)作为参数传递$ curl https://$INGRESS_GATEWAY_DOMAIN/status/418 --cert alb_certs/client.crt --key alb_certs/client.key -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
删除包含 ALB 和 Ingress 网关证书和密钥的目录。
$ rm -r alb_certs trusted.crt
配置 ALB
您需要配置您的 Ingress 资源以将流量引导到 Istio Ingress 网关,同时使用存储在 alb-certs
密钥中的证书。通常,ALB 会在将流量转发到您的应用程序之前解密 HTTPS 请求。您可以配置 ALB 在将流量转发到 Istio Ingress 网关之前重新加密流量,方法是在 Ingress 资源上使用 ssl-services
注释。此注释还允许您指定存储在 alb-certs
密钥中的证书,这是双向 TLS 所需的。
配置 ALB 的
Ingress
资源。您必须在istio-system
命名空间中创建Ingress
资源,以便将流量转发到 Istio Ingress 网关。$ kubectl apply -f - <<EOF apiVersion: extensions/v1beta1 kind: Ingress metadata: name: alb-ingress namespace: istio-system annotations: ingress.bluemix.net/ssl-services: "ssl-service=istio-ingressgateway ssl-secret=alb-certs proxy-ssl-name=$INGRESS_GATEWAY_DOMAIN" spec: tls: - hosts: - httpbin.$ALB_INGRESS_DOMAIN secretName: $ALB_SECRET rules: - host: httpbin.$ALB_INGRESS_DOMAIN http: paths: - path: /status backend: serviceName: istio-ingressgateway servicePort: 443 EOF
测试 ALB Ingress
$ curl https://httpbin.$ALB_INGRESS_DOMAIN/status/418 -=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
恭喜!您已配置 IKS Ingress ALB 以将加密流量发送到 Istio Ingress 网关。您为 Istio Ingress 网关分配了主机名和证书,并将该证书用作 Istio Ingress 网关的服务器证书。作为 ALB 的客户端证书,您使用了 IKS 为 ALB 提供的证书。一旦您将证书部署为 Kubernetes 密钥,您就会将来自 ALB 的入口流量引导到 Istio Ingress 网关以获取一些特定路径,并使用证书进行 ALB 和 Istio Ingress 网关之间的双向 TLS 身份验证。
清理
删除
Gateway
配置、VirtualService
和密钥$ kubectl delete ingress alb-ingress -n istio-system $ kubectl delete virtualservice default-ingress -n httptools $ kubectl delete gateway default-ingress-gateway -n httptools $ kubectl delete secrets alb-certs -n istio-system $ rm -rf alb_certs trusted.crt $ unset CLUSTER_NAME ALB_INGRESS_DOMAIN ALB_SECRET INGRESS_GATEWAY_DOMAIN INGRESS_GATEWAY_SECRET
关闭
httpbin
服务$ kubectl delete -f @samples/httpbin/httpbin.yaml@ -n httptools
删除
httptools
命名空间$ kubectl delete namespace httptools