Egress 网关的 TLS 发起过程

为出口流量发起 TLS 连接 示例中演示了如何配置 Istio 以对外部服务流量实施 TLS origination。 配置 Egress 网关示例中演示了如何配置 Istio 来通过专门的 Egress 网关服务引导出口流量。 本示例兼容以上两者,描述如何配置 Egress 网关,为外部服务流量发起 TLS 连接。

Istio 支持 Kubernetes Gateway API, 并计划将其作为未来流量管理的默认 API。 以下说明指导您在网格中配置流量管理时如何选择使用 Gateway API 或 Istio 配置 API。 请按照您的首选项遵循 Gateway APIIstio APIs 页签中的指示说明。

请注意,Kubernetes Gateway API CRD 不会默认安装在大多数 Kubernetes 集群上, 因此请确保在使用 Gateway API 之前已安装好这些 CRD:

  1. $ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  2. { kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml; }

开始之前

  • 遵照安装指南中的指令,安装 Istio。

  • 启动 curl 样本应用,作为外部请求的测试源。

    若已开启自动 Sidecar 注入,执行

    Zip

    1. $ kubectl apply -f @samples/curl/curl.yaml@

    否则,必须在部署 curl 应用之前手动注入 Sidecar:

    Zip

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

    注意每一个可以执行 execcurl 操作的 Pod,都需要注入。

  • 创建一个 shell 变量,来保存向外部服务发送请求的源 Pod 的名称。 若使用 curl 样例,运行:

    1. $ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
  • 对于 macOS 用户,确认您使用的是 openssl 版本 1.1 或更高版本:

    1. $ openssl version -a | grep OpenSSL
    2. OpenSSL 1.1.1g 21 Apr 2020

    如果前面的命令输出的是版本 1.1 或更高版本,如图所示,则您的 openssl 命令应该正确执行此任务中的指示。否则,升级您的 openssl 或尝试 openssl 的不同实现,像在 Linux 机器上一样。

  • 开启 Envoy 的访问日志, 如果尚未启用。例如,使用 istioctl

    1. $ istioctl install <flags-you-used-to-install-Istio> --set meshConfig.accessLogFile=/dev/stdout
  • 如果您不使用 Gateway API 指令, 请确保部署 Istio Egress 网关

通过 Egress 网关发起 TLS 连接

