Skip to content

Add configuration option for trusted proxies#1126

Merged
st0012 merged 6 commits intogetsentry:4-2from
jeschneiderhan:je-trusted-proxies
Jan 26, 2021
Merged

Add configuration option for trusted proxies#1126
st0012 merged 6 commits intogetsentry:4-2from
jeschneiderhan:je-trusted-proxies

Conversation

@jeschneiderhan
Copy link
Copy Markdown
Contributor

Description

When Sentry calculates the IP address for a user, it will skip addresses that fall in a predetermined list of private IP address ranges: https://github.com/getsentry/sentry-ruby/blob/master/sentry-ruby/lib/sentry/utils/real_ip.rb#L10-L17. Some people run services behind proxies that are not part of these ranges, which currently results in the IP address of the proxy being used as the user IP address.

For example, Let's assume I have a service running behind Cloudflare. When a request from a client (2.2.2.2) reaches my application, it has headers like the following:

X-Forwarded-For: 2.2.2.2,172.68.54.247     # 172.68.54.247 is an IP address owned by Cloudflare
X-Real-Ip: 172.68.54.247

Right now, if the request throws an error, the Sentry will have a user IP address of 172.68.54.247 since it is the first address encountered that is not in the default list of IPs to skip.

ActionDispatch allows the specification of trusted_proxies via the config.action_dispatch.trusted_proxies setting. Any IP ranges specified will be added to default list of private address ranges (See remote_ip.rb for more information). I've attempted to provide a similar setting to the sentry-ruby configuration. It also updates the sentry-rails railtie to automatically add any config.action_dispatch.trusted_proxies values to the sentry-ruby trusted_proxies.

With these settings, it is possible to add the IP ranges of the non-private proxies that you trust. These IPs will be skipped, and in the example above, will result in Sentries using the correct user IP (2.2.2.2 in the above example).

I also noticed that the X-Forwarded-For header is being iterated from the beginning of the string. Although this works a lot of the time, I think the usual way to process this header is to iterate from right to left, taking the first IP that is not in the trusted list. The remote_ip code reverses the list prior to processing, for example. I added a forwarded_ips.reverse call below to match that behavior.

I hope that all makes sense!

@st0012
Copy link
Copy Markdown
Contributor

st0012 commented Dec 8, 2020

@jeschneiderhan thanks for the PR, I think the idea makes sense 👍
but currently, we're busy preparing for the official release of the new SDKs. so I can't accept new feature changes until we roll out the 4.0.0 version and will put this into the 4.1.0 milestone. I hope that's ok to you?

@st0012 st0012 added this to the 4.1.0 milestone Dec 8, 2020
@jeschneiderhan
Copy link
Copy Markdown
Contributor Author

@st0012 sounds good! Thanks!

@st0012 st0012 modified the milestones: 4.1.0, 4.2.0 Dec 15, 2020
@st0012
Copy link
Copy Markdown
Contributor

st0012 commented Dec 18, 2020

@jeschneiderhan sorry for the delay, we have several bug fixes needed to be shipped this week, which contains a few breaking changes. so we cut the 4.1.0 earlier than expected. as a result, this PR has been moved to 4.2.0 🙇

I'll review and merge it once we confirm the 4.1.0 doesn't have major issues. in the meantime, can you resolve the conflicts too? I updated the structure of railtie.rb so you'll need to adjust the code a bit.

@codecov-io
Copy link
Copy Markdown

codecov-io commented Dec 18, 2020

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.49%. Comparing base (c68442b) to head (cf7f977).

Additional details and impacted files
@@           Coverage Diff           @@
##              4-2    #1126   +/-   ##
=======================================
  Coverage   98.48%   98.49%           
=======================================
  Files         102      102           
  Lines        4565     4589   +24     
=======================================
+ Hits         4496     4520   +24     
  Misses         69       69           

☔ 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.

@jeschneiderhan
Copy link
Copy Markdown
Contributor Author

@st0012 thanks for the update. I've rebased off of master and resolved the conflicts.

Copy link
Copy Markdown
Contributor

@st0012 st0012 left a comment

Choose a reason for hiding this comment

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

some small changes needed + some questions. otherwise looks good 👍

client_ips = ips_from(@client_ip)
real_ips = ips_from(@real_ip)
forwarded_ips = ips_from(@forwarded_for)
forwarded_ips = ips_from(@forwarded_for).reverse
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.

can you add a comment on why we need to call reverse here?

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.

👍 Comment added.

From the Mozilla docs:

If a request goes through multiple proxies, the IP addresses of each successive proxy is listed. This means, the right-most IP address is the IP address of the most recent proxy and the left-most IP address is the IP address of the originating client.

When processing these values for a client IP address, one typically starts from the rightmost value (the last proxy) and walks backward until the first IP not in a trusted IP range is found. This is used as the client IP address since nothing before that can be "trusted" to have recorded legitimate values.

The ActiveDispatch code reverses the list prior to processing, for example.

@jeschneiderhan
Copy link
Copy Markdown
Contributor Author

Thanks for the comments, @st0012. I'm hoping to find time to address them this afternoon.

