mod_auth_openidc: newer versions cause lots of warnings about OIDCXForwardedHeaders
We upgraded mod_auth_openidc to a newer version (we have tested 2.4.15.7 and 2.4.16.4 specifically), in order to get certain site-specific functionality working. We noticed that there is a noticeable amount of warning logs from the module, which complain about mismatches in expectations of X-Forwarded-* headers. See the configuration documentation here for details.
The default value of OIDCXForwardedHeaders none causes warnings each time one of the headers appears, and if one were to set it to X-Forwarded-Proto for example, it would warn whenever the header is missing.
The X-Forwarded-Proto header is the only one we've observed in our OOD deployments, and the total amount of logging is roughly 35% of the OOD instance's log line count, when using the default OIDCXForwardedHeaders none configuration. So it's a significant issue.
The mod_auth_openidc project seems to not offer any way of avoiding this check, or warning log, which indicates to me that sites should have this working correctly.
My questions for OOD are:
- Why are we seeing
X-Forwarded-Protowarnings from making a request to the dashboard?
I noticed that the header is set in the Lua proxy code, and this is what triggers the warnings from mod_auth_openidc. Commenting out this line in proxy.lua removes the warning logs altogether.
- What is this header used for downstream?
- Could it simply be removed?
- If not, could it be injected in some other way, which would not irritate
mod_auth_openidc?
Some additional info:
- While debugging httpd behavior, it seems like
mod_auth_openidcchecks the headers multiple times per end-user HTTP request (e.g.GET /pun/sys/dashboard). I saw three checks per request in our deployment. It seems thatmod_auth_openidcis hooked into multiple stages of request processing. - We experimented with always removing the
X-Forwarded-Protoheader usingRequestHeader unset X-Forwarded-Proto early. This didn't work completely, since theproxy.luaaddition still happened by the end of request handling, andmod_auth_openidcran its check once after that as well...- Note the
earlyrequest processing is not recommended for production setups: https://httpd.apache.org/docs/current/mod/mod_headers.html#early
- Note the
Thanks in advance!
- Why are we seeing X-Forwarded-Proto warnings from making a request to the dashboard?
- What is this header used for downstream?
Unfortunately the commit that adds it doesn't give us much information. Ostensibly, it's so the origin server can make some sort of toggle. While the dashboard may not care, it's sort of a larger issue when we talk about what other Passenger apps could be out there in the wild, and how they may be reacting to this.
https://github.com/OSC/ondemand/commit/c7ab1c71af4aa606e491424a8ef83eb200bc6dbd
- Could it simply be removed?
Maybe. But again, it brings into question comparability with Passenger apps in the wild. Someone may be using it, though I can't say for sure.
Why not just configure OIDCXForwardedHeaders to allow the X-Forwarded-Proto header?
While the dashboard may not care, it's sort of a larger issue when we talk about what other Passenger apps could be out there in the wild, and how they may be reacting to this.
Based on my understanding this is the risk with disabling it, yes. Downstream apps might behave differently if they do not know whether the connection is secure or not. I suppose we would need to test this and make a decision based on the outcomes. But good to know that OOD's default apps don't rely on it.
Why not just configure
OIDCXForwardedHeadersto allow theX-Forwarded-Protoheader?
Good question, sorry for not bringing that up earlier. I already tested this as well, and it also causes a non-zero amount of warnings due to the logic I described above:
if one were to set it to
X-Forwarded-Protofor example, it would warn whenever the header is missing.
A quick 1-minute test with this option on yields 89 warning lines in a total of 256 httpd log lines. So this is not really a viable option either.
$ ts="2024-10-21T14:43:00" ; \
> gawk "{if (\$1 > $(date +%s --date=${ts:?})) print }" < log | grep -cE ' ondemand_httpd ' ; \
> gawk "{if (\$1 > $(date +%s --date=${ts:?})) print }" < log | grep -cE 'oidc_check_x_forwarded_hdr' ;
256 # Total httpd log lines
89 # OIDC warning lines
I believe that the mod_auth_openidc that OOD bundles doesn't yet have these warnings, but if you plan on upgrading that to something newer, other sites will run into this as well. The parsing of these headers seems to have been introduced in version 2.4.11rc0 (commit).
It would be nice to understand what the correct way of handling this might be, and how to avoid the warning logs, so please let us know if you have ideas here.
I've encountered this issue as well, and the approach that I took was to allow the headers. As you say, when a header is missing, then the logs will warn about that as well, but I haven't seen new warnings about missing headers. I'm working in a development environment, so it's possible that will come later.
I also ran into an issue where when I enabled the missing headers, the port was included in the request url, causing OIDC authentication through dex to fail. I addressed this by allowing the url with the port as an OIDC redirect URI. The better config for me looks like
oidc_settings:
OIDCXForwardedHeaders: X-Forwarded-Proto X-Forwarded-Port
dex_uri: /dex
dex:
client_redirect_uris:
- 'https://${WEBSITE_DOMAIN}:443/oidc'
# rest of the dex config unchanged
That has WEBSITE_DOMAIN subbed in for the domain of the environment being deployed.
3. Could it simply be removed?
Maybe. But again, it brings into question comparability with Passenger apps in the wild. Someone may be using it, though I can't say for sure.
I tried this today, and can report that some Rails middleware will be unhappy about the X-Forwarded-Proto header being missing when submitting a Slurm job. I got an HTTP 422 error ("Unprocessable Content") and the following Passenger logs:
App 4729 output: [2025-06-24 10:13:51 +0300 ] WARN "HTTP Origin header (https://my-redacted-hostname) didn't match request.base_url (http://my-redacted-hostname)"
App 4729 output: [2025-06-24 10:13:51 +0300 ] INFO "method=POST path=/pun/sys/dashboard/batch_connect/sys/ood-vnc/session_contexts format=html controller=BatchConnect::SessionContextsController action=create status=422 allocations=216 duration=0.49 view=0.00"
App 4729 output: [2025-06-24 10:13:51 +0300 ] FATAL "ActionController::InvalidAuthenticityToken (HTTP Origin header (https://my-redacted-hostname) didn't match request.base_url (http://my-redacted-hostname)):
actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:253:in `handle_unverified_request'
actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:286:in `handle_unverified_request'
actionpack (7.0.8.5) lib/action_controller/metal/request_forgery_protection.rb:275:in `verify_authenticity_token'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:400:in `block in make_lambda'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:199:in `block (2 levels) in halting'
actionpack (7.0.8.5) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:200:in `block in halting'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:595:in `block in invoke_before'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:595:in `each'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:595:in `invoke_before'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:116:in `block in run_callbacks'
turbo-rails (2.0.7) lib/turbo-rails.rb:24:in `with_request_id'
turbo-rails (2.0.7) app/controllers/concerns/turbo/request_id_tracking.rb:10:in `turbo_tracking_request_id'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:127:in `block in run_callbacks'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:138:in `run_callbacks'
actionpack (7.0.8.5) lib/abstract_controller/callbacks.rb:233:in `process_action'
actionpack (7.0.8.5) lib/action_controller/metal/rescue.rb:23:in `process_action'
actionpack (7.0.8.5) lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'
activesupport (7.0.8.5) lib/active_support/notifications.rb:206:in `block in instrument'
activesupport (7.0.8.5) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (7.0.8.5) lib/active_support/notifications.rb:206:in `instrument'
actionpack (7.0.8.5) lib/action_controller/metal/instrumentation.rb:66:in `process_action'
actionpack (7.0.8.5) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
actionpack (7.0.8.5) lib/abstract_controller/base.rb:151:in `process'
actionview (7.0.8.5) lib/action_view/rendering.rb:39:in `process'
actionpack (7.0.8.5) lib/action_controller/metal.rb:188:in `dispatch'
actionpack (7.0.8.5) lib/action_controller/metal.rb:251:in `dispatch'
actionpack (7.0.8.5) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (7.0.8.5) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (7.0.8.5) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (7.0.8.5) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (7.0.8.5) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (7.0.8.5) lib/action_dispatch/routing/route_set.rb:852:in `call'
rack (2.2.10) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.10) lib/rack/etag.rb:27:in `call'
rack (2.2.10) lib/rack/conditional_get.rb:40:in `call'
rack (2.2.10) lib/rack/head.rb:12:in `call'
actionpack (7.0.8.5) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
actionpack (7.0.8.5) lib/action_dispatch/http/content_security_policy.rb:36:in `call'
rack (2.2.10) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.10) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/cookies.rb:704:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.8.5) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.8.5) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
lograge (0.14.0) lib/lograge/rails_ext/rack/logger.rb:18:in `call_app'
railties (7.0.8.5) lib/rails/rack/logger.rb:25:in `block in call'
activesupport (7.0.8.5) lib/active_support/tagged_logging.rb:99:in `block in tagged'
activesupport (7.0.8.5) lib/active_support/tagged_logging.rb:37:in `tagged'
activesupport (7.0.8.5) lib/active_support/tagged_logging.rb:99:in `tagged'
railties (7.0.8.5) lib/rails/rack/logger.rb:25:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
request_store (1.7.0) lib/request_store/middleware.rb:19:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.10) lib/rack/method_override.rb:24:in `call'
rack (2.2.10) lib/rack/runtime.rb:22:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/executor.rb:14:in `call'
rack (2.2.10) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.8.5) lib/action_dispatch/middleware/host_authorization.rb:138:in `call'
railties (7.0.8.5) lib/rails/engine.rb:530:in `call'
/opt/rh/ondemand/root/usr/share/ruby/vendor_ruby/phusion_passenger/rack/thread_handler_extension.rb:107:in `process_request'
/opt/rh/ondemand/root/usr/share/ruby/vendor_ruby/phusion_passenger/request_handler/thread_handler.rb:157:in `accept_and_process_next_request'
/opt/rh/ondemand/root/usr/share/ruby/vendor_ruby/phusion_passenger/request_handler/thread_handler.rb:110:in `main_loop'
/opt/rh/ondemand/root/usr/share/ruby/vendor_ruby/phusion_passenger/request_handler.rb:419:in `block (3 levels) in start_threads'
/opt/rh/ondemand/root/usr/share/ruby/vendor_ruby/phusion_passenger/utils.rb:113:in `block in create_thread_and_abort_on_exception'"
I tried various combinations of expecting OIDCXForwardedHeaders and setting or unsetting the X-Forwarded-Proto header in the ood-portal.conf (early vs. late, set vs. unset), but none of the combinations actually removed the warnings in httpd's logs when hard-refreshing the dashboard app. I get warnings both when expecting and not expecting the headers:
# Expected, i.e., "OIDCXForwardedHeaders X-Forwarded-Proto"
oidc_check_x_forwarded_hdr: OIDCXForwardedHeaders configured for header X-Forwarded-Proto but not found in request, referer: https://my-redacted-hostname/pun/sys/dashboard/
# Not expected, i.e. "OIDCXForwardedHeaders none" (the default config):
oidc_check_x_forwarded_hdr: header X-Forwarded-Proto received but OIDCXForwardedHeaders not configured for it, referer: https://my-redacted-hostname/pun/sys/dashboard/
To be clear, the httpd server is at the edge of the network, so no reverse proxies are in front of it and mod_auth_openidc. We're currently testing mod_auth_openidc 2.4.17.
I'm starting to think that the easiest way out would be to filter out these log messages in other parts of the stack... Let me know if you have other ideas.
Hi again,
I reached out to the mod_auth_openidc project and asked if the logs could be ignored, and they very quickly added a possibility to do that! See https://github.com/OpenIDC/mod_auth_openidc/discussions/1333#discussioncomment-13572107
So there's a patch now if anybody wants to pick it up. Otherwise, I suppose the new environment variable will be available in version 2.4.17.2 whenever it is released.
Regarding OOD's role in this issue, it could still be considered whether the httpd configuration should be put into the ood-portal.conf.erb template, for ease of use. Any opinions on this?
Basically something like this would be needed to disable the logging (see the discussion linked above):
SetEnvIfExpr true OIDC_CHECK_X_FORWARDED_HDR_LOG_DISABLE=X-Forwarded-Proto
GitHub review meeting notes: Explained that newer versions of ModAuth OpenIDC generate many warnings User had provided a workaround in the issue Noted that user's company manages more users and notices issues at scale
Conclusion: Scheduled tentatively for version 4.1 Team will implement user's workaround