Skip to content

Conversation

@abh1sar
Copy link
Collaborator

@abh1sar abh1sar commented Oct 16, 2025

Description

This PR fixes a bug due to which forwarded IPs behind a proxy won't be logged in management.log, api.log and access.log.

  1. Access log : addForwardingCustomiser() updates request's remoteAddr to the forwarded client's IP
    But ACSRequestLog.log() was looking at getHttpChannel().getEndPoint().getRemoteAddress(), which still returns the proxy's address

  2. AddForwardinfCustomizer would only look at the first header in proxy.header.names. If the user is sending client IP address via some other header, it won't be detected.

  3. Changing the request's remoteAddr by addFOrwardingCustomizer changes the behaviour in ApiServlet.getClientAddress() which expects request.getRemoteAddr() to return the proxy's address, so that it can compare it with the allowed proxy cidrs as set in proxy.cidr

For the fix, I have removed addForwardingCustomizer and calling ApiServlet.getClientAddress() from ACSRequestLog. This way IPs in all the logs are consistent with each other and use the same method (getClientAddress()) to get the forwarded client's IP address.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • Build/CI
  • Test (unit or integration test code)

Feature/Enhancement Scale or Bug Severity

Feature/Enhancement Scale

  • Major
  • Minor

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

Screenshots (if appropriate):

How Has This Been Tested?

Verified that the forwarded IP is being logged in all the logs.
Also tried the with the script test_forwareded_headers.sh as given here #11386 (review)

Settings used :
Screenshot 2025-10-17 at 7 41 15 PM

Forwarded IP : 203.0.113.1
management.log
2025-10-17 11:35:03,230 DEBUG [c.c.a.ApiServlet] (qtp1390913202-27:[ctx-e2a9983c]) (logid:294c8b7e) found ip 203.0.113.1 in header X-Forwarded-For
2025-10-17 11:35:03,230 DEBUG [c.c.a.ApiServlet] (qtp1390913202-27:[ctx-e2a9983c]) (logid:294c8b7e) ===START===  203.0.113.1 -- GET  command=listCapabilities&response=json

api.log
2025-10-17 11:34:58,164 INFO  [a.c.c.a.ApiServlet] (qtp1390913202-443:[ctx-1ba1de31, ctx-a7f19570]) (logid:041cfd8f)  203.0.113.1 -- GET command=listCapabilities&response=json 401 unable to verify user credentials and/or request signature

access.log
/203.0.113.1 - - [2025-10-17 11:34:58] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"


./test_forwareded_headers.sh

=== RESULTS ANALYSIS ===
CloudStack access log entries:
==============================
/10.0.3.251 - - [2025-10-17 11:34:58] "GET /client/api/?managementserverid=ff7ce98c-a53e-44a1-8df5-7adc455cd523&command=readyForShutdown&response=json& HTTP/1.1" 200 231 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:144.0) Gecko/20100101 Firefox/144.0"
/203.0.113.1 - - [2025-10-17 11:34:58] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
/203.0.113.2 - - [2025-10-17 11:34:59] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
/203.0.113.3 - - [2025-10-17 11:35:00] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
/203.0.113.10 - - [2025-10-17 11:35:01] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
/0:0:0:0:0:0:0:1 - - [2025-10-17 11:35:02] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
/10.0.3.251 - - [2025-10-17 11:35:03] "GET /client/api/?managementserverid=ff7ce98c-a53e-44a1-8df5-7adc455cd523&command=readyForShutdown&response=json& HTTP/1.1" 200 231 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:144.0) Gecko/20100101 Firefox/144.0"
/203.0.113.20 - - [2025-10-17 11:35:03] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"

=== VALIDATION ===
==================
SUCCESS: Forwarded IP addresses found in CloudStack access log!
PR #11386 forwarded headers functionality is working correctly

