Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use nginx realip module #2977

Merged
merged 2 commits into from
May 6, 2024
Merged

fix: use nginx realip module #2977

merged 2 commits into from
May 6, 2024

Conversation

oioki
Copy link
Member

@oioki oioki commented Apr 19, 2024

By default, Sentry gets the client's IP address from the X-Forwarded-For header:
https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py#L3080

However, this header can be spoofed. The more correct approach adhering to standard is suggested in getsentry/sentry#68884
However, before going forward with it, we need to make sure that we are not breaking self-hosted installations.

This PR makes sure that the X-Forwarded-For header that is sent along the request to the sentry container, contains the real IP address of the client, and it's the only one, no other values in the list.

We do so by using nginx realip module in the nginx container of self-hosted installation:

  1. if there is an X-Forwarded-For header coming from internal subnets (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), then we trust it and use the rightmost IP address that does not belong to the said subnets. E.g in the case of SPOOFED_IP, MY_REAL_IP, 172.17.0.0 it will be MY_REAL_IP;
  2. if there is an X-Forwarded-For header coming from the other untrusted subnet, then the rightmost (untrustworthy) value will be used;
  3. if there is no X-Forwarded-For header in a request to the nginx container, then the IP address of the connection will be used (as usual).

We recommend to use an external load balancer (such as nginx) in addition to self-hosted docker-compose: https://develop.sentry.dev/self-hosted/#productionalizing
Usually, a load balancer sends X-Forwarded-For request header so it will always be the case 1 (from above list), and sentry container will get the correct client's IP address.

@oioki oioki requested review from tonyo, a team and mwarkentin April 19, 2024 13:40
Copy link

codecov bot commented Apr 19, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.01%. Comparing base (d59c0aa) to head (f2a4b55).
Report is 2 commits behind head on master.

✅ All tests successful. No failed tests found ☺️

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2977   +/-   ##
=======================================
  Coverage   99.01%   99.01%           
=======================================
  Files           3        3           
  Lines         203      203           
=======================================
  Hits          201      201           
  Misses          2        2           

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

Copy link
Collaborator

@aldy505 aldy505 left a comment

Choose a reason for hiding this comment

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

We recommend to use an external load balancer (such as nginx) in addition to self-hosted docker-compose: https://develop.sentry.dev/self-hosted/#productionalizing
Usually, a load balancer sends X-Forwarded-For request header so it will always be the case 1 (from above list), and sentry container will get the correct client's IP address.

There's a page dedicated for that, but it's missing nginx (because at the time of writing, I don't use nginx), it'll be nice if you can also take a look to fill some missing gaps (if any): https://develop.sentry.dev/self-hosted/reverse-proxy

nginx/nginx.conf Outdated
Comment on lines 46 to 48
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is up for debate, but I think proper list of internal subnets should be acquired from here: https://en.wikipedia.org/wiki/Reserved_IP_addresses. Also considering that the address might come from an IPv6 address. But if this turns out to be out of scope, then these addresses are fine.

Copy link
Collaborator

Choose a reason for hiding this comment

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

These should be docker default subnets which are:

https://github.com/moby/libnetwork/blob/3797618f9a38372e8107d8c06f6ae199e1133ae8/ipamutils/utils.go#L10-L22 :

172.17.0.0/16
172.18.0.0/16
172.19.0.0/16
172.20.0.0/14
172.24.0.0/14
172.28.0.0/14
192.168.0.0/16
10.0.0.0/8

Copy link
Member Author

Choose a reason for hiding this comment

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

@aminvakil Thank you for the reference! That seems the most correct subnet list.

# Remove the Connection header if the client sends it,
# it could be "close" to close a keepalive connection
proxy_set_header Connection '';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr;
Copy link
Member

Choose a reason for hiding this comment

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

Note: this might break some installations that have multiple hops before this Nginx, e.g. when the self-hosted installation is behind Google/AWS load balancers that normally add a bunch of records to X-Forwarded-For header automatically.

That means that we should highlight this in the release notes, and point to recommendations around "how to pass the trusted client IP to the Sentry backend".

@tonyo tonyo requested a review from a team April 23, 2024 09:25
Copy link
Member

@hubertdeng123 hubertdeng123 left a comment

Choose a reason for hiding this comment

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

tested branch on dogfood self hosted, seems to be fine

@oioki
Copy link
Member Author

oioki commented Apr 29, 2024

@aldy505

There's a page dedicated for that, but it's missing nginx (because at the time of writing, I don't use nginx), it'll be nice if you can also take a look to fill some missing gaps (if any): https://develop.sentry.dev/self-hosted/reverse-proxy

I'm adding it here: getsentry/develop#1257

@oioki oioki merged commit 23fa29d into master May 6, 2024
12 checks passed
@oioki oioki deleted the fix/real-ip branch May 6, 2024 11:55
@github-actions github-actions bot locked and limited conversation to collaborators May 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

5 participants