Egress 网关的 TLS 发起过程

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

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

本文使用 Gateway API 配置内部网格(东西)流量。 使用 Gateway API 配置内部网格流量目前是一个还在开发的实验性特性, 也是 Istio 特有的功能。在使用 Gateway API 指令之前,请确保:

  1. 安装 实验版本 的 Gateway API CRD:

    1. $ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v1.1.0" | kubectl apply -f -
  2. 安装 Istio 时,通过将 PILOT_ENABLE_ALPHA_GATEWAY_API 环境变量设置为 true 使 Istio 读取 Alpha 版本的 Gateway API 资源:

    1. $ istioctl install --set values.pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true --set profile=minimal -y

开始之前

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

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

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

    Zip

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

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

    Zip

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

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

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

    1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -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/v1alpha3
    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 sleep -- 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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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/v1alpha3
    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 sleep -- 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/v1alpha3
    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/v1alpha3
    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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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/v1alpha3
  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. 验证凭证是否已提供给 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=sleep -o jsonpath={.items..metadata.name})" -c sleep -- 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

清除

删除 sleep 的 Service 和 Deployment:

Zip

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