Show HN: Using eBPF to see through encryption without a proxy
259 points| tylerflint | 9 months ago |github.com
For a while now, my team and I at Qpoint.io have been grappling with the challenge of understanding what's actually happening inside the encrypted traffic leaving our production systems. Modern apps rely heavily on third-party APIs (think payment processors, data providers, etc.), but once TLS kicks in, figuring out exactly what data is being sent, identifying PII exposure, or debugging integration issues becomes incredibly difficult without resorting to complex and often brittle solutions.
Traditional approaches like forward proxies require terminating TLS (MITM), managing certificates, and often introduce performance bottlenecks or single points of failure. Network firewalls usually operate at L3/L4 and lack payload visibility. We felt there had to be a better way.
That's why we built qtap. It's a lightweight agent that uses eBPF to tap into network traffic at the kernel level. The key idea is to hook into common TLS libraries (like OpenSSL) before encryption and after decryption. This gives us deep visibility into the actual request/response payloads of HTTPS/TLS traffic without needing to terminate the connection or manage certs. Because it leverages eBPF, the performance impact is minimal compared to traditional methods.
With qtap, we can now see exactly which external services our apps are talking to, inspect the payloads for debugging or security auditing (e.g., spotting accidental PII leaks), monitor API performance/errors for third-party dependencies, and get a much clearer picture of our egress traffic patterns.
We've found this approach really powerful for improving reliability and security posture. We've packaged qtap as a Linux Binary, Docker container, and Helm chart for deployment.
This is still evolving, but we're excited about the potential of using eBPF for this kind of deep, yet non-intrusive, visibility.
We'd love to get the HN community's feedback:
Do you face similar challenges monitoring encrypted egress traffic?
What are your thoughts on using eBPF for this compared to other methods?
Any suggestions or potential use cases we haven't considered?
Happy to answer any questions!
brendangregg|9 months ago
"This is not a vulnerability: eBPF currently requires root access to do this. Also, eBPF makes this easy but does not make it possible, as debuggers, interposers/shims, and other tools can also attach to pre-encryption points, and therefore banning eBPF (as some people want to do after seeing projects like this) would not actually improve security, but it would instead _reduce_ security as it would prevent eBPF-based security solutions from being used."
tylerflint|9 months ago
On an unrelated note, your work has inspired most of my career in Solaris/Illumos/Linux systems and honestly this project likely wouldn't have happened if it wasn't for all of your books/blogs/projects to help me along the way. Thank you!
bbkane|9 months ago
tylerflint|9 months ago
We do this by scanning every version of Go that is released to find offsets in the standard library that won't change. Then when we detect a new Go process, we use an ELF scanner to find some function offsets and hook into those with uprobes. Using both of these, we have all the information we need to see Go pre-encryption content as well as attribute it to connections and processes.
lights0123|9 months ago
> The key idea is to hook into common TLS libraries (like OpenSSL) before encryption and after decryption
unknown|9 months ago
[deleted]
zxilly|9 months ago
dilyevsky|9 months ago
ebb_earl_co|9 months ago
compscidr|9 months ago
I work a bunch with vpn-like networking on Android phones and it would be cool to have a bit of info on how I might get something like working on phones. I guess its probably not your typical usecase.
Currently since the project is a VPN client, I already intercept all of the packets, I have a pcap writer and can write to files or a tcp sockets and connect wireshark to it - but it needs a bunch of complication to setup the keys so that I can see through encryption, so anything that would make that process easier would be great.
PcChip|9 months ago
I've seen that type of behavior for apps that inject ads and add affiliate marketing links
eptcyka|9 months ago
formerly_proven|9 months ago
delusional|9 months ago
There's an alternative implementation where SSLKEYLOGFILE is more "dynamic" and permits being toggled on an off during runtime, but that doesn't currently exist.
linsomniac|9 months ago
worldsavior|9 months ago
tylerflint|9 months ago
pclmulqdq|9 months ago
tylerflint|9 months ago
kristopolous|9 months ago
Anyone have any experience with it?
markasoftware|9 months ago
armitron|9 months ago
1. uprobes can be expensive and add latency (they force a context switch and copy data), especially when the hooked functions are called a lot
2. EBPF is not widely available outside of Linux, requires elevated privileges (compared to a MITM proxy that requires no privileges and works with every OS)
3. Doesn't work with JVM, Rust, any runtime that doesn't use the hooked functions
jonfriesen|9 months ago
To address your points:
1. In our testing, uprobes add a statistically insignificant amount of latency and in comparison to a MITM proxies it's nearly identical to native.
2. True, we're focused on Linux right now. I'm looking forward to exploring Microsoft's eBPF implementation and exploring how we can support the Windows ecosystem.
3. You're right that the technique we are using for OpenSSL will not work for other runtimes. That said, there are other techniques that we've implemented in our Pro offering for the JVM, Go, and NodeJS. Rust is in the works!
delusional|9 months ago
I'm always looking for a way to make sniffing traffic from inside a container easier, and if I could attach a debug sidecar with something like an eBPF based SSL pre-master key extractor (both on incoming and outgoing requests) it starts to feel a lot like having network JTAG.
jonfriesen|9 months ago
There are some important flags when spinning it up in docker: `--privileged`, `--cap-add CAP_BPF`, `--cap-add CAP_SYS_ADMIN`, and `--pid=host`. These provide access to load eBPF programs, and monitor traffic.
Many deployments use Kubernetes daemonsets where Qtap runs in a container, but monitors all of the traffic on the node. The Qpoint paid offering comes with a Control Plane that produces context specific dashboards so seeing what's happening from a specific container, or pod namespace can provide a lot of insights into your deployments.
tecleandor|9 months ago
jonfriesen|9 months ago
Severian|9 months ago
mrbluecoat|9 months ago
> Security enforcement: Allowing or denying traffic based on precise conditions
Very cool. What are your supported log sinks?
jonfriesen|9 months ago
As far as log sinks, we have stdout right now. We have been working on Fluentbit and will eventually add a bunch more. If you have a request, drop them here!
We also have a services concept which support an "event store" and "object store", where the object store handles artifacts that may contain sensitive data and don't need to be indexed for search/aggregation (this is an S3 compliant store). The event store handles all of the events from connection audit logs (these cover the ip protocol level) to individual http request/response pairs. The event store is a custom API we use and need to write some proper documentation for, stay tuned!
1vuio0pswjnm7|9 months ago
Modifying response bodies in the forward proxy is less than ideal. The proxy must wait for the full response body to be received before making modifications.
Can eBPF be any better in this regard.
hamburglar|9 months ago
0nethacker1|9 months ago
jonfriesen|9 months ago
How can we remove the impact that proxies have on connections, AND see the content without having to manage a custom certificate authority, AND not have to instrument all of our code.
dahateb|9 months ago
jonfriesen|9 months ago
Edit: Another user posted a link to https://github.com/gojue/ecapture which looks like it supports android and has some overlapping functionality.
sunbum|9 months ago
octobereleven|9 months ago
ranger_danger|9 months ago
adampk|9 months ago
tylerflint|9 months ago
You can customize config and/or integrate with existing observability pipelines, but initially you just need to turn it on for it to work. No app instrumentation required.
plicense|9 months ago
tylerflint|9 months ago
onnimonni|9 months ago
jonfriesen|9 months ago
https://www.obdev.at/products/littlesnitch/index.html
nikolayasdf123|9 months ago
jonfriesen|9 months ago
That said, the eBPF verifier has robust security guarantees and runs on every load. So arbitrary mem access for example isn't possible. Qtap runs exclusively on your nodes, so you control what it captures and where that data goes. Our paid offering provides more functionality with a Control Plane solutions that provides dashboards, alerting, and live config updates. However, all sensitive information, like captured http bodies, are uploaded to a S3 compliant bucket that you control. This could be S3, Minio, or anything else that supports the S3 API. We never see this information.
It's intentionally designed for deployment within your infra and abides by the security policies you set within your org.
mberning|9 months ago
CMCDragonkai|9 months ago
jonfriesen|9 months ago
otterley|9 months ago
jakedata|9 months ago