验证网格内部是否已启用mTLS通信

mTLS加密通信是服务网格ASM提供的一项重要的基础能力,您无需对应用进行改造,只需要给应用Pod注入Sidecar代理就会默认启用mTLS。但由于mTLS是无感启用的,无法直观判断流量是否真正进行了加密,本文将介绍和演示如何确认网格内部是否启用了mTLS通信。

背景信息

TLS(Transport Layer Security)是一个广泛应用于互联网的安全协议,旨在为通信两端提供安全的数据传输通道。常见的TLS通信通常只执行单向的身份认证,比如在浏览器中通过HTTPS访问一个网站时,只需要网站服务器提供网站自身的证书,向客户证明自己是这个网站的合法所有者,并不需要客户提供证书证明客户的身份。

普通的TLS通信仅执行单向验证,服务器需要向客户端提供证书来建立安全的连接;而在mTLS(Mutual Transport Layer Security)中,客户端也必须向服务器提供证书,双方需要相互验证对方的身份。如此一来就可以保证只有被授权的客户端才能访问指定服务端。

服务网格中的授权机制依赖于mTLS协议来验证客户端身份,这种互相认证的机制能够确保在服务网格中的每个服务调用都来自受信任的客户端,从而为微服务通信提供了一层额外的安全保护。

以下将以sleep访问httpbin应用为例,演示通过间接和直接的方式确认网格内部是否已启用mTLS通信。

前提条件

步骤一:部署sleep应用

  1. 通过kubectl连接到ASM实例添加的Kubernetes集群,使用以下内容创建sleep.yaml。

    展开查看YAML详细内容

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: sleep
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: sleep
      labels:
        app: sleep
        service: sleep
    spec:
      ports:
      - port: 80
        name: http
      selector:
        app: sleep
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sleep
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sleep
      template:
        metadata:
          labels:
            app: sleep
        spec:
          terminationGracePeriodSeconds: 0
          serviceAccountName: sleep
          containers:
          - name: sleep
            image: registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2
            command: ["/bin/sleep", "infinity"]
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - mountPath: /etc/sleep/tls
              name: secret-volume
          volumes:
          - name: secret-volume
            secret:
              secretName: sleep-secret
              optional: true
    ---
  2. 执行以下命令,部署测试客户端应用sleep。

    kubectl apply -f sleep.yaml

步骤二:验证是否已启用mTLS

通过Header标识间接确认是否启用mTLS

X-FORWARDED-CLIENT-CERT(XFCC)是一个特殊的Proxy Header,用来标识请求从客户端到服务端的途中经过的部分或全部的客户端或代理的证书信息。具体信息,请参见HTTP header manipulation

在sleep应用中使用curl命令访问httpbin应用时,httpbin应用收到的请求会携带XFCC header,标识这个请求由sleep应用发出,通过这个Header可以间接确定两端通信中启用了mTLS。

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择可观测管理中心 > 可观测配置

  3. 全局配置中的日志设置中找到X-FORWARDED-CLIENT-CERT,选中后点击最下方的提交

    image

  4. 通过kubectl连接到ASM实例添加的Kubernetes集群,执行以下命令在sleep应用Pod中访问httpbin服务。

    kubectl exec <sleep pod name> -- curl httpbin:8000 -I
  5. 执行以下命令查看httpbin应用Pod的日志。

    kubectl logs <httpbin pod> -c istio-proxy | tail -1

    预期输出:

    {"bytes_received":"0","bytes_sent":"0","downstream_local_address":"192.168.34.76:80","downstream_remote_address":"192.168.34.74:45042","duration":"2","istio_policy_status":"-","method":"HEAD","path":"/","protocol":"HTTP/1.1","request_id":"7bd9862b-69d8-4d14-bc62-4520b2b45370","requested_server_name":"outbound_.8000_._.httpbin.default.svc.cluster.local","response_code":"200","response_flags":"-","route_name":"default","start_time":"2024-06-11T11:24:04.163Z","trace_id":"-","upstream_cluster":"inbound|80||","upstream_host":"192.168.34.76:80","upstream_local_address":"127.0.0.6:54963","upstream_service_time":"2","upstream_response_time":"2","upstream_transport_failure_reason":"-","user_agent":"curl/8.1.2","x_forwarded_for":"-","authority_for":"httpbin:8000","x_forwarded_client_cert":"By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=583116d4dfd7b548400031f5c8685ee4f8ca99f217aca2af8634022362988114;Subject="";URI=spiffe://cluster.local/ns/default/sa/sleep"}

    从上述输出中的XFCC header信息可以看到客户端身份标识是sleep应用。

通过tcpdump抓包直接确认是否启用mTLS

本节在sleep应用Pod中抓取sleep Sidecar发送给httpbin Sidecar的数据包。抓包有两种方式可以实现,您可以根据实际情况选择。

说明

抓包前请先删除已有的httpbin Pod使其重启,确保Sidecar之间的长连接被强制断开。

通过ASMPacketInspector实现抓包(ASM实例版本1.21以上)

  1. 通过kubectl连接到ASM实例,使用以下内容创建ASMPacketInspector.yaml。

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: ASMPacketInspector
    metadata:
      name: test
    spec:
      pod:
        clusterId: ${ACK Cluster ID}
        namespace: default
        name: ${sleep pod name}
      tcpDumpParams: '-i any port 80'
      duration: 60s
      fileName: sleep.pcap
  2. 执行以下命令部署ASMPacketInspector资源。

    kubectl apply -f ASMPacketInspector.yaml
  3. ASMPacketInspector资源部署后,ASM会自动在sleep pod中抓取80端口的数据包(httpbin pod暴露的服务端口),抓包时长为60s。在此期间,通过kubectl连接到ASM实例添加的Kubernetes集群,执行以下命令。

    kubectl exec -it <sleep pod name> -c sleep --  sh -c 'for i in $(seq 1 30); do curl httpbin:8000 -I ; echo "request $i done"; done'

    此命令会自动从sleep pod向httpbin服务发送30次请求。

  4. 通过kubectl连接到ASM实例,执行以下命令查看抓包结果。

    kubectl get ASMPacketInspector test -o yaml

    预期结果:

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: ASMPacketInspector
    metadata:
      ******
    spec:
      ******
    status:
      completedAt: null
      conditions:
      - time: "2024-06-12T08:15:33Z"
        type: Inspecting
      - message: 'inspecting job status: Running'
        time: "2024-06-12T08:15:43Z"
        type: Inspecting
      - message: 'inspecting job status: Running'
        time: "2024-06-12T08:15:53Z"
        type: Inspecting
      - message: 'inspecting job status: Running'
        time: "2024-06-12T08:16:03Z"
        type: Inspecting
      - message: 'inspecting job status: Running'
        time: "2024-06-12T08:16:13Z"
        type: Inspecting
      - message: 'inspecting job status: Running'
        time: "2024-06-12T08:16:23Z"
        type: Inspecting
      filePath: /tmp/sleep.pcap
      phase: Inspecting
      runningOnNode: *******
      startAt: "2024-06-12T08:15:43Z"
      taskId: inspector-zumnmwdc

    status部分的runningOnNode可以看到抓包运行的node,filePath代表输出文件的路径。登录到指定节点将文件下载到本地。

直接在sleep应用Pod所在节点上抓包

  1. 通过kubectl连接到ASM实例添加的Kubernetes集群,执行以下命令查看sleep应用运行在哪个Node上。

    kubectl  get pod -o wide 

    预期输出:

    NAME                       READY   STATUS    RESTARTS   AGE     IP           NODE                       NOMINATED NODE   READINESS GATES
    httpbin-6c8f47d9b9-stq72   2/2     Running   0          33m     172.16.*.*   cn-***.172.16.*.*   <none>           <none>
    sleep-84f9785988-ft9rm     2/2     Running   0          3h56m   172.16.*.*   cn-***.172.16.*.*   <none>           <none>
  2. 登录到目标节点。操作步骤详情,请参见通过密码或密钥认证登录Linux实例

    1. 执行以下命令查看sleep应用对应的容器CONTAINER ID

      sudo crictl ps |grep <Pod名称关键字>

      预期输出:

      CONTAINER           IMAGE               CREATED             STATE                      
      a1a214d2*****       35d28df4*****       2 days ago          Running
    2. 使用CONTAINER ID参数,执行以下命令查看容器PID。

      sudo crictl inspect  a1a214d2***** |grep -i PID

      预期输出:

          "pid": 2309838,    # 目标容器的PID进程号。
                  "pid": 1
                  "type": "pid"
    3. 执行以下抓包命令。

      sudo nsenter -t <容器PID> tcpdump -i any port 80 -w /tmp/test.pcap

      将命令执行后生成的test.pcap文件下载到本地。

确保本地安装了Wireshark,使用wireshark打开上述下载到本地pcap格式文件,选择对应端口协议为TLS,可以看到如下结果。

lQLPJyD1OwZMe9nNAyLNCiSwkwADizrf70MGVI7OabFdAA_2596_802

通过对应的TLS报文,可以确认Sidecar之间通信使用了mTLS进行了加密。

说明

这里只能看到Client Hello和Server Hello,之后就是Application Data报文了。这里之所以没有直接看到TLS的证书信息,是因为TLSv1.3中对后续的证书交换消息都进行了加密,所以无法直接在WireShark中查看到证书的明文信息,这是正常现象。

相关文档

您可以通过PeerAuthentication资源来配置服务之间的mTLS策略。请参见对等身份认证(Peer Authentication)