@st0012 st0012 changed the base branch from master to 4-2 January 15, 2021 11:20
* Add `trusted_proxies` configuration option to sentry-ruby
* Add existing ActionDispatch `trusted_proxies` values
* Isolate trusted proxy test configuration
* Add comments to explain why we reverse the forwarded_for ip list
* Call `uniq` on the trusted proxy list
* Rename `filter_local_addresses(ips) to filter_trusted_proxy_addresses(ips)
@jeschneiderhan
Copy link
Copy Markdown
Contributor Author

@st0012 I think I got to everything 👍

Copy link
Copy Markdown
Contributor

@st0012 st0012 left a comment

Choose a reason for hiding this comment

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

I left some comments on updating the test cases. otherwise all look good now 👍

Copy link
Copy Markdown
Contributor

@st0012 st0012 left a comment

Choose a reason for hiding this comment

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

@jeschneiderhan thanks for the great work ❤️ I'll resolve the conflicts 😉

@jeschneiderhan
Copy link
Copy Markdown
Contributor Author

I think the check that failed may have been a transient error. Can we re-run it?

@st0012
Copy link
Copy Markdown
Contributor

st0012 commented Jan 26, 2021

@jeschneiderhan the failure is actually inherited from the 4-2 branch, so merging now.

@st0012 st0012 merged commit df57dee into getsentry:4-2 Jan 26, 2021
@jeschneiderhan jeschneiderhan deleted the je-trusted-proxies branch January 26, 2021 14:15
st0012 added a commit that referenced this pull request Feb 3, 2021
* Add ThreadsInterface (#1178)

* Add ThreadsInterface

* Update changelog

* Inspect exception cause by default & don't exclude ActiveJob::DeserializationError  (#1180)

* Turn on inspect_exception_causes_for_exclusion by default

With this config turned on, we can avoid matching the surface exceptions
in integrations, which could cause issues like #1071.

Solves #642.

* Remove ActiveJob::DeserializationError from ignored list

Since the previous commit solves #642, this commit can remove
ActiveJob::DeserializationError from the ignored exceptions list.

Solves #1071.

* Update async document

* Update changelog

* Make sentry-rails a Rails engine and provide default job class for async (#1181)

* Make sentry-rails a Rails engine too

* Add Sentry::SendEventJob

Instead of letting users defining their SentryJob class, we should
provide a default job class for them.

* Update document and example for the new job class

* Update changelog

* Add configuration option for trusted proxies (#1126)

* Add configuration option for trusted proxies

* Add `trusted_proxies` configuration option to sentry-ruby
* Add existing ActionDispatch `trusted_proxies` values

* Address some PR feedback

* Isolate trusted proxy test configuration
* Add comments to explain why we reverse the forwarded_for ip list
* Call `uniq` on the trusted proxy list
* Rename `filter_local_addresses(ips) to filter_trusted_proxy_addresses(ips)

* Remove duplicated hash entry

* Update some tests after PR feedback

* retrigger checks

Co-authored-by: Stan Lo <stan001212@gmail.com>

* Only define SendEventJob when ActiveJob is defined

* Allow users to configure ActiveJob adapters to ignore (#1256)

* Allow users to configure ActiveJob adapters to ignore

* Update changelog

* Add sidekiq adapter to sentry-rails' ignored adapters list (#1257)

* Add sidekiq adapter to sentry-rails' ignored adapters list

* Update changelog

* Tag queue name and jid on sidekiq events (#1258)

* Add queue name and jid to event tags

* Update changelog

* Tag job_id and provider_job_id on ActiveJob events (#1259)

* Refactor/test ActiveJob's context data

* Tag job_id and provider_job_id on ActiveJob events

* Update changelog

* Add ability to have many post initialization callbacks (#1261)

* Add ability to have many post initialization callbacks

* Revert version bumping, fix codestyle and rewrite rspec test

* Remove dependenciy bumping from sentry-sidekiq

* Add entries to CHANGELOG

* Support config.before_breadcrumb (#1253)

* Support config.before_breadcrumb

Example:

```
config.before_breadcrumb = lambda do |breadcrumb, hint|
  breadcrumb.message = "foo"
  breadcrumb
end
```

* Update changelog

* Update sentry-ruby's changelog

* Update sentry-rails' changelog

* Update sentry-sidekiq's changelog

* Rename ignored_active_job_adapters to skippable_job_adapters (#1264)

* Update sentry-ruby's changelog

Co-authored-by: Jon-Erik Schneiderhan <45184220+jeschneiderhan@users.noreply.github.com>
Co-authored-by: Valentine Kiselev <mrexox@outlook.com>
st0012 added a commit that referenced this pull request Feb 3, 2021
* Add configuration option for trusted proxies

* Add `trusted_proxies` configuration option to sentry-ruby
* Add existing ActionDispatch `trusted_proxies` values

* Address some PR feedback

* Isolate trusted proxy test configuration
* Add comments to explain why we reverse the forwarded_for ip list
* Call `uniq` on the trusted proxy list
* Rename `filter_local_addresses(ips) to filter_trusted_proxy_addresses(ips)

* Remove duplicated hash entry

* Update some tests after PR feedback

* retrigger checks

Co-authored-by: Stan Lo <stan001212@gmail.com>
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