Egress 网关 TLS 连接 发起的过程 (SDS)
TLS 连接流量 Egress的例子展示了如何配置 Istio 来执行TLS origination把流量导入至外部服务,并为通往外部服务的流量进行 TLS 连接。配置 Egress 网关的示例显示了如何配置 Istio 以引导 Egress 流量通过一个专门的 Egress 网关服务。这个例子结合了之前的两个例子描述了如何配置一个 Egress 网关,来执行把 TLS 发起的流量连接到外部服务。
TLS 所需的私钥、服务器证书和 root 证书是通过以下方式配置的Secret Discovery Service (SDS).
开始之前
按照安装指南中的说明设置 Istio。
启动sleep样例这将被用作外部调用的测试源。
如果您已经启用了自动 Sidecar 注入,请执行
$ kubectl apply -f @samples/sleep/sleep.yaml@
否则,您必须在部署”sleep”应用程序之前手动注入 Sidecar。
$ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)
注意,任何您可以
exec
和curl
的 Pod 都可以。对于macOS用户,请确认您使用的是1.1或更高版本的
openssl
。$ openssl version -a | grep OpenSSL OpenSSL 1.1.1g 2020年4月21日
如果前面的命令输出的是”1.1”或更高版本,如图所示,您的”openssl”命令应该可以按照本任务的说明正常工作。否则,请升级您的
openssl
或尝试不同的openssl
实现,例如在 Linux 机器上
使用SDS在 Egress 网关上执行 TLS 连接
本节描述了如何执行TLS 连接流量 Egress 的例子。只是这次使用了一个 Egress 网关。请注意,在这种情况下,TLS初始化将由 Egress 网关完成。是由 Egress 网关完成的,而不是前一个例子中的挎包。Egress 网关将使用 SDS 而不是文件挂载来提供客户证书。
生成 CA 及证书密钥
对于这项任务,您可以使用您喜欢的工具来生成证书和钥匙。下面的命令使用openssl.
创建一个根证书和私钥,为您的服务签署证书:
$ 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
为
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 -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 代理注入的命名空间中。
创建一个命名空间来代表 Istio 网状结构之外的服务,即
mesh-external
。请注意,Sidecar 代理将不会被自动注入到这个命名空间的 Pod 中,因为自动注入 Sidecar 的功能没有被启用 上。$ kubectl create namespace mesh-external
创建 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
为 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
创建一个 Kubernetes ConfigMap 来保存 NGINX 服务器的配置。
$ kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf
部署 NGINX 服务器:
$ kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: my-nginx namespace: mesh-external labels: run: my-nginx spec: ports: - port: 443 protocol: TCP selector: run: my-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx namespace: mesh-external spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 443 volumeMounts: - name: nginx-config mountPath: /etc/nginx readOnly: true - name: nginx-server-certs mountPath: /etc/nginx-server-certs readOnly: true - name: nginx-ca-certs mountPath: /etc/nginx-ca-certs readOnly: true volumes: - name: nginx-config configMap: name: nginx-configmap - name: nginx-server-certs secret: secretName: nginx-server-certs - name: nginx-ca-certs secret: secretName: nginx-ca-certs EOF
为 Egress 流量配置简单的 TLS 连接
创建一个 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”。为
my-nginx.mesh-external.svc.cluster.local
创建一个 Egressgateway
,端口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
定义一个
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
添加一个
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
发送一个 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> ...
检查
istio-egressgateway
Pod 的日志,看看有没有与我们的请求相对应的日志。如果 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 连接的示例
删除您创建的 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
删除证书和私钥:
$ 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
删除本例中生成的配置文件。
$ rm ./nginx.conf
通过 Egress 网关发起 双向TLS 连接
与上一节类似,这一节描述了如何配置一个 Egress 网关来执行为外部服务进行 TLS 连接,只是这次使用的是一个需要双向 TLS 连接的服务。
Egress 网关将使用 SDS 而不是文件挂载来提供客户端证书。
生成客户端和服务端的证书和钥匙
对于这项任务,您可以使用您喜欢的工具来生成证书和钥匙。也可以参考下面命令:openssl.
创建一个 root 证书和私钥,为您的服务端签署证书:
$ 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
为
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 -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
生成客户端的证书和私钥:
$ 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 -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 代理注入的命名空间中运行。
创建一个命名空间来代表 Istio 网状结构之外的服务,即
mesh-external
。请注意,Sidecar 代理将不会被自动注入到这个命名空间的 Pod 中,因为自动注入 Sidecar 的功能没有被启用 上。$ kubectl create namespace mesh-external
创建 Kubernetes Secrets来保存服务器的证书。
$ 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
为 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
创建一个 Kubernetes ConfigMap 来保存 NGINX 服务器的配置。
$ kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf
部署 NGINX 服务器。
$ kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: my-nginx namespace: mesh-external labels: run: my-nginx spec: ports: - port: 443 protocol: TCP selector: run: my-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx namespace: mesh-external spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 443 volumeMounts: - name: nginx-config mountPath: /etc/nginx readOnly: true - name: nginx-server-certs mountPath: /etc/nginx-server-certs readOnly: true - name: nginx-ca-certs mountPath: /etc/nginx-ca-certs readOnly: true volumes: - name: nginx-config configMap: name: nginx-configmap - name: nginx-server-certs secret: secretName: nginx-server-certs - name: nginx-ca-certs secret: secretName: nginx-ca-certs EOF
使用 SDS 给 Egress 流量配置双向 TSL 连接
创建 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
, andca.crt
is used.为
my-nginx.mesh-external.svc.cluster.local
创建一个 EgressGateway
,端口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
定义一个
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
添加一个
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
发送一个 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> ...
检查
istio-egressgateway
Pod 的日志,看看有没有与我们的请求相对应的日志。如果 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}
移除创建的 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
删除证书和私钥:
$ 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
删除本例中生成的配置文件:
$ rm ./nginx.conf $ rm ./gateway-patch.json
清理
删除sleep
服务和部署。
$ kubectl delete service sleep
$ kubectl delete deployment sleep