本节描述如何使用 Egress 网关发起与示例为出口流量发起 TLS 连接中一样的 TLS。注意,这种情况下,TLS 的发起过程由 Egress 网关完成,而不是像之前示例演示的那样由 Sidecar 完成。

  1. edition.cnn.com 定义一个 ServiceEntry

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: networking.istio.io/v1
    3. kind: ServiceEntry
    4. metadata:
    5. name: cnn
    6. spec:
    7. hosts:
    8. - edition.cnn.com
    9. ports:
    10. - number: 80
    11. name: http
    12. protocol: HTTP
    13. - number: 443
    14. name: https
    15. protocol: HTTPS
    16. resolution: DNS
    17. EOF
  2. 发送一个请求至 http://edition.cnn.com/politics, 验证 ServiceEntry 已被正确应用。

    1. $ kubectl exec -it $SOURCE_POD -c curl -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
    2. HTTP/1.1 301 Moved Permanently
    3. ...
    4. location: https://edition.cnn.com/politics
    5. ...
    6. command terminated with exit code 35

    如果在输出中看到 301 Moved Permanently,说明 ServiceEntry 配置正确。

  3. edition.cnn.com 创建一个 Egress Gateway,端口 443,以及一个 Sidecar 请求的目标规则,Sidecar 请求被直接导向 Egress 网关。

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 80
  12. name: https-port-for-tls-origination
  13. protocol: HTTPS
  14. hosts:
  15. - edition.cnn.com
  16. tls:
  17. mode: ISTIO_MUTUAL
  18. ---
  19. apiVersion: networking.istio.io/v1
  20. kind: DestinationRule
  21. metadata:
  22. name: egressgateway-for-cnn
  23. spec:
  24. host: istio-egressgateway.istio-system.svc.cluster.local
  25. subsets:
  26. - name: cnn
  27. trafficPolicy:
  28. loadBalancer:
  29. simple: ROUND_ROBIN
  30. portLevelSettings:
  31. - port:
  32. number: 80
  33. tls:
  34. mode: ISTIO_MUTUAL
  35. sni: edition.cnn.com
  36. EOF
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: gateway.networking.k8s.io/v1
  3. kind: Gateway
  4. metadata:
  5. name: cnn-egress-gateway
  6. annotations:
  7. networking.istio.io/service-type: ClusterIP
  8. spec:
  9. gatewayClassName: istio
  10. listeners:
  11. - name: https-listener-for-tls-origination
  12. hostname: edition.cnn.com
  13. port: 80
  14. protocol: HTTPS
  15. tls:
  16. mode: Terminate
  17. options:
  18. gateway.istio.io/tls-terminate-mode: ISTIO_MUTUAL
  19. allowedRoutes:
  20. namespaces:
  21. from: Same
  22. ---
  23. apiVersion: networking.istio.io/v1
  24. kind: DestinationRule
  25. metadata:
  26. name: egressgateway-for-cnn
  27. spec:
  28. host: cnn-egress-gateway-istio.default.svc.cluster.local
  29. trafficPolicy:
  30. loadBalancer:
  31. simple: ROUND_ROBIN
  32. portLevelSettings:
  33. - port:
  34. number: 80
  35. tls:
  36. mode: ISTIO_MUTUAL
  37. sni: edition.cnn.com
  38. EOF
  1. 配置路由规则以引导流量通过 Egress 网关:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: VirtualService
  4. metadata:
  5. name: direct-cnn-through-egress-gateway
  6. spec:
  7. hosts:
  8. - edition.cnn.com
  9. gateways:
  10. - istio-egressgateway
  11. - mesh
  12. http:
  13. - match:
  14. - gateways:
  15. - mesh
  16. port: 80
  17. route:
  18. - destination:
  19. host: istio-egressgateway.istio-system.svc.cluster.local
  20. subset: cnn
  21. port:
  22. number: 80
  23. weight: 100
  24. - match:
  25. - gateways:
  26. - istio-egressgateway
  27. port: 80
  28. route:
  29. - destination:
  30. host: edition.cnn.com
  31. port:
  32. number: 443
  33. weight: 100
  34. EOF
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: gateway.networking.k8s.io/v1
  3. kind: HTTPRoute
  4. metadata:
  5. name: direct-cnn-to-egress-gateway
  6. spec:
  7. parentRefs:
  8. - kind: ServiceEntry
  9. group: networking.istio.io
  10. name: cnn
  11. rules:
  12. - backendRefs:
  13. - name: cnn-egress-gateway-istio
  14. port: 80
  15. ---
  16. apiVersion: gateway.networking.k8s.io/v1
  17. kind: HTTPRoute
  18. metadata:
  19. name: forward-cnn-from-egress-gateway
  20. spec:
  21. parentRefs:
  22. - name: cnn-egress-gateway
  23. hostnames:
  24. - edition.cnn.com
  25. rules:
  26. - backendRefs:
  27. - kind: Hostname
  28. group: networking.istio.io
  29. name: edition.cnn.com
  30. port: 443
  31. EOF
  1. 定义一个 DestinationRule 来为 edition.cnn.com 的请求执行 TLS 发起:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: networking.istio.io/v1
    3. kind: DestinationRule
    4. metadata:
    5. name: originate-tls-for-edition-cnn-com
    6. spec:
    7. host: edition.cnn.com
    8. trafficPolicy:
    9. loadBalancer:
    10. simple: ROUND_ROBIN
    11. portLevelSettings:
    12. - port:
    13. number: 443
    14. tls:
    15. mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
    16. EOF
  2. 发送一个 HTTP 请求至 http://edition.cnn.com/politics

    1. $ kubectl exec -it $SOURCE_POD -c curl -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
    2. HTTP/1.1 200 OK
    3. ...

    输出将与在示例为出口流量发起 TLS 连接中显示的一样,发起 TLS 连接后,不再显示 301 Moved Permanently 消息。

  3. 检查 Egress 网关代理的日志。

如果 Istio 部署在 istio-system 命名空间中,则打印日志的命令为:

  1. $ kubectl logs -l istio=egressgateway -c istio-proxy -n istio-system | tail

您应该看到一行类似于以下的内容:

  1. [2020-06-30T16:17:56.763Z] "GET /politics HTTP/2" 200 - "-" "-" 0 1295938 529 89 "10.244.0.171" "curl/7.64.0" "cf76518d-3209-9ab7-a1d0-e6002728ef5b" "edition.cnn.com" "151.101.129.67:443" outbound|443||edition.cnn.com 10.244.0.170:54280 10.244.0.170:8080 10.244.0.171:35628 - -

使用 Istio 生成的 Pod 标签访问 Egress 网关对应的日志:

  1. $ kubectl logs -l gateway.networking.k8s.io/gateway-name=cnn-egress-gateway -c istio-proxy | tail

您应该看到一行类似于以下的内容:

  1. [2024-03-14T18:37:01.451Z] "GET /politics HTTP/1.1" 200 - via_upstream - "-" 0 2484998 59 37 "172.30.239.26" "curl/7.87.0-DEV" "b80c8732-8b10-4916-9a73-c3e1c848ed1e" "edition.cnn.com" "151.101.131.5:443" outbound|443||edition.cnn.com 172.30.239.33:51270 172.30.239.33:80 172.30.239.26:35192 edition.cnn.com default.forward-cnn-from-egress-gateway.0

清除 TLS 启动实例

删除创建的 Istio 配置项:

  1. $ kubectl delete gw istio-egressgateway
  2. $ kubectl delete serviceentry cnn
  3. $ kubectl delete virtualservice direct-cnn-through-egress-gateway
  4. $ kubectl delete destinationrule originate-tls-for-edition-cnn-com
  5. $ kubectl delete destinationrule egressgateway-for-cnn
  1. $ kubectl delete serviceentry cnn
  2. $ kubectl delete gtw cnn-egress-gateway
  3. $ kubectl delete httproute direct-cnn-to-egress-gateway
  4. $ kubectl delete httproute forward-cnn-from-egress-gateway
  5. $ kubectl delete destinationrule egressgateway-for-cnn
  6. $ kubectl delete destinationrule originate-tls-for-edition-cnn-com

通过 Egress 网关发起双向 TLS 连接

与前一章节类似,本章节描述如何配置一个 Egress 网关,为外部服务发起 TLS 连接, 只是这次服务要求双向 TLS。

本示例要求更高的参与性,首先需要:

  1. 生成客户端和服务器证书
  2. 部署一个支持双向 TLS 的外部服务
  3. 使用所需的证书重新部署 Egress 网关

然后才可以配置出口流量流经 Egress 网关,Egress 网关将发起 TLS 连接。

生成客户端和服务器的证书与密钥

对于此任务,您可以使用自己喜欢的工具来生成证书和密钥。以下命令使用 openssl

  1. 为您的服务签名证书创建根证书和私钥:

    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 创建证书和私钥:

    1. $ 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"
    2. $ 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

    或者,如果您想要为目标启用 SAN 验证,您可以将 SubjectAltNames 添加到证书中。例如:

    1. $ cat > san.conf <<EOF
    2. [req]
    3. distinguished_name = req_distinguished_name
    4. req_extensions = v3_req
    5. x509_extensions = v3_req
    6. prompt = no
    7. [req_distinguished_name]
    8. countryName = US
    9. [v3_req]
    10. keyUsage = critical, digitalSignature, keyEncipherment
    11. extendedKeyUsage = serverAuth, clientAuth
    12. basicConstraints = critical, CA:FALSE
    13. subjectAltName = critical, @alt_names
    14. [alt_names]
    15. DNS = my-nginx.mesh-external.svc.cluster.local
    16. EOF
    17. $
    18. $ openssl req -out my-nginx.mesh-external.svc.cluster.local.csr -newkey rsa:4096 -nodes -keyout my-nginx.mesh-external.svc.cluster.local.key -subj "/CN=my-nginx.mesh-external.svc.cluster.local/O=some organization" -config san.conf
    19. $ 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 -extfile san.conf -extensions v3_req
  3. 生成客户端证书和私钥:

    1. $ openssl req -out client.example.com.csr -newkey rsa:2048 -nodes -keyout client.example.com.key -subj "/CN=client.example.com/O=client organization"
    2. $ 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 服务器

为了模拟一个真实的支持双向 TLS 协议的外部服务,在 Kubernetes 集群中部署一个 NGINX 服务器, 该服务器运行在 Istio 服务网格之外,譬如:运行在一个没有开启 Istio Sidecar proxy 注入的命名空间中。

  1. 创建一个命名空间,表示 Istio 网格之外的服务,mesh-external。 注意在这个命名空间中,Sidecar 自动注入是没有开启的, 不会在 Pod 中自动注入 Sidecar 代理。

    1. $ kubectl create namespace mesh-external
  2. 创建 Kubernetes Secret, 保存服务器和 CA 的证书。

    1. $ 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
    2. $ kubectl create -n mesh-external secret generic nginx-ca-certs --from-file=example.com.crt
  3. 生成 NGINX 服务器的配置文件:

    1. $ cat <<\EOF > ./nginx.conf
    2. events {
    3. }
    4. http {
    5. log_format main '$remote_addr - $remote_user [$time_local] $status '
    6. '"$request" $body_bytes_sent "$http_referer" '
    7. '"$http_user_agent" "$http_x_forwarded_for"';
    8. access_log /var/log/nginx/access.log main;
    9. error_log /var/log/nginx/error.log;
    10. server {
    11. listen 443 ssl;
    12. root /usr/share/nginx/html;
    13. index index.html;
    14. server_name my-nginx.mesh-external.svc.cluster.local;
    15. ssl_certificate /etc/nginx-server-certs/tls.crt;
    16. ssl_certificate_key /etc/nginx-server-certs/tls.key;
    17. ssl_client_certificate /etc/nginx-ca-certs/example.com.crt;
    18. ssl_verify_client on;
    19. }
    20. }
    21. EOF
  4. 生成 Kubernetes ConfigMap 保存 NGINX 服务器的配置文件:

    1. $ kubectl create configmap nginx-configmap -n mesh-external --from-file=nginx.conf=./nginx.conf
  5. 部署 NGINX 服务器:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: v1
    3. kind: Service
    4. metadata:
    5. name: my-nginx
    6. namespace: mesh-external
    7. labels:
    8. run: my-nginx
    9. spec:
    10. ports:
    11. - port: 443
    12. protocol: TCP
    13. selector:
    14. run: my-nginx
    15. ---
    16. apiVersion: apps/v1
    17. kind: Deployment
    18. metadata:
    19. name: my-nginx
    20. namespace: mesh-external
    21. spec:
    22. selector:
    23. matchLabels:
    24. run: my-nginx
    25. replicas: 1
    26. template:
    27. metadata:
    28. labels:
    29. run: my-nginx
    30. spec:
    31. containers:
    32. - name: my-nginx
    33. image: nginx
    34. ports:
    35. - containerPort: 443
    36. volumeMounts:
    37. - name: nginx-config
    38. mountPath: /etc/nginx
    39. readOnly: true
    40. - name: nginx-server-certs
    41. mountPath: /etc/nginx-server-certs
    42. readOnly: true
    43. - name: nginx-ca-certs
    44. mountPath: /etc/nginx-ca-certs
    45. readOnly: true
    46. volumes:
    47. - name: nginx-config
    48. configMap:
    49. name: nginx-configmap
    50. - name: nginx-server-certs
    51. secret:
    52. secretName: nginx-server-certs
    53. - name: nginx-ca-certs
    54. secret:
    55. secretName: nginx-ca-certs
    56. EOF
  6. nginx.example.com 定义一个 ServiceEntry 和一个 VirtualService, 指示 Istio 引导目标为 nginx.example.com 的流量流向 NGINX 服务器:

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: networking.istio.io/v1
    3. kind: ServiceEntry
    4. metadata:
    5. name: nginx
    6. spec:
    7. hosts:
    8. - nginx.example.com
    9. ports:
    10. - number: 80
    11. name: http
    12. protocol: HTTP
    13. - number: 443
    14. name: https
    15. protocol: HTTPS
    16. resolution: DNS
    17. endpoints:
    18. - address: my-nginx.mesh-external.svc.cluster.local
    19. ports:
    20. https: 443
    21. ---
    22. apiVersion: networking.istio.io/v1
    23. kind: VirtualService
    24. metadata:
    25. name: nginx
    26. spec:
    27. hosts:
    28. - nginx.example.com
    29. tls:
    30. - match:
    31. - port: 443
    32. sni_hosts:
    33. - nginx.example.com
    34. route:
    35. - destination:
    36. host: nginx.example.com
    37. port:
    38. number: 443
    39. weight: 100
    40. EOF

为出口流量配置双向 TLS

  1. 在部署 Egress 网关的同一命名空间中创建一个 Kubernetes Secret, 以保存客户端的证书:
  1. $ kubectl create secret -n istio-system generic client-credential --from-file=tls.key=client.example.com.key \
  2. --from-file=tls.crt=client.example.com.crt --from-file=ca.crt=example.com.crt

为了支持与各种工具的集成,Istio 支持几种不同的 Secret 格式。 在此示例中,使用具有关键字 tls.keytls.crtca.crt 的通用 Secret。

如有必要,凭据可以包含一个证书吊销列表 (CRL), 使用 ca.crl 作为键名。如果是这样,请在上述示例中添加另一个参数来提供 CRL:--from-file=ca.crl=/some/path/to/your-crl.pem

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

为了支持与各种工具的集成,Istio 支持几种不同的 Secret 格式。 在此示例中,使用具有关键字 tls.keytls.crtca.crt 的通用 Secret。

如有必要,凭据可以包含一个证书吊销列表 (CRL), 使用 ca.crl 作为键名。如果是这样,请在上述示例中添加另一个参数来提供 CRL:--from-file=ca.crl=/some/path/to/your-crl.pem

  1. my-nginx.mesh-external.svc.cluster.local、端口 443 创建 Egress Gateway, 并为将定向到 Egress 网关的 Sidecar 请求创建目标规则:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 443
  12. name: https
  13. protocol: HTTPS
  14. hosts:
  15. - my-nginx.mesh-external.svc.cluster.local
  16. tls:
  17. mode: ISTIO_MUTUAL
  18. ---
  19. apiVersion: networking.istio.io/v1
  20. kind: DestinationRule
  21. metadata:
  22. name: egressgateway-for-nginx
  23. spec:
  24. host: istio-egressgateway.istio-system.svc.cluster.local
  25. subsets:
  26. - name: nginx
  27. trafficPolicy:
  28. loadBalancer:
  29. simple: ROUND_ROBIN
  30. portLevelSettings:
  31. - port:
  32. number: 443
  33. tls:
  34. mode: ISTIO_MUTUAL
  35. sni: my-nginx.mesh-external.svc.cluster.local
  36. EOF
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: gateway.networking.k8s.io/v1
  3. kind: Gateway
  4. metadata:
  5. name: nginx-egressgateway
  6. annotations:
  7. networking.istio.io/service-type: ClusterIP
  8. spec:
  9. gatewayClassName: istio
  10. listeners:
  11. - name: https
  12. hostname: my-nginx.mesh-external.svc.cluster.local
  13. port: 443
  14. protocol: HTTPS
  15. tls:
  16. mode: Terminate
  17. options:
  18. gateway.istio.io/tls-terminate-mode: ISTIO_MUTUAL
  19. allowedRoutes:
  20. namespaces:
  21. from: Same
  22. ---
  23. apiVersion: rbac.authorization.k8s.io/v1
  24. kind: Role
  25. metadata:
  26. name: nginx-egressgateway-istio-sds
  27. rules:
  28. - apiGroups:
  29. - ""
  30. resources:
  31. - secrets
  32. verbs:
  33. - get
  34. - watch
  35. - list
  36. ---
  37. apiVersion: rbac.authorization.k8s.io/v1
  38. kind: RoleBinding
  39. metadata:
  40. name: nginx-egressgateway-istio-sds
  41. roleRef:
  42. apiGroup: rbac.authorization.k8s.io
  43. kind: Role
  44. name: nginx-egressgateway-istio-sds
  45. subjects:
  46. - kind: ServiceAccount
  47. name: nginx-egressgateway-istio
  48. ---
  49. apiVersion: networking.istio.io/v1
  50. kind: DestinationRule
  51. metadata:
  52. name: egressgateway-for-nginx
  53. spec:
  54. host: nginx-egressgateway-istio.default.svc.cluster.local
  55. trafficPolicy:
  56. loadBalancer:
  57. simple: ROUND_ROBIN
  58. portLevelSettings:
  59. - port:
  60. number: 443
  61. tls:
  62. mode: ISTIO_MUTUAL
  63. sni: my-nginx.mesh-external.svc.cluster.local
  64. EOF
  1. 配置路由规则以引导流量通过 Egress 网关:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: VirtualService
  4. metadata:
  5. name: direct-nginx-through-egress-gateway
  6. spec:
  7. hosts:
  8. - my-nginx.mesh-external.svc.cluster.local
  9. gateways:
  10. - istio-egressgateway
  11. - mesh
  12. http:
  13. - match:
  14. - gateways:
  15. - mesh
  16. port: 80
  17. route:
  18. - destination:
  19. host: istio-egressgateway.istio-system.svc.cluster.local
  20. subset: nginx
  21. port:
  22. number: 443
  23. weight: 100
  24. - match:
  25. - gateways:
  26. - istio-egressgateway
  27. port: 443
  28. route:
  29. - destination:
  30. host: my-nginx.mesh-external.svc.cluster.local
  31. port:
  32. number: 443
  33. weight: 100
  34. EOF
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: VirtualService
  4. metadata:
  5. name: direct-nginx-to-egress-gateway
  6. spec:
  7. hosts:
  8. - my-nginx.mesh-external.svc.cluster.local
  9. gateways:
  10. - mesh
  11. http:
  12. - match:
  13. - port: 80
  14. route:
  15. - destination:
  16. host: nginx-egressgateway-istio.default.svc.cluster.local
  17. port:
  18. number: 443
  19. ---
  20. apiVersion: gateway.networking.k8s.io/v1
  21. kind: HTTPRoute
  22. metadata:
  23. name: forward-nginx-from-egress-gateway
  24. spec:
  25. parentRefs:
  26. - name: nginx-egressgateway
  27. hostnames:
  28. - my-nginx.mesh-external.svc.cluster.local
  29. rules:
  30. - backendRefs:
  31. - name: my-nginx
  32. namespace: mesh-external
  33. port: 443
  34. ---
  35. apiVersion: gateway.networking.k8s.io/v1beta1
  36. kind: ReferenceGrant
  37. metadata:
  38. name: my-nginx-reference-grant
  39. namespace: mesh-external
  40. spec:
  41. from:
  42. - group: gateway.networking.k8s.io
  43. kind: HTTPRoute
  44. namespace: default
  45. to:
  46. - group: ""
  47. kind: Service
  48. name: my-nginx
  49. EOF

TODO:弄清楚为什么使用 HTTPRoute 而不是上面不起作用的 VirtualService。 它完全忽略 HTTPRoute 并尝试传递到目标服务,但超时。 与上面的 VirtualService 唯一的区别是生成的 VirtualService 包含注解:internal.istio.io/route-semantics": "gateway"

  1. 添加 DestinationRule 来执行双向 TLS 发起:
  1. $ kubectl apply -n istio-system -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: DestinationRule
  4. metadata:
  5. name: originate-mtls-for-nginx
  6. spec:
  7. host: my-nginx.mesh-external.svc.cluster.local
  8. trafficPolicy:
  9. loadBalancer:
  10. simple: ROUND_ROBIN
  11. portLevelSettings:
  12. - port:
  13. number: 443
  14. tls:
  15. mode: MUTUAL
  16. credentialName: client-credential # 这必须与之前创建的用于保存客户端证书的 Secret 相匹配
  17. sni: my-nginx.mesh-external.svc.cluster.local
  18. # subjectAltNames: # 如果证书是随着上一节中指定的 SAN 生成的,则可以被启用
  19. # - my-nginx.mesh-external.svc.cluster.local
  20. EOF
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: DestinationRule
  4. metadata:
  5. name: originate-mtls-for-nginx
  6. spec:
  7. host: my-nginx.mesh-external.svc.cluster.local
  8. trafficPolicy:
  9. loadBalancer:
  10. simple: ROUND_ROBIN
  11. portLevelSettings:
  12. - port:
  13. number: 443
  14. tls:
  15. mode: MUTUAL
  16. credentialName: client-credential # 这必须与之前创建的用于保存客户端证书的 Secret 相匹配
  17. sni: my-nginx.mesh-external.svc.cluster.local
  18. # subjectAltNames: # 如果证书是随着上一节中指定的 SAN 生成的,则可以被启用
  19. # - my-nginx.mesh-external.svc.cluster.local
  20. EOF

