Problem/Motivation

We are setting up a client website in Azure Kubernetes(K8S) Service behind Application Gateway (AppGW) fronted by Cloudflare (CF):

CF => AppGW => K8S => Drupal

The problem is that, when 'Restore Client Ip Address' option is enabled, the module tries to validate that request is really coming from Cloudflare by comparing $client_ip = $current_request->getClientIp(); which is coming from Kubernetes ingress controller (and is private un-routable IP, like 10.170.76.133) to the list of known Cloudflare IPs. Of course this validation fails.

In our case, we setting it all up in a secure recommended way - only CF IPs are allowed to talk to AppGW, so we can safely avoid this check, and implement the same code as in ClientIpRestore::onRequest():

    $event->getRequest()->server->set('HTTPS', $event->getRequest()->isSecure() ? 'on' : 'off');
    $event->getRequest()->server->set('REMOTE_ADDR', $cf_connecting_ip);
    $event->getRequest()->overrideGlobals();

without remote address IP validation.

Proposed resolution

  • Use CF-Visitor header provided by CloudFlare to detect request scheme used by website visitor
  • Add option to skip remote address IP validation
  • Move restore visitor IP address functionality into middleware

First item solves the problem of an incorrect "secure" flag value on a session cookie when website is configured in the flexible encryption mode. Last two supports both the cookie problem, and flexible encryption set and set up with intermediaries.

Remaining tasks

  • Patch - Done
  • Review
  • Commit

User interface changes

New checkbox on the configuration form.

API changes

None.

Data model changes

None

Release notes snippet

Ability to skip Cloudflare IP validation when restoring real client IP address.

Original description

We are setting up a client website in Azure Kubernetes(K8S) Service behind Application Gateway (AppGW) , but I'm not sure if that is related to the issue we are having, fronted by Cloudflare (CF):

CF => AppGW => K8S => Drupal

The problem is that, when 'Restore Client Ip Address' option is enabled, the module tries to validate that request is really coming from Cloudflare by comparing $client_ip = $current_request->getClientIp(); which is coming from Kubernetes ingress controller (and is private un-routable IP, like 10.170.76.133) to the list of known Cloudflare IPs. Of course this validation fails.

The question is how do we as a community address this ?

In our case, we setting it all up in a secure recommended way - only CF IPs are allowed to talk to AppGW so we can safely avoid this check, and implement the same code as in ClientIpRestore::onRequest():

    $event->getRequest()->server->set('HTTPS', $event->getRequest()->isSecure() ? 'on' : 'off');
    $event->getRequest()->server->set('REMOTE_ADDR', $cf_connecting_ip);
    $event->getRequest()->overrideGlobals();

skipping all previous checks. This solution however wouldn't fit all other use-cases .

I would prefer to see some kind of configuration option in this module that would allow me to achieve what I'm after, rather than throwing custom code in my projects. If that approach sounds acceptable I'm happy to code it and provide a patch. Something like "Skip request origin check" with the bold description similar to "Scary-sounding warning" of Trusted Reverse Proxy that this should only be enabled in exceptional circumstances and full responsibility about consequences is on the user ticking that checkbox.

Comments

RoSk0 created an issue. See original summary.

rosk0’s picture

Title: Cloudflare IP validation » Allow skipping Cloudflare IP validation
Component: Miscellaneous » Code
Category: Support request » Feature request
Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new8.94 KB

After some additional time thinking about it and conversation with colleague I decided to re-qualify this to feature request.

Patch attached.

rosk0’s picture

StatusFileSize
new6.3 KB
new3.01 KB

Disregard the previous patch please.

rosk0’s picture

Not starting tests as they are broken.

I fixed all tests in #2915341: Proposal to switch Cloudflare library, but that includes the changes related to the subject. Might need to pull our test fixes into a separate issue...

rosk0’s picture

Related issues: +#3137858: Not original IPs on "access denied", "page not found", Ban module
StatusFileSize
new7.51 KB
new1.53 KB

Important bit that I missed previously is that TLS termination is happening in K8s ingress controller and Drupal receives plain HTTP traffic so using original request to determine the scheme is pointless. So in this patch I used supplied by Cloudflare CF-Visitor header. It contains scheme of the original request.

Adding #3137858: Not original IPs on "access denied", "page not found", Ban module to related, as in our case, it was required to make the whole thing work as expected. See #3137858-6: Not original IPs on "access denied", "page not found", Ban module for details.

rosk0’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests
rosk0’s picture

Title: Allow skipping Cloudflare IP validation » Support more use cases
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new13.08 KB

Changing the title and description to better reflect what is actually happening here and why.

Also I will start with just the test to proof missing support for various use cases:

  • when website is access by authenticated users over CloudFlare
  • when website is configure in the flexible encryption mode
  • when website have intermediaries between CloudFlare and the origin server, like for example Kubernetes ingress controller or Azure Application Gateway

For starters this patch includes priority change from #3137858: Not original IPs on "access denied", "page not found", Ban module just to show that authenticated users are still getting insecure cookie in flexible encryption mode with the priority change.

Could not generate interdiff as module moved one since patch in #5, the changes are:

Status: Needs review » Needs work

The last submitted patch, 7: cloudflare-3280262-7.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

rosk0’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new22.44 KB
new13 KB

Functional test failed in expected way, unit tests failed because of missing configuration value - fixed.

And now with the middleware.

  • RoSk0 committed 0c59e6f1 on 8.x-1.x
    Issue #3280262 by RoSk0: Support more use cases
    
rosk0’s picture

Status: Needs review » Fixed

Tests are green, manual testing on a real project went good as well.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.