Egress 网关 TLS 连接 发起的过程 (SDS)

    TLS 所需的私钥、服务器证书和 root 证书是通过以下方式配置的Secret Discovery Service (SDS).

    • 按照安装指南中的说明设置 Istio。

    • 启动样例这将被用作外部调用的测试源。

      如果您已经启用了自动 Sidecar 注入,请执行

      否则,您必须在部署”sleep”应用程序之前手动注入 Sidecar。

      Zip

      $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)

      注意,任何您可以execcurl的 Pod 都可以。

    • 对于macOS用户,请确认您使用的是1.1或更高版本的openssl

      $ openssl version -a | grep OpenSSL OpenSSL 1.1.1g 2020年4月21日

      如果前面的命令输出的是”1.1”或更高版本,如图所示,您的”openssl”命令应该可以按照本任务的说明正常工作。否则,请升级您的openssl或尝试不同的openssl实现,例如在 Linux 机器上

    如果您使用基于文件挂载的方法配置了一个egress网关。 而您想把您的 Egress 网关迁移到使用SDS方法,则不需要额外的步骤。

    本节描述了如何执行TLS 连接流量 Egress 的例子。只是这次使用了一个 Egress 网关。请注意,在这种情况下,TLS初始化将由 Egress 网关完成。是由 Egress 网关完成的,而不是前一个例子中的挎包。Egress 网关将使用 SDS 而不是文件挂载来提供客户证书。

    对于这项任务,您可以使用您喜欢的工具来生成证书和钥匙。下面的命令使用openssl.

    1. 创建一个根证书和私钥,为您的服务签署证书:

      $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt

    2. my-nginx.mesh-external.svc.cluster.local创建一个证书和私钥:

      $ openssl req -out my-nginx.mesh-external.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout my-nginx.mesh-external.svc.cluster.local.key -subj "/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization" $ openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.mesh-external.svc.cluster.local.csr -out my-nginx.mesh-external.svc.cluster.local.crt

    部署一个简单的 TLS 服务器

    为了模拟一个支持简单 TLS 协议的实际外部服务。在您的Kubernetes集群中部署一个NGINX服务器,但在 Istio 服务网外运行,即在没有启用 Istio sidecar 代理注入的命名空间中。

    1. 创建一个命名空间来代表 Istio 网状结构之外的服务,即mesh-external。请注意,Sidecar 代理将不会被自动注入到这个命名空间的 Pod 中,因为自动注入 Sidecar 的功能没有被 上。

      $ kubectl create namespace mesh-external

    2. 创建 Kubernetes Secrets来保存服务器的和 CA 的证书。

      $ kubectl create -n mesh-external secret tls nginx-server-certs --key my-nginx.mesh-external.svc.cluster.local.key --cert my-nginx.mesh-external.svc.cluster.local.crt $ kubectl create -n mesh-external secret generic nginx-ca-certs --from-file=example.com.crt

    3. 为 NGINX 服务器创建一个配置文件:

      $ cat <<\EOF > ./nginx.conf events { } http { log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; server { listen 443 ssl; root /usr/share/nginx/html; index index.html; server_name my-nginx.mesh-external.svc.cluster.local; ssl_certificate /etc/nginx-server-certs/tls.crt; ssl_certificate_key /etc/nginx-server-certs/tls.key; ssl_client_certificate /etc/nginx-ca-certs/example.com.crt; ssl_verify_client off; # In simple TLS, server doesn't verify client's certificate } } EOF

    4. 创建一个 Kubernetes 来保存 NGINX 服务器的配置。

      $ kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf

    5. 部署 NGINX 服务器:

    1. 创建一个 Kubernetes Secret 来保存 Egress 网关用来发起 TLS 连接的CA证书。

      $ kubectl create secret generic client-credential-cacert --from-file=ca.crt=example.com.crt -n istio-system

      请注意,Istio 的纯 CA 证书的 Secret 名称必须以-cacert结尾,并且秘密必须在与 Istio 相同的命名空间中创建。Secret 必须与 Istio 部署的命名空间相同,本例中为 “istio-system”。

    2. my-nginx.mesh-external.svc.cluster.local创建一个 Egress gateway,端口443,以及目标规则和虚拟服务,以引导流量通过 Egress 网关并从 Egress 网关到外部服务

      $ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 443 name: https protocol: HTTPS hosts: - my-nginx.mesh-external.svc.cluster.local tls: mode: ISTIO_MUTUAL --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-nginx spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: nginx trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: ISTIO_MUTUAL sni: my-nginx.mesh-external.svc.cluster.local EOF

    3. 定义一个来引导流量通过 Egress 网关:

      $ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-nginx-through-egress-gateway spec: hosts: - my-nginx.mesh-external.svc.cluster.local gateways: - istio-egressgateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: nginx port: number: 443 weight: 100 - match: - gateways: - istio-egressgateway port: 443 route: - destination: host: my-nginx.mesh-external.svc.cluster.local port: number: 443 weight: 100 EOF

    4. 添加一个DestinationRule来执行一个简单的 TLS 连接

      $ kubectl apply -n istio-system -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-tls-for-nginx spec: host: my-nginx.mesh-external.svc.cluster.local trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE credentialName: client-credential # this must match the secret created earlier without the "-cacert" suffix sni: my-nginx.mesh-external.svc.cluster.local EOF

    5. 发送一个 HTTP 请求到http://my-nginx.mesh-external.svc.cluster.local

      $ kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})" -c sleep -- curl -sS http://my-nginx.mesh-external.svc.cluster.local <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...

    6. 检查istio-egressgatewayPod 的日志,看看有没有与我们的请求相对应的日志。如果 Istio 被部署在istio-system命名空间,打印日志的命令是:

      $ kubectl logs -l istio=egressgateway -n istio-system | grep 'my-nginx.mesh-external.svc.cluster.local' | grep HTTP

      您应该看到与下面类似的一行:

      [2018-08-19T18:20:40.096Z] "GET / HTTP/1.1" 200 - 0 612 7 5 "172.30.146.114" "curl/7.35.0" "b942b587-fac2-9756-8ec6-303561356204" "my-nginx.mesh-external.svc.cluster.local" "172.21.72.197:443"

    清理 TLS 连接的示例{#cleanup-the-TLS-origination example}

    1. 删除您创建的 Istio 配置项:

    ``` $ kubectl delete destinationrule originate-tls-for-nginx -n istio-system $ kubectl delete virtualservice direct-nginx-through-egress-gateway $ kubectl delete destinationrule egressgateway-for-nginx $ kubectl delete gateway istio-egressgateway $ kubectl delete secret client-credential-cacert -n istio-system $ kubectl delete service my-nginx -n mesh-external $ kubectl delete deployment my-nginx -n mesh-external $ kubectl delete configmap nginx-configmap -n mesh-external $ kubectl delete secret nginx-server-certs nginx-ca-certs -n mesh-external $ kubectl delete namespace mesh-external ```

    1. 删除证书和私钥:

      $ rm example.com.crt example.com.key my-nginx.mesh-external.svc.cluster.local.crt my-nginx.mesh-external.svc.cluster.local.key my-nginx.mesh-external.svc.cluster.local.csr

    2. 删除本例中生成的配置文件。

      $ rm ./nginx.conf

    与上一节类似,这一节描述了如何配置一个 Egress 网关来执行为外部服务进行 TLS 连接,只是这次使用的是一个需要双向 TLS 连接的服务。

    Egress 网关将使用 SDS 而不是文件挂载来提供客户端证书。

    对于这项任务,您可以使用您喜欢的工具来生成证书和钥匙。也可以参考下面命令:openssl.

    1. my-nginx.mesh-external.svc.cluster.local创建一个证书和私钥:

      $ openssl req -out my-nginx.mesh-external.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout my-nginx.mesh-external.svc.cluster.local.key -subj "/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization" $ openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in my-nginx.mesh-external.svc.cluster.local.csr -out my-nginx.mesh-external.svc.cluster.local.crt

    2. 生成客户端的证书和私钥:

      $ openssl req -out client.example.com.csr -newkey rsa:2048 -nodes -keyout client.example.com.key -subj "/CN=client.example.com/O=client organization" $ openssl x509 -req -sha256 -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.example.com.csr -out client.example.com.crt

    部署一个双向TLS服务器{deploy-a-mutual-TLS-server}

    为了模拟一个支持双向 TLS 连接的实际外部服务。在您的 Kubernetes 集群中部署一个NGINX服务器,但在 Istio 服务网外运行,即在没有启用 Istio Sidecar 代理注入的命名空间中运行。

    1. 创建一个命名空间来代表 Istio 网状结构之外的服务,即mesh-external。请注意,Sidecar 代理将不会被自动注入到这个命名空间的 Pod 中,因为自动注入 Sidecar 的功能没有被 上。

      $ kubectl create namespace mesh-external

    2. $ kubectl create -n mesh-external secret tls nginx-server-certs --key my-nginx.mesh-external.svc.cluster.local.key --cert my-nginx.mesh-external.svc.cluster.local.crt $ kubectl create -n mesh-external secret generic nginx-ca-certs --from-file=example.com.crt

    3. 为 NGINX 服务器创建一个配置文件:

      $ cat <<\EOF > ./nginx.conf events { } http { log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; server { listen 443 ssl; root /usr/share/nginx/html; index index.html; server_name my-nginx.mesh-external.svc.cluster.local; ssl_certificate /etc/nginx-server-certs/tls.crt; ssl_certificate_key /etc/nginx-server-certs/tls.key; ssl_client_certificate /etc/nginx-ca-certs/example.com.crt; ssl_verify_client on; # In mutual TLS, server verifies client's certificate } } EOF

    4. 创建一个 Kubernetes ConfigMap 来保存 NGINX 服务器的配置。

      $ kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf

    5. 部署 NGINX 服务器。

    1. 创建 Kubernetes Secrets来保存客户的证书。

      $ kubectl create secret -n istio-system generic client-credential --from-file=tls.key=client.example.com.key \ --from-file=tls.crt=client.example.com.crt --from-file=ca.crt=example.com.crt

      The secret must be created in the same namespace as Istio is deployed in, istio-system in this case.

      To support integration with various tools, Istio supports a few different Secret formats.

      In this example. a single generic Secret with keys tls.key, tls.crt, and ca.crt is used.

    2. my-nginx.mesh-external.svc.cluster.local创建一个 Egress Gateway,端口443,以及目标规则和虚拟服务,以引导流量通过 Egress 网关并从 Egress 网关到外部服务。

      $ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: istio-egressgateway spec: selector: istio: egressgateway servers: - port: number: 443 name: https protocol: HTTPS hosts: - my-nginx.mesh-external.svc.cluster.local tls: mode: ISTIO_MUTUAL --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: egressgateway-for-nginx spec: host: istio-egressgateway.istio-system.svc.cluster.local subsets: - name: nginx trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: ISTIO_MUTUAL sni: my-nginx.mesh-external.svc.cluster.local EOF

    3. 定义一个 VirtualService 来引导流量通过 Egress 网关:

      $ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: direct-nginx-through-egress-gateway spec: hosts: - my-nginx.mesh-external.svc.cluster.local gateways: - istio-egressgateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-system.svc.cluster.local subset: nginx port: number: 443 weight: 100 - match: - gateways: - istio-egressgateway port: 443 route: - destination: host: my-nginx.mesh-external.svc.cluster.local port: number: 443 weight: 100 EOF

    4. 添加一个 DestinationRule 来执行双向 TLS 连接

      $ kubectl apply -n istio-system -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: originate-mtls-for-nginx spec: host: my-nginx.mesh-external.svc.cluster.local trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: MUTUAL credentialName: client-credential # this must match the secret created earlier to hold client certs sni: my-nginx.mesh-external.svc.cluster.local EOF

    5. 发送一个 HTTP 请求到 http://my-nginx.mesh-external.svc.cluster.local:

      $ kubectl exec "$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})" -c sleep -- curl -sS http://my-nginx.mesh-external.svc.cluster.local <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...

    6. 检查istio-egressgatewayPod 的日志,看看有没有与我们的请求相对应的日志。如果 Istio 被部署在istio-system命名空间,打印日志的命令是:

      $ kubectl logs -l istio=egressgateway -n istio-system | grep 'my-nginx.mesh-external.svc.cluster.local' | grep HTTP

      您应该看到与下面类似的一行。

      [2018-08-19T18:20:40.096Z] "GET / HTTP/1.1" 200 - 0 612 7 5 "172.30.146.114" "curl/7.35.0" "b942b587-fac2-9756-8ec6-303561356204" "my-nginx.mesh-external.svc.cluster.local" "172.21.72.197:443"

    清理双向TLS连接的示例{cleanup-the mutual-TLS-origination-example}

    1. 移除创建的 Kubernetes 资源:

      $ kubectl delete secret nginx-server-certs nginx-ca-certs -n mesh-external $ kubectl delete secret client-credential -n istio-system $ kubectl delete configmap nginx-configmap -n mesh-external $ kubectl delete service my-nginx -n mesh-external $ kubectl delete deployment my-nginx -n mesh-external $ kubectl delete namespace mesh-external $ kubectl delete gateway istio-egressgateway $ kubectl delete virtualservice direct-nginx-through-egress-gateway $ kubectl delete destinationrule -n istio-system originate-mtls-for-nginx $ kubectl delete destinationrule egressgateway-for-nginx

    2. 删除证书和私钥:

      $ rm example.com.crt example.com.key my-nginx.mesh-external.svc.cluster.local.crt my-nginx.mesh-external.svc.cluster.local.key my-nginx.mesh-external.svc.cluster.local.csr client.example.com.crt client.example.com.csr client.example.com.key

    3. 删除本例中生成的配置文件:

      $ rm ./nginx.conf $ rm ./gateway-patch.json

    删除服务和部署。

    $ kubectl delete service sleep $ kubectl delete deployment sleep