Detected forwarded IPs:
======================
  /203.0.113.1 - - [2025-10-17 11:34:58] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
  /203.0.113.2 - - [2025-10-17 11:34:59] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
  /203.0.113.3 - - [2025-10-17 11:35:00] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
  /203.0.113.10 - - [2025-10-17 11:35:01] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"
  /203.0.113.20 - - [2025-10-17 11:35:03] "GET /client/api?command=listCapabilities&response=json HTTP/1.1" 401 133 "-" "curl/7.61.1"

Analysis:
=========
Unique forwarded IPs detected:
  /203.0.113.1 (appeared 2 time(s))
  /203.0.113.10 (appeared 1 time(s))
  /203.0.113.2 (appeared 2 time(s))
  /203.0.113.20 (appeared 1 time(s))
  /203.0.113.3 (appeared 1 time(s))

Test completed at: Fri Oct 17 11:35:06 UTC 2025
===========================

The script ./test_forwareded_headers.sh fails without the fix

How did you try to break this feature and the system with this change?

@abh1sar
Copy link
Collaborator Author

abh1sar commented Oct 16, 2025

@blueorangutan package

@blueorangutan
Copy link

@abh1sar a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

Copy link
Contributor

@DaanHoogland DaanHoogland left a comment

Choose a reason for hiding this comment

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

clgtm

@codecov
Copy link

codecov bot commented Oct 16, 2025

Codecov Report

❌ Patch coverage is 92.30769% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 17.59%. Comparing base (55ab7c5) to head (04eb391).
⚠️ Report is 31 commits behind head on 4.22.

Files with missing lines Patch % Lines
server/src/main/java/com/cloud/api/ApiServlet.java 92.30% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##               4.22   #11854    +/-   ##
==========================================
  Coverage     17.59%   17.59%            
- Complexity    15595    15598     +3     
==========================================
  Files          5910     5910            
  Lines        529606   529753   +147     
  Branches      64705    64723    +18     
