Skip to content

Add proxy.protocol.accepted.ip.range config to guard PROXY protocol data by peer IP#668

Open
Hritwik Singhai (devhritwik) wants to merge 2 commits intomasterfrom
ip-routing-v3-v4
Open

Add proxy.protocol.accepted.ip.range config to guard PROXY protocol data by peer IP#668
Hritwik Singhai (devhritwik) wants to merge 2 commits intomasterfrom
ip-routing-v3-v4

Conversation

@devhritwik
Copy link
Member

During v3/v4 migration on GCP and Azure, both load balancer (v3, no PROXY protocol) and Envoy (v4, with PROXY protocol) connections coexist. Without this guard, an attacker can send a fake PROXY header through the v3 LB to spoof their IP and bypass IP filtering.

This adds a new config proxy.protocol.accepted.ip.range (CIDR notation) that tells ProxyCustomizer to only trust PROXY protocol data from peers whose raw TCP IP falls within the range. Connections from outside the range get wrapped with a RawPeerRequest that overrides getRemoteAddr() back to the raw TCP peer IP using Jetty 12's ConnectionMetaData.Wrapper, effectively undoing the ProxyEndPoint's address override.

Companion change to ce-kafka PR #28385.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a per-listener guard for Jetty PROXY protocol handling in rest-utils to prevent client IP spoofing during v3/v4 migration scenarios where both non-PROXY and PROXY-capable frontends coexist.

Changes:

  • Add proxy.protocol.accepted.ip.range config and wiring to only trust PROXY data from raw TCP peers within a configured CIDR.
  • Implement CidrRange CIDR parsing/containment utility and unit tests.
  • Update ProxyCustomizer to ignore PROXY-derived addresses for untrusted peers by wrapping requests with ConnectionMetaData.Wrapper, plus add E2E coverage in ProxyProtocolTest.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
rest-utils-ip-filtering-context.md Adds detailed design/context documentation for the new peer-IP guard behavior.
core/src/main/java/io/confluent/rest/RestConfig.java Defines the new proxy.protocol.accepted.ip.range config and documentation.
core/src/main/java/io/confluent/rest/ApplicationServer.java Reads/parses the new config per listener and passes it into ProxyCustomizer.
core/src/main/java/io/confluent/rest/customizer/ProxyCustomizer.java Adds accepted-range enforcement and RawPeerRequest wrapper to restore raw socket addresses.
core/src/main/java/io/confluent/rest/customizer/CidrRange.java Adds CIDR parsing and containment checks.
core/src/test/java/io/confluent/rest/customizer/CidrRangeTest.java Adds unit tests for CIDR parsing and containment edge cases.
core/src/test/java/io/confluent/rest/customizer/ProxyCustomizerTest.java Adds unit tests for accepted-range behavior (in-range, out-of-range, and non-PROXY endpoints).
core/src/test/java/io/confluent/rest/ProxyProtocolTest.java Adds E2E tests validating PROXY header is ignored/used depending on peer IP range.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ata by peer IP

During v3/v4 migration on GCP and Azure, both load balancer (v3, no PROXY
protocol) and Envoy (v4, with PROXY protocol) connections coexist. Without
this guard, an attacker can send a fake PROXY header through the v3 LB to
spoof their IP and bypass IP filtering.

This adds a new config `proxy.protocol.accepted.ip.range` (CIDR notation)
that tells ProxyCustomizer to only trust PROXY protocol data from peers
whose raw TCP IP falls within the range. Connections from outside the range
get wrapped with a RawPeerRequest that overrides getRemoteAddr() back to
the raw TCP peer IP using Jetty 12's ConnectionMetaData.Wrapper, effectively
undoing the ProxyEndPoint's address override.

Companion change to ce-kafka PR #28385.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ProxyCustomizer: fail closed when peer address cannot be evaluated
  (non-InetSocketAddress or null InetAddress) instead of trusting PROXY data
- CidrRange: use Guava InetAddresses.forString() instead of InetAddress.getByName()
  to reject hostnames and avoid DNS resolution during config parsing
- CidrRange: trim address and prefix components before parsing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@@ -0,0 +1,115 @@
/*
* Copyright 2025 Confluent Inc.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants