Skip to content

Implement trusted proxies config#38471

Merged
sgress454 merged 13 commits intomainfrom
sgress454/trusted-proxies
Jan 20, 2026
Merged

Implement trusted proxies config#38471
sgress454 merged 13 commits intomainfrom
sgress454/trusted-proxies

Conversation

@sgress454
Copy link
Copy Markdown
Contributor

@sgress454 sgress454 commented Jan 19, 2026

Details

Adds a new FLEET_SERVER_TRUSTED_PROXIES config, allowing more fine-grained control over how the client IP is determined for requests. Uses the realclientip-go library as the engine for parsing headers and using rules to determine the IP.

Checklist for submitter

If some of the following don't apply, delete the relevant line.

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    See Changes files for more information.

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features
    • Introduced FLEET_SERVER_TRUSTED_PROXIES configuration option to specify trusted proxy IPs and hosts. The server now supports flexible client IP detection strategies that respect your proxy configuration, with support for multiple formats including single IP header names, hop counts, and IP address ranges, adapting to various infrastructure setups and deployment scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@sgress454 sgress454 requested a review from a team as a code owner January 19, 2026 05:57
Comment thread server/platform/endpointer/clientip.go
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 19, 2026

Codecov Report

❌ Patch coverage is 87.23404% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.99%. Comparing base (a394596) to head (ff7b2a9).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
server/platform/endpointer/clientip.go 88.23% 2 Missing and 2 partials ⚠️
server/service/handler.go 77.77% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #38471      +/-   ##
==========================================
+ Coverage   65.97%   65.99%   +0.01%     
==========================================
  Files        2408     2409       +1     
  Lines      192369   192464      +95     
  Branches     8501     8501              
==========================================
+ Hits       126925   127017      +92     
- Misses      53891    53893       +2     
- Partials    11553    11554       +1     
Flag Coverage Δ
backend 67.83% <87.23%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 19, 2026

@sgress454: I'll review the changes in this PR for implementing the trusted proxies configuration.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sgress454
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 19, 2026

Walkthrough

The changes introduce a configurable client IP extraction strategy for the fleet server. A new FLEET_SERVER_TRUSTED_PROXIES configuration option is added to ServerConfig. A pluggable ClientIPStrategy interface is implemented, supporting multiple extraction modes (legacy, none, single IP header, hop count, IP ranges). The service handler middleware is updated to use this strategy instead of hard-coded IP extraction. An external dependency (realclientip-go) is added to support the implementation.

Changes

Cohort / File(s) Summary
Configuration
changes/add-trusted-proxies-config, server/config/config.go
Added new configuration option FLEET_SERVER_TRUSTED_PROXIES. New TrustedProxies field (string) with YAML tag trusted_proxies added to ServerConfig struct. Configuration loading updated to populate this field from config.
Client IP Strategy Implementation
server/platform/endpointer/clientip.go
New file introducing ClientIPStrategy interface with method ClientIP(headers http.Header, remoteAddr string) string. Implements NewClientIPStrategy(trustedProxies string) constructor that parses configuration and returns appropriate strategy: legacy (empty), none, single-header, numeric hop count, or comma-separated IP ranges. All strategies chain to RemoteAddr fallback. Includes known single-IP header names and legacy strategy for backward compatibility.
Client IP Strategy Tests
server/platform/endpointer/clientip_test.go
Comprehensive test coverage for ClientIPStrategy including: construction variants with empty, "none", known header names, numeric hop counts, IP ranges, and invalid inputs; legacy behavior verification; header selection prioritization; hop count selection; trusted IP range filtering; and fallback to RemoteAddr. Helper function makeHeaders included.
Service Handler Integration
server/service/handler.go
Replaced hard-coded publicIP middleware function with new publicIPMiddleware(strategy ClientIPStrategy) that accepts a strategy parameter. Handler initialization creates strategy from config.Server.TrustedProxies with panic on invalid configuration. Middleware uses strategy to extract client IP and attach to request context.
Dependencies
go.mod
Added indirect dependency github.com/realclientip/realclientip-go v1.0.0.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as HTTP Handler
    participant Middleware as publicIPMiddleware
    participant Strategy as ClientIPStrategy
    participant Context as Request Context

    Client->>Handler: HTTP Request
    Handler->>Middleware: Forward Request
    Middleware->>Strategy: ClientIP(headers, remoteAddr)
    
    alt trustedProxies = "" (Legacy)
        Strategy->>Strategy: Check True-Client-IP Header
        Strategy->>Strategy: Check X-Real-IP Header
        Strategy->>Strategy: Check X-Forwarded-For Header
        Strategy->>Strategy: Fallback to RemoteAddr
    else trustedProxies = "none"
        Strategy->>Strategy: Use RemoteAddr only
    else trustedProxies = Known Header (e.g., CF-Connecting-IP)
        Strategy->>Strategy: Extract from Header
        Strategy->>Strategy: Fallback to RemoteAddr
    else trustedProxies = Hop Count (e.g., "2")
        Strategy->>Strategy: Parse X-Forwarded-For
        Strategy->>Strategy: Select rightmost N IPs
        Strategy->>Strategy: Fallback to RemoteAddr
    else trustedProxies = IP Ranges (e.g., 10.0.0.0/8)
        Strategy->>Strategy: Parse IP Ranges
        Strategy->>Strategy: Find first non-trusted IP
        Strategy->>Strategy: Fallback to RemoteAddr
    end
    
    Strategy-->>Middleware: Return extracted IP
    Middleware->>Context: Attach IP to ctx
    Middleware-->>Handler: Continue Request
    Handler-->>Client: Response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing a new trusted proxies configuration option for the fleet server.
Description check ✅ Passed The description covers the main feature details and includes checked items for changes file and testing, though several optional sections were appropriately removed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sgress454/trusted-proxies

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@server/config/config.go`:
- Around line 1179-1180: Update the help text passed to man.addConfigString for
the "server.trusted_proxies" config to explicitly list the header names the
implementation accepts (e.g., "X-Forwarded-For, Forwarded, X-Real-IP,
True-Client-IP") instead of implying arbitrary header names are allowed; ensure
the wording in the man.addConfigString call matches the actual allowed headers
in the parsing logic so operators aren't misled and include the accepted header
list and examples along with the existing hop-count and CIDR options.

Comment thread server/config/config.go
Copy link
Copy Markdown
Contributor

@iansltx iansltx left a comment

Choose a reason for hiding this comment

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

Hopping into a meeting but I've reviewed everything except the first ~200 lines of tests.

Comment thread server/platform/endpointer/clientip.go Outdated

// singleIPHeaderNames are header names that contain a single IP address,
// typically set by CDNs or reverse proxies.
var singleIPHeaderNames = map[string]bool{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIRC we usually do map[string]struct{} for items like this?

Comment thread server/platform/endpointer/clientip.go Outdated
Comment thread server/platform/endpointer/clientip.go
Comment thread server/platform/endpointer/clientip_test.go
Comment thread server/platform/endpointer/clientip_test.go
Copy link
Copy Markdown
Contributor

@iansltx iansltx left a comment

Choose a reason for hiding this comment

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

Unreviewed is down to first 120 lines of the test. Will finish after this call.

Comment thread server/platform/endpointer/clientip_test.go Outdated
Comment thread server/platform/endpointer/clientip_test.go Outdated
@sgress454
Copy link
Copy Markdown
Contributor Author

Addressed feedback!

Copy link
Copy Markdown
Member

@lucasmrod lucasmrod left a comment

Choose a reason for hiding this comment

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

LGTM!

Left some questions.

Comment thread server/platform/endpointer/clientip.go Outdated
Comment thread server/platform/endpointer/clientip.go Outdated
Comment thread server/platform/endpointer/clientip_test.go Outdated
Comment thread server/service/handler.go
Comment on lines +144 to +150
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := ipStrategy.ClientIP(r.Header, r.RemoteAddr)
if ip != "" {
r.RemoteAddr = ip
}
handler.ServeHTTP(w, r.WithContext(publicip.NewContext(r.Context(), ip)))
})
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Putting this inline to avoid having to declare an interface solely for the purpose of sending strategy as a param to a "create the IP extraction middleware" utility function that gets called once when the server starts.

@sgress454 sgress454 merged commit 393531b into main Jan 20, 2026
48 checks passed
@sgress454 sgress454 deleted the sgress454/trusted-proxies branch January 20, 2026 04:13
sgress454 added a commit that referenced this pull request Jan 23, 2026
Adds documentation for the new config setting added in
#38471.

Adding to 4.8.0 (with callout that this works in 4.80.1) on guidance
from @rachaelshaw.

cc: @iansltx if you want to double-check my math on the examples 😆
@sgress454
Copy link
Copy Markdown
Contributor Author

To test:

The general pattern is to start the fleet server with FLEET_SERVER_TRUSTED_PROXIES=<some value> and then run a cURL command to attempt to log in using various headers, and view the activity log to see what IP address is reported for the login. The login itself doesn't need to be successful so you can use fake creds. For example, start the server with:

FLEET_SERVER_TRUSTED_PROXIES=2 fdm up --dev_license --dev

and hit the login API with:

curl -k -X POST "https://localhost:8080/api/v1/fleet/login" -H "X-Forwarded-For: 192.168.99.1,1.1.1.1"  -H "Content-Type: application/json" -d '{"email":"hi@example.com","password":"pineapple"}'

You should get an authn failed message and in the activity feed see:
image
because using 2 as the FLEET_SERVER_TRUSTED_PROXIES value means "take the second value from the right of the x-forwarded-for header, if any".

For the actual tests to do, you can refer to the automated tests for reference, as well as the trusted proxies config.

@georgekarrv georgekarrv mentioned this pull request Feb 6, 2026
@georgekarrv
Copy link
Copy Markdown
Member

#39483

georgekarrv pushed a commit that referenced this pull request Feb 6, 2026
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #

Adds a new `FLEET_SERVER_TRUSTED_PROXIES` config, allowing more
fine-grained control over how the client IP is determined for requests.
Uses the
[realclientip-go](https://github.com/realclientip/realclientip-go)
library as the engine for parsing headers and using rules to determine
the IP.

If some of the following don't apply, delete the relevant line.

- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [X] Added/updated automated tests
- [X] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

* **New Features**
* Introduced FLEET_SERVER_TRUSTED_PROXIES configuration option to
specify trusted proxy IPs and hosts. The server now supports flexible
client IP detection strategies that respect your proxy configuration,
with support for multiple formats including single IP header names, hop
counts, and IP address ranges, adapting to various infrastructure setups
and deployment scenarios.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

4 participants