==========================================
+ Hits          93178    93225    +47     
- Misses       425940   426036    +96     
- Partials      10488    10492     +4     
Flag Coverage Δ
uitests 3.60% <ø> (+0.02%) ⬆️
unittests 18.66% <92.30%> (+<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.

@blueorangutan
Copy link

Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 15485

@abh1sar abh1sar closed this Oct 17, 2025
@abh1sar abh1sar reopened this Oct 17, 2025
@abh1sar abh1sar closed this Oct 17, 2025
@abh1sar abh1sar reopened this Oct 17, 2025
@abh1sar
Copy link
Collaborator Author

abh1sar commented Oct 17, 2025

@blueorangutan package

@blueorangutan
Copy link

@abh1sar a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 15490

@abh1sar
Copy link
Collaborator Author

abh1sar commented Oct 17, 2025

@blueorangutan package

@abh1sar abh1sar changed the title [Wip] Fix logging forwarded IP in access log Fix logging of forwarded IPs in logs Oct 17, 2025
@abh1sar abh1sar marked this pull request as ready for review October 17, 2025 14:12
@abh1sar abh1sar requested a review from DaanHoogland October 17, 2025 14:13
@blueorangutan
Copy link

@abh1sar a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 15495

@abh1sar
Copy link
Collaborator Author

abh1sar commented Oct 17, 2025

@blueorangutan package

@blueorangutan
Copy link

@abh1sar a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 15496

@abh1sar
Copy link
Collaborator Author

abh1sar commented Oct 21, 2025

@blueorangutan package

@blueorangutan
Copy link

@abh1sar a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 15509

@abh1sar abh1sar marked this pull request as draft October 21, 2025 10:56
@abh1sar abh1sar force-pushed the forwarded-ip-accesslog branch from 63ce1c6 to 2ca1e10 Compare October 21, 2025 14:13
@abh1sar abh1sar marked this pull request as ready for review October 21, 2025 15:17
@abh1sar
Copy link
Collaborator Author

abh1sar commented Oct 21, 2025

@blueorangutan package

@blueorangutan
Copy link

@abh1sar a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

[SF] Trillian Build Failed (tid-14710)

@DaanHoogland
Copy link
Contributor

@blueorangutan package

@blueorangutan
Copy link

@DaanHoogland a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 15589

@DaanHoogland
Copy link
Contributor

@blueorangutan test keepEnv

@blueorangutan
Copy link

@DaanHoogland a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests

@blueorangutan
Copy link

[SF] Trillian test result (tid-14748)
Environment: kvm-ol8 (x2), zone: Advanced Networking with Mgmt server ol8
Total time taken: 63595 seconds
Marvin logs: https://github.com/blueorangutan/acs-prs/releases/download/trillian/pr11854-t14748-kvm-ol8.zip
Smoke tests completed. 148 look OK, 1 have errors, 0 did not run
Only failed and skipped tests results shown below:

Test Result Time (s) Test File
test_02_enableHumanReadableLogs Error 0.25 test_human_readable_logs.py

Copy link
Contributor

@DaanHoogland DaanHoogland left a comment

Choose a reason for hiding this comment

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

clgtm, tested in Lab

@DaanHoogland
Copy link
Contributor

@harikrishna-patnala , can you please review?

Copy link
Contributor

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 fixes a bug where forwarded client IPs behind a proxy were not being correctly logged in management.log, api.log, and access.log. The root cause was that PR #11386 introduced a ForwardedRequestCustomizer in Jetty that only checked the first header in the configured list and modified the request's remote address, which interfered with proxy CIDR verification.

Changes:

  • Removed the Jetty ForwardedRequestCustomizer approach in favor of consistently using ApiServlet.getClientAddress() across all logging points
  • Made several methods in ApiServlet static to enable reuse from ACSRequestLog
  • Updated ACSRequestLog to use ApiServlet.getClientAddress() instead of directly accessing the endpoint's remote address

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
client/src/main/java/org/apache/cloudstack/ServerDaemon.java Removed addForwardingCustomiser() method and related Jetty customizer configuration, plus removed unused imports
client/src/main/java/org/apache/cloudstack/ACSRequestLog.java Updated to call ApiServlet.getClientAddress() for consistent forwarded IP detection across all logs
server/src/main/java/com/cloud/api/ApiServlet.java Refactored getClientAddress() and related methods to be static with improved early-return logic and updated logging format
server/src/test/java/com/cloud/api/ApiServletTest.java Updated tests to use static method calls and added ConfigDepot mocking infrastructure for testing configuration values

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

.getRemoteAddress().getAddress()
.getHostAddress())
InetAddress remoteAddress = ApiServlet.getClientAddress(request);
sb.append(remoteAddress)
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

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

The log format has changed by appending the InetAddress object directly instead of calling getHostAddress(). This results in IP addresses being logged with a leading "/" (e.g., "/192.168.1.1" instead of "192.168.1.1") because InetAddress.toString() returns the format "hostname/ipaddress" or "/ipaddress". This format change could break existing log parsing tools. Consider calling getHostAddress() on the InetAddress object to maintain the previous log format.

Suggested change
sb.append(remoteAddress)
sb.append(remoteAddress != null ? remoteAddress.getHostAddress() : "-")

Copilot uses AI. Check for mistakes.
.getRemoteAddress().getAddress()
.getHostAddress())
InetAddress remoteAddress = ApiServlet.getClientAddress(request);
sb.append(remoteAddress)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
sb.append(remoteAddress)
sb.append(remoteAddress.getHostAddress())

httpConfig.setResponseHeaderSize(8192);
httpConfig.setSendServerVersion(false);
httpConfig.setSendDateHeader(false);
addForwardingCustomiser(httpConfig);
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to remove this?

@abh1sar abh1sar modified the milestones: 4.20.3, 4.22.1 Jan 13, 2026
@abh1sar abh1sar changed the base branch from main to 4.22 January 13, 2026 07:27
@abh1sar abh1sar force-pushed the forwarded-ip-accesslog branch from e9fd76f to 04eb391 Compare January 13, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants