Tracing Encrypted Traffic (TLS)

Kubeshark can detect TLS traffic and display encrypted traffic (TLS). In most cases, Kubeshark can also show the unencrypted payload.

Detecting Encrypted Traffic

Before attempting to display encrypted traffic in clear text, Kubeshark detects and marks TLS TCP packets, identifying various TLS-related messages (e.g., ClientHello and ServerHello).

TLS traffic is marked with an open lock icon to the left of the entry. You can use the helper tls as a KFL query to filter and view all TLS traffic.

TLS Traffic Example

TLS 1.x Items

At the very least, Kubeshark will display the ClientHello and ServerHello TLS messages and related information.

TLS 1.x Items

TLS TCP Packets

In addition to the TLS messages mentioned above, Kubeshark shows all encrypted TCP packets within Kubernetes contexts, including information such as namespaces, pod and service names, IPs, ports, and more.

Displaying Unencrypted Payloads

Kubeshark can display the unencrypted payload in clear text by utilizing eBPF. It hooks into entry and exit points in specific functions within the OpenSSL library, Go’s crypto/tls package and Google’s BoringSSL. If Kubeshark detects TLS termination via one of these libraries, the entire message is reassembled into a request-response pair, similar to HTTP, allowing you to view encrypted traffic in clear text.

eBPF TLS

TL;DR - Use of eBPF

Kubeshark traces both kernel-space and user-space functions using eBPF (Extended Berkeley Packet Filter). eBPF is an in-kernel virtual machine that runs programs passed from user space. First introduced in Linux kernel version 4.4, it has since matured significantly.

OpenSSL

Kubeshark attaches uprobes to SSL_read and SSL_write, capturing unencrypted incoming responses and outgoing encrypted requests in any TLS/SSL connection.

Languages like Python, Java, PHP, Ruby, and Node.js use the OpenSSL library for encryption/decryption tasks, so any program or service using TLS for encrypted communication falls into this category.

Go

Go’s encryption process is a bit more complex than OpenSSL, but the underlying principle is similar.

Go has two ABIs: ABI0 and ABIInternal, and Kubeshark supports both amd64 and arm64, which translates into a significant number of offsets to handle.

We probe crypto/tls.(*Conn).Read and crypto/tls.(*Conn).Write, much like OpenSSL’s SSL_read and SSL_write. Additionally, we disassemble targeted Go binaries using Capstone to locate the offsets of ret instructions, as uretprobe does not work properly in Go due to its unique ABI.

Finally, we track the Goroutine ID using offsets identified in the DWARF table.

Kernel

We use kprobes on certain kernel tracepoints to perform tasks such as address resolution (learning the IP and port for both source and destination) and matching request-response pairs.

While these methods may sound complex, Kubeshark’s TLS sniffer has minimal performance impact due to the efficient eBPF in-kernel virtual machine and our carefully written C code. Furthermore, the Linux kernel limits the number of instructions allowed for probing purposes, ensuring there is no significant slowdown or crash risk.

TLS Capture in Action