Istio 默认启用了 auto_sniauto_san_validation。 这意味着,只要您的 DestinationRule 中没有显式设置 sni, 新上游连接的传输套接字 SNI 将根据下游 HTTP 主机/授权标头进行设置。 如果在 sni 未设置时 DestinationRule 中没有设置 subjectAltNames, 则 auto_san_validation 将启动,并且新上游连接的上游出示的证书将根据下游 HTTP 主机/授权标头自动验证。

  1. 验证凭证是否已提供给 Egress 网关并且处于活动状态:
  1. $ istioctl -n istio-system proxy-config secret deploy/istio-egressgateway | grep client-credential
  2. kubernetes://client-credential Cert Chain ACTIVE true 1 2024-06-04T12:46:28Z 2023-06-05T12:46:28Z
  3. kubernetes://client-credential-cacert Cert Chain ACTIVE true 16491643791048004260 2024-06-04T12:46:28Z 2023-06-05T12:46:28Z
  1. $ istioctl proxy-config secret deploy/nginx-egressgateway-istio | grep client-credential
  2. kubernetes://client-credential Cert Chain ACTIVE true 1 2024-06-04T12:46:28Z 2023-06-05T12:46:28Z
  3. kubernetes://client-credential-cacert Cert Chain ACTIVE true 16491643791048004260 2024-06-04T12:46:28Z 2023-06-05T12:46:28Z
  1. 发送一个 HTTP 请求到 http://my-nginx.mesh-external.svc.cluster.local

    1. $ kubectl exec "$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})" -c curl -- curl -sS http://my-nginx.mesh-external.svc.cluster.local
    2. <!DOCTYPE html>
    3. <html>
    4. <head>
    5. <title>Welcome to nginx!</title>
    6. ...
  2. 检查 Egress 网关代理的日志:

If Istio is deployed in the istio-system namespace, the command to print the log is:

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

You should see a line similar to the following:

  1. [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"

使用 Istio 生成的 Pod 标签访问 Egress 网关对应的日志:

  1. $ kubectl logs -l gateway.networking.k8s.io/gateway-name=nginx-egressgateway | grep 'my-nginx.mesh-external.svc.cluster.local' | grep HTTP

您应该看到一行类似于以下的内容:

  1. [2024-04-08T20:08:18.451Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 615 5 5 "172.30.239.41" "curl/7.87.0-DEV" "86e54df0-6dc3-46b3-a8b8-139474c32a4d" "my-nginx.mesh-external.svc.cluster.local" "172.30.239.57:443" outbound|443||my-nginx.mesh-external.svc.cluster.local 172.30.239.53:48530 172.30.239.53:443 172.30.239.41:53694 my-nginx.mesh-external.svc.cluster.local default.forward-nginx-from-egress-gateway.0

清除双向 TLS 连接示例

  1. 删除 NGINX 双向 TLS 服务器资源:

    1. $ kubectl delete secret nginx-server-certs nginx-ca-certs -n mesh-external
    2. $ kubectl delete configmap nginx-configmap -n mesh-external
    3. $ kubectl delete service my-nginx -n mesh-external
    4. $ kubectl delete deployment my-nginx -n mesh-external
    5. $ kubectl delete namespace mesh-external
  2. 删除网关配置资源:

  1. $ kubectl delete secret client-credential -n istio-system
  2. $ kubectl delete gw istio-egressgateway
  3. $ kubectl delete virtualservice direct-nginx-through-egress-gateway
  4. $ kubectl delete destinationrule -n istio-system originate-mtls-for-nginx
  5. $ kubectl delete destinationrule egressgateway-for-nginx
  1. $ kubectl delete secret client-credential
  2. $ kubectl delete gtw nginx-egressgateway
  3. $ kubectl delete role nginx-egressgateway-istio-sds
  4. $ kubectl delete rolebinding nginx-egressgateway-istio-sds
  5. $ kubectl delete virtualservice direct-nginx-to-egress-gateway
  6. $ kubectl delete httproute forward-nginx-from-egress-gateway
  7. $ kubectl delete destinationrule originate-mtls-for-nginx
  8. $ kubectl delete destinationrule egressgateway-for-nginx
  9. $ kubectl delete referencegrant my-nginx-reference-grant -n mesh-external
  1. 删除证书和私钥:

    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 client.example.com.crt client.example.com.csr client.example.com.key
  2. 删除生成并应用于示例中的配置文件

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

清除

删除 curl 的 Service 和 Deployment:

Zip

  1. $ kubectl delete -f @samples/curl/curl.yaml@