IBM Cloud Kubernetes Service Ingress 到 Istio Ingress Gateway 的直接加密流量

配置 IBM Cloud Kubernetes Service 应用程序负载均衡器,以使用双向 TLS 将流量引导到 Istio Ingress 网关。

2020 年 5 月 15 日 | 作者:Vadim Eisenberg - IBM

在本博文中,我将展示如何配置 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 Aservice Bservice 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 域名。

A cluster with the ALB and the Istio ingress gateway
具有 ALB 和 Istio Ingress 网关的集群

初始设置

  1. 创建 httptools 命名空间并启用 Istio sidecar 注入

    $ kubectl create namespace httptools
    $ kubectl label namespace httptools istio-injection=enabled
    namespace/httptools created
    namespace/httptools labeled
    
  2. 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 网关以交换这些证书,以信任彼此的证书,并使用其私钥加密和签名流量。

  1. 将集群名称存储在 CLUSTER_NAME 环境变量中

    $ export CLUSTER_NAME=<your cluster name>
    
  2. 将 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>
    
  3. 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
    
  4. 为 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>
    
  5. 将来自上一个命令的域名存储在环境变量中

    $ export INGRESS_GATEWAY_DOMAIN=<the domain from the previous command>
    
  6. 列出已注册的域名

    $ 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)。

  7. 存储新域名的密钥的名称

    $ export INGRESS_GATEWAY_SECRET=<the secret's name as shown in the SSL Cert Secret Name column>
    
  8. 从为 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
    
  9. 下载 Let’s Encrypt 证书的发行者证书,它是 IKS 提供的证书的发行者。您将此证书指定为要信任的证书颁发机构的证书,用于 ALB 和 Istio Ingress 网关。

    $ curl https://letsencrypt.openssl.ac.cn/certs/trustid-x3-root.pem --output trusted.crt
    
  10. 创建一个 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
    
  11. 对于双向 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 提供的证书和密钥。

  1. 定义一个 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
    
  2. 配置通过 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
    
  3. 通过 curlhttpbin 发送请求,并将客户端证书(--cert 选项)和私钥(--key 选项)作为参数传递

    $ curl https://$INGRESS_GATEWAY_DOMAIN/status/418 --cert alb_certs/client.crt  --key alb_certs/client.key
    
    -=[ teapot ]=-
    
       _...._
     .'  _ _ `.
    | ."` ^ `". _,
    \_;`"---"`|//
      |       ;/
      \_     _/
        `"""`
    
  4. 删除包含 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 所需的。

  1. 配置 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
    
  2. 测试 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 身份验证。

清理

  1. 删除 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
    
  2. 关闭 httpbin 服务

    压缩
    $ kubectl delete -f @samples/httpbin/httpbin.yaml@ -n httptools
    
  3. 删除 httptools 命名空间

    $ kubectl delete namespace httptools
    
分享此文章