Early last year, ngrok started a project to revamp its firewall system to better protect its infrastructure and, by extension, its customers. In this blog post, I'd like to share a few high-level goals we set when designing this new system called Firewall Next-Generation (or FWNG), the technical bits that make it work, and introduce the Firewall Toolkit that we built along the way, and opened the source to the community.
Global in nature
Our previous firewall system had a data center/regional view of traffic - it operated independently in each region. It collected network telemetry via application metrics within an individual region, generated iptables rules, and applied them on each host. If a network attack targeted hosts across multiple ngrok regions, each region would need to gather, analyze, and mitigate the attack independently.
While not having to coordinate between regions/data centers did have the significant advantage of reduced complexity, ngrok's ongoing global network initiatives made it critical to have a global view of traffic. As one of our engineers put it, "Now that customer traffic is globally distributed, the DDOS's are too." As a simple example, with ngrok's global network, if a geographically distributed botnet were to send traffic to one of ngrok's "global" domains, each node in the botnet would send traffic to its geographically closest ngrok region.
FWNG's high-level architecture
Instead of aggregating and analyzing telemetry locally within an ngrok region, FWNG aggregates telemetry in our controlplane. The various telemetry sources in a region send data to a local-to-the-region sink, which is then replicated to the controlplane.
Once in the controlplane, data is aggregated, enriched, analyzed, and used to generate traffic policies. Traffic policies are communicated back to all ngrok nodes in all regions. In this way, all ngrok infrastructure has a consistent view of the currently enforced traffic policies, regardless of region. The major advantage of this system is that an attack that originates in one region results in traffic policies that affect all regions. If malicious traffic were directed to other ngrok regions, they would be ready to enforce the same policies that were generated from a different region.
Another significant benefit is that it allows us to track traffic sources across regions. As an example, network-level rate limits designed to protect ngrok's infrastructure from excessive traffic are aggregated across all regions - meaning that a single traffic source is allowed a specific rate of traffic into ngrok's infrastructure, whether that's to a single region, or distributed across many regions.
Telemetry sources and traffic policies
Let's get more specific regarding telemetry sources, traffic policies, and how those are enforced.
Currently, FWNG ingests network telemetry from two major sources - network flows from the NetObserv eBPF Agent and our own application's metrics.
NetObserv eBPF Agent
The Netobserv eBPF Agent is a part of the NetObserv Operator, maintained by the awesome folks at Red Hat. It uses eBPF programs attached to network interfaces to collect network flows and does it very efficiently.
The efficiency at which the NetObserv eBPF Agent can collect and export network flows allows low-level network monitoring without any special or dedicated hardware or access to physical routers in the network. We run the Agent on each ingress node in our system with minimal performance overhead alongside our other applications.
The agent exports network flows in protobuf-formatted messages, which we collect and process in the controlplane.
In addition to network flows, we collect application-emitted metrics. Application metrics can be very useful in enriching existing network telemetry and helping to detect traffic flows that would be difficult (or impossible) to parse with low-level network flow data. For example, viewing how many connections or how much data is destined for an ngrok tunnel owned by a particular account or how much traffic from a specific source IP was destined for an online ngrok tunnel.
Today, all policies are enforced via nftables rules on our ingress nodes. Each ingress node in the dataplane runs a small Go service that polls the controlplane for the current set of traffic policies, then updates nftables rules, tables, and sets, to enforce that policy. To make that process more ergonomic and programmable, we developed the Firewall Toolkit.
Firewall Toolkit builds on top of Google's nftables Go library and allows you to ergonomically and programmatically generate nftables rules, modify tables and sets, and set up data sources that will keep those rules, tables, and sets up to date with the data source - all via communication with the netlink socket in pure Go.
Using the library, creating an nftables rule that blocks incoming connections from IPs in a set destined to ports in a set can be as simple as:
Mason Johnson is a Senior Software Engineer at ngrok where he works on their network edge team. His most recent work includes expanding and modernizing ngrok’s internal firewall systems as well as supporting their on-premise product. Mason holds a Bachelor of Science degree in Computer Science from the University of Wyoming.