利用服务网格实现全链路mTLS(二):通过出口网关访问外部mTLS服务

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 阿里云服务网格(Service Mesh,简称ASM)提供了一个全托管式的服务网格平台,兼容Istio开源服务网格,简化服务治理,包括流量管理、服务间通信安全及网格可观测性。ASM出口网关统一管理网格内的出口流量,实现全链路加密通信与精细访问控制。本文介绍如何配置ASM出口网关以管理出口流量并发起mTLS通信,涉及配置ServiceEntry、创建出口网关、设置虚拟服务及目标规则等步骤,最终实现安全可控的mTLS服务访问。

阿里云服务网格Service Mesh,简称ASM)提供一个全托管式的服务网格平台,兼容社区Istio开源服务网格,用于简化服务的治理,包括服务调用之间的流量路由与拆分管理、服务间通信的认证安全以及网格可观测性能力,从而极大地减轻开发与运维的工作负担。

ASM出口网关作为网格内流量的统一出口,可以执行TLS/mTLS发起,进而实现全链路的加密通信。同时,出口网关也可以执行丰富的安全策略,实现更加精细的访问控制。在服务网格中,出口网关是实现出口流量管理的最佳方案。本文将介绍如何使用ASM出口网关管理出口流量并发起mTLS通信。

前提条件

步骤一:部署测试应用sleep

参考如何部署httpbin应用_服务网格(ASM)-阿里云帮助中心中的“相关操作”章节,部署sleep应用。

使用ACK集群kubeconfig,通过以下命令测试访问之前部署在另一套环境中的httpbin服务:

kubectl exec deployment/sleep -- curl --header "host:test.com" ${ASM网关ip}/status/418

步骤二:开启REGISTRY_ONLY并创建ServiceEntry

sidecar支持配置配置外部访问策略为REGISTRY_ONLY,开启之后pod只能访问通过ServiceEntry注册的服务。您可以根据需要选择是否开启此项功能。具体开启步骤,请参考配置统一的出口网关提升网格内流量的安全性_服务网格(ASM)-阿里云帮助中心中的步骤二。开启之后,访问未经注册的服务将会返回502 Bad Gateway

为test.com配置ServiceEntry,使用ASM的kubeconfig创建如下YAML资源:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: test-com
  namespace: default
spec:
  endpoints:
    - address: ${ASM网关IP}
  hosts:
    - test.com
  location: MESH_EXTERNAL
  ports:
    - name: http
      number: 80
      protocol: HTTP
    - name: https
      number: 443
      protocol: HTTPS
  resolution: STATIC

配置上述YAML后,即可正常从sleep pod中访问httpbin服务。

步骤三:创建ASM出口网关,并让HTTP协议请求经过出口网关

创建出口网关,配置HTTP协议和80端口,并且打开了双向TLS认证开关(这个开关打开之后,网格中其他工作负载向网关发送流量时会自动使用mTLS,该mTLS的证书由网格统一管理)。具体操作,请参见创建ASM出口网关统一Kubernetes集群的访问出口_服务网格(ASM)-阿里云帮助中心

使用ASM kubeconfig创建网关规则,YAML如下:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: egress-gateway
  namespace: default
spec:
  selector:
    istio: egressgateway
  servers:
  - hosts:
    - '*'
    port:
      name: http
      number: 80
      protocol: HTTPS
    tls:
      mode: ISTIO_MUTUAL

这个网关规则中声明了:出口网关在80端口上开启mTLS监听,并且使用网格统一提供的证书。

使用ASM kubeconfig创建如下虚拟服务,YAML如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: egressgateway-vs
spec:
  hosts:
  - test.com
  gateways:
  - egress-gateway  # 上一步创建的网关规则名称。
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - egress-gateway
      port: 80
    route:
    - destination:
        host: test.com
        port:
          number: 80
      weight: 100

这个虚拟服务的意思是:将sidecar中test.com的流量发送给出口网关。并且将出口网关收到的test.com的流量发送给真正的test.com ServiceEntry。

创建完成之后,可以在sleep pod中访问test.com,使用ACK的kubeconfig,命令如下所示:

kubectl exec deployment/sleep -it -- curl --header "host:test.com" ${ASM网关IP}/status/418

此时查看出口网关日志,可以看到类似输出:

kubectl -n istio-system logs ${出口网关pod名称}| tail -1
{"authority_for":"test.com","bytes_received":"0","bytes_sent":"135","downstream_local_address":"192.168.36.32:80","downstream_remote_address":"192.168.36.29:58146","duration":"8","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"9f7b5475-6e45-4700-a85a-e00835b6b6c0","requested_server_name":"outbound_.80_._.istio-egressgateway.istio-system.svc.cluster.local","response_code":"418","response_flags":"-","route_name":"-","start_time":"2024-07-29T03:05:58.421Z","trace_id":"-","upstream_cluster":"outbound|80||test.com","upstream_host":"${ASM网关IP}:80","upstream_local_address":"192.168.36.32:52838","upstream_response_time":"7","upstream_service_time":"7","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"192.168.36.29"}

通过上述日志可以确认该服务经过了ASM出口网关。

当前的请求链路是:sleep pod --> istio-egressgateway --> istio-ingressgateway --> httpbin。其中:

  • sleep pod --> istio-egressgateway这段是mTLS流量。
  • istio-egressgateway --> istio-ingressgateway这段是明文流量。
  • istio-ingressgateway --> httpbin这段是mTLS流量。

显然,两个网关之间交互通过明文是不安全的。由于服务端网关已经支持了mTLS,因此只需要客户端出口网关支持发起mTLS请求即可。下面的章节将介绍如何使用出口网关发起mTLS请求。

步骤四:在出口网关中将sleep pod中发出的test.com的HTTP请求升级为mTLS流量

首先修改虚拟服务定义,使用ASM kubeconfig应用如下YAML文件:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: egressgateway-vs
spec:
  hosts:
  - test.com
  gateways:
  - egress-gateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - egress-gateway
      port: 80
    route:
    - destination:
        host: test.com
        port:
          number: 443  # 只修改了这一行
      weight: 100

这里的修改只是将网关收到的test.com的流量,发送给test.com ServiceEntry的443端口,修改之前是发送给80端口。

光修改VirtualService是不够的,还是要告知出口网关在将请求发送给443端口时,使用mTLS。

首先需要导入mTLS中用到的证书(此处使用了使用上篇文档中生成的证书):使用ASM证书管理导入mTLS证书,请确保此处导入的证书名称为test.client,如何使用ASM证书管理_服务网格(ASM)-阿里云帮助中心

您也可以使用kubectl直接创建secret完成证书导入。使用数据面集群的kubeconfig,执行如下命令即可:

kubectl create -n istio-system secret generic test.client \
  --from-file=tls.key=client.key.pem \
  --from-file=tls.crt=clientcert.pem \
  --from-file=ca.crt=cacert.pem

使用ASM的kubeconfig,创建如下目标规则:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: originate-mtls-for-test-com
spec:
  host: test.com
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    portLevelSettings:
    - port:
        number: 443
      tls:
        mode: MUTUAL
        credentialName: test.client
        sni: test.com

配置完成之后,再次测试访问,使用ACK的kubeconfig执行以下命令:

kubectl exec deployment/sleep -it -- curl --header "host:test.com" ${ASM网关IP}/status/418
RBAC: access denied%

可以看到请求被拒绝了。这是因为我们复用了上篇文章中的客户端证书,上篇文章中配置了:禁止test.client访问status/418路径。

使用ACK的kubeconfig执行以下命令:

kubectl exec deployment/sleep -it -- curl --header "host:test.com" ${ASM网关IP}/status/200 -I
HTTP/1.1 200 OK
server: envoy
date: Mon, 29 Jul 2024 03:33:50 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 5

可以看到访问正常。

使用ACK集群的kubeconfig查看出口网关访问日志:

kubectl -n istio-system logs ${出口网关pod名称}| tail -1
{"authority_for":"test.com","bytes_received":"0","bytes_sent":"19","downstream_local_address":"192.168.36.32:80","downstream_remote_address":"192.168.36.29:58146","duration":"3","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"82394ec4-cf13-45cb-ae4c-cb1873fbccda","requested_server_name":"outbound_.80_._.istio-egressgateway.istio-system.svc.cluster.local","response_code":"403","response_flags":"-","route_name":"-","start_time":"2024-07-29T03:34:36.647Z","trace_id":"-","upstream_cluster":"outbound|443||test.com","upstream_host":"${ASM网关IP}:443","upstream_local_address":"192.168.36.32:42214","upstream_response_time":"2","upstream_service_time":"2","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"192.168.36.29"}

可以看到这条请求访问了入口网关的443端口,这个端口上只提供mTLS服务。

步骤五:后续配置

当前的请求路径是:sleep pod --> istio-egressgateway --> istio-ingressgateway --> httpbin。sleep pod发起的请求是HTTP请求,然而经过sidecar和出口网关之后,全链路均使用了mTLS加密。mTLS加密是执行客户端身份认证的基础,在这条链路中,您可以在两个地方配置授权策略,限制客户端行为:

  1. 出口网关上配置授权策略:可以限制集群内哪些服务可以访问test.com服务。示例配置如下:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  labels:
    gateway: egressgateway
  name: test
  namespace: istio-system
spec:
  action: DENY
  rules:
    - from:
        - source:
            principals:
              - cluster.local/ns/default/sa/sleep
      to:
        - operation:
            hosts:
              - test.com
            paths:
              - /headers
  selector:
    matchLabels:
      istio: egressgateway

该配置限制了sleep pod不可以通过出口网关访问test.com/headers路径。

  1. 在入口网关上配置授权策略:可以限制直接访问入口网关的客户端身份,本文中的出口网关就是一个直接访问入口网关的客户端。从上面的演示中已经可以看出:由于之前在入口网关上配置的授权策略,当前出口网关无法访问/status/418路径。
目录
相关文章
|
7天前
|
安全 5G 网络性能优化
|
1月前
|
监控 负载均衡 安全
微服务(五)-服务网关zuul(一)
微服务(五)-服务网关zuul(一)
|
17天前
|
前端开发 Java API
vertx学习总结5之回调函数及其限制,如网关/边缘服务示例所示未来和承诺——链接异步操作的简单模型响应式扩展——一个更强大的模型,特别适合组合异步事件流Kotlin协程
本文是Vert.x学习系列的第五部分,讨论了回调函数的限制、Future和Promise在异步操作中的应用、响应式扩展以及Kotlin协程,并通过示例代码展示了如何在Vert.x中使用这些异步编程模式。
38 5
vertx学习总结5之回调函数及其限制,如网关/边缘服务示例所示未来和承诺——链接异步操作的简单模型响应式扩展——一个更强大的模型,特别适合组合异步事件流Kotlin协程
|
5天前
|
弹性计算 网络协议 网络安全
内网DNS解析&VPN网关联动实现云上访问云下资源
内网DNS解析&VPN网关联动实现云上访问云下资源
|
2月前
|
负载均衡 应用服务中间件 nginx
搭建域名访问环境二(负载均衡到网关)
这篇文章讲述了如何配置Nginx实现域名访问环境,通过负载均衡将请求从Nginx反向代理到服务网关,并提供了详细的配置步骤和测试验证方法。
搭建域名访问环境二(负载均衡到网关)
|
1月前
|
测试技术 微服务
微服务(八)-服务网关zuul(四)
微服务(八)-服务网关zuul(四)
|
1月前
|
监控 前端开发 Java
微服务(七)-服务网关zuul(三)
微服务(七)-服务网关zuul(三)
|
1月前
|
负载均衡 前端开发 安全
微服务(六)-服务网关zuul(二)
微服务(六)-服务网关zuul(二)
|
2月前
|
Java API 微服务
服务网关Gateway
该博客文章详细介绍了Spring Cloud Gateway的使用方法和概念。文章首先阐述了API网关在微服务架构中的重要性,解释了客户端直接与微服务通信可能带来的问题。接着,文章通过具体的示例代码,展示了如何在Spring Cloud Gateway中添加依赖、编写路由规则,并对路由规则中的基本概念如Route、Predicate和Filter进行了详细解释。最后,文章还提供了路由规则的测试方法。
服务网关Gateway
|
2月前
|
SQL Java
访问者模式问题之在ASM中,实现一个访问者来删除指定的类属性,如何解决
访问者模式问题之在ASM中,实现一个访问者来删除指定的类属性,如何解决