-
Notifications
You must be signed in to change notification settings - Fork 59
use pool_authorized() for all lookups #873
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
Conversation
} else { | ||
// If the user did not authenticate successfully, this will | ||
// become a 401 rather than a 403. | ||
Err(if !is_authn { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a small but important change.
Prior to this, if you failed an authz check, the logic went like this:
- Pick a "fallback" error to signify "you didn't have permissions to do this". This would be 401 if you were unauthenticated and 403 if you're authenticated.
- Check with the resource impl (via the call to
on_unauthorized
at L109). The only interesting impl is this one, which is used for most API resources. Pass the fallback error, but return whatever the resource says to return.
The intent of the on_unauthorized
call is to determine if you're allowed to even know this resource exists. If so, the "fallback error" (401 or 403) is fine. If not, return a 404 instead. The on_unauthorized
impl I linked above is what actually does this.
After this change, the 401 always takes precedence. If you fail the authz check and you're not authenticated, you always get a 401 -- we don't invoke on_unauthorized()
at all. If you're authenticated, then we do the same as before: 403 if you're allowed to read the resource, 404 otherwise.
This change isn't strictly necessary. I did this for consistency of the public API. If we just change lookups to use pool_authorized()
, then all the endpoints that do a lookup behave this way without this change here. But the endpoints that don't do lookups for whatever reason (see #845) would still return 404s in some cases for unauthenticated users that fail an authz check. I thought it better to put this logic here for consistency. If you ever add a new endpoint (whether it hits the database or not), and the user fails an authz check, and they're not authenticated, they'll get a 401, instead of having it be dependent on how the endpoint was implemented.
In case it's helpful, here's the output for the "unauthorized" test showing the new behavior:
and here's the diff -- unfortunately it's a column that changed, so nearly every line changed, and I'm not sure how to most usefully show that:
The best I know how to do is show |
Crucible changes are: Make `ImpactedBlocks` an absolute range (#1685) update omicron (#1687) Update Rust crate chrono to v0.4.40 (#1682) Update Rust crate tempfile to v3.19.0 (#1676) Log loops during crutest replay (#1674) Refactor live-repair start and send (#1673) Update Rust crate libc to v0.2.171 (#1684) Update Rust crate clap to v4.5.32 (#1683) Update Rust crate async-trait to 0.1.88 (#1680) Update Rust crate bytes to v1.10.1 (#1681) Update Rust crate anyhow to v1.0.97 (#1679) Update Rust crate http to v1 (#1678) Update Rust crate tokio-util to v0.7.14 (#1675) Update Rust crate thiserror to v2 (#1657) Update Rust crate omicron-zone-package to 0.12.0 (#1647) Update Rust crate opentelemetry to 0.28.0 (#1543) Update Rust crate itertools to 0.14.0 (#1646) Update Rust crate clearscreen to v4 (#1656) nightly test polish (#1665) Update Rust crate strum_macros to 0.27 (#1654) Update Rust crate strum to 0.27 (#1653) Update Rust crate rusqlite to 0.34 (#1652) Better return semantics from should_send Trying to simplify enqueue Remove unnecessary argument Remove unused code from `ImpactedBlocks` (#1668) Log when pantry/volume layers activate things (#1670) Fix unused import (#1669) Use `RangeSet` instead of tracking every complete job (#1663) Update Rust crate dropshot to 0.16.0 (#1645) Simplify pending work tracking (#1662) Remove rusqlite dependency from crucible-common (#1659) Update Rust crate reedline to 0.38.0 (#1651) Update Rust crate proptest to 1.6.0 (#1648) Update Rust crate bytes to v1.10.0 (#1644) Update Rust crate tracing-subscriber to 0.3.19 (#1643) Update Rust crate tracing to v0.1.41 (#1642) Update Rust crate toml to v0.8.20 (#1641) Update Rust crate thiserror to v1.0.69 (#1640) Update Rust crate serde_json to v1.0.139 (#1639) Update Rust crate serde to v1.0.218 (#1638) Update Rust crate reqwest to v0.12.12 (#1637) Update Rust crate libc to v0.2.170 (#1636) Update Rust crate indicatif to 0.17.11 (#1635) Update Rust crate httptest to 0.16.3 (#1634) Update Rust crate clap to v4.5.31 (#1632) Update Rust crate chrono to v0.4.39 (#1631) Update Rust crate byte-unit to 5.1.6 (#1630) Update Rust crate async-trait to 0.1.86 (#1629) Update Rust crate csv to 1.3.1 (#1633) Update Rust crate anyhow to v1.0.96 (#1628) Fix a test flake (#1626) Bitpack per-block slot data in memory (#1625) Use `div_ceil` instead of `(x + 7) / 8` (#1624) Add repair server dynamometer (#1618) Propolis changes are: Paper over minor() differences Update crucible (#886) Test oximeter metrics end to end (#855) server: improve behavior of starting VMs that are waiting for Crucible activation (#873) server: extend API request queue's memory of prior requests (#880) Use production propolis-server flags in PHD CI builds (#878) Added a new field to the Board struct that propolis requires.
Crucible changes are: Make `ImpactedBlocks` an absolute range (#1685) update omicron (#1687) Update Rust crate chrono to v0.4.40 (#1682) Update Rust crate tempfile to v3.19.0 (#1676) Log loops during crutest replay (#1674) Refactor live-repair start and send (#1673) Update Rust crate libc to v0.2.171 (#1684) Update Rust crate clap to v4.5.32 (#1683) Update Rust crate async-trait to 0.1.88 (#1680) Update Rust crate bytes to v1.10.1 (#1681) Update Rust crate anyhow to v1.0.97 (#1679) Update Rust crate http to v1 (#1678) Update Rust crate tokio-util to v0.7.14 (#1675) Update Rust crate thiserror to v2 (#1657) Update Rust crate omicron-zone-package to 0.12.0 (#1647) Update Rust crate opentelemetry to 0.28.0 (#1543) Update Rust crate itertools to 0.14.0 (#1646) Update Rust crate clearscreen to v4 (#1656) nightly test polish (#1665) Update Rust crate strum_macros to 0.27 (#1654) Update Rust crate strum to 0.27 (#1653) Update Rust crate rusqlite to 0.34 (#1652) Better return semantics from should_send Trying to simplify enqueue Remove unnecessary argument Remove unused code from `ImpactedBlocks` (#1668) Log when pantry/volume layers activate things (#1670) Fix unused import (#1669) Use `RangeSet` instead of tracking every complete job (#1663) Update Rust crate dropshot to 0.16.0 (#1645) Simplify pending work tracking (#1662) Remove rusqlite dependency from crucible-common (#1659) Update Rust crate reedline to 0.38.0 (#1651) Update Rust crate proptest to 1.6.0 (#1648) Update Rust crate bytes to v1.10.0 (#1644) Update Rust crate tracing-subscriber to 0.3.19 (#1643) Update Rust crate tracing to v0.1.41 (#1642) Update Rust crate toml to v0.8.20 (#1641) Update Rust crate thiserror to v1.0.69 (#1640) Update Rust crate serde_json to v1.0.139 (#1639) Update Rust crate serde to v1.0.218 (#1638) Update Rust crate reqwest to v0.12.12 (#1637) Update Rust crate libc to v0.2.170 (#1636) Update Rust crate indicatif to 0.17.11 (#1635) Update Rust crate httptest to 0.16.3 (#1634) Update Rust crate clap to v4.5.31 (#1632) Update Rust crate chrono to v0.4.39 (#1631) Update Rust crate byte-unit to 5.1.6 (#1630) Update Rust crate async-trait to 0.1.86 (#1629) Update Rust crate csv to 1.3.1 (#1633) Update Rust crate anyhow to v1.0.96 (#1628) Fix a test flake (#1626) Bitpack per-block slot data in memory (#1625) Use `div_ceil` instead of `(x + 7) / 8` (#1624) Add repair server dynamometer (#1618) Propolis changes are: Paper over minor() differences Update crucible (#886) Test oximeter metrics end to end (#855) server: improve behavior of starting VMs that are waiting for Crucible activation (#873) server: extend API request queue's memory of prior requests (#880) Use production propolis-server flags in PHD CI builds (#878) --------- Co-authored-by: Alan Hanson <[email protected]>
Recall that the
DataStore
has two methods for getting a database connection:pool()
andpool_authorized(opctx: &OpContext)
. The latter checks whether the caller is even allowed to query the database. All authenticated users have this permission, so it's kind of silly. But this seemed useful as a belt-and-suspenders way to ensure that if we accidentally add some unauthenticated code path, an attacker can't use this to trivially DoS the database. We should eventually be usingpool_authorized()
everywhere and rip outpool()
altogether. Right now, lookups usepool()
, only for historical reasons. It's time to switch these to usepool_authorized(opctx)
.This changes some failure modes for unauthenticated users! Previously, if an unauthenticated user tried to fetch, say,
/organizations/foo
, they would have gotten a 404. Same if they tried to update or delete it. That's because we'd look up the resource, find they didn't have read access, and send a 404. To be clear, I think that behavior remains reasonable. But with this change, we're kicking them out before even doing the lookup. I think that's also reasonable. From some casual research, it seems that people often advocate for using 401 when there's any authz error and no credentials were provided, so we're consistent with expectations there. This is also what our own docs/http-status-codes.adoc says.This is especially relevant when we get to Silos. Once we do #850, it won't even be possible to do the lookup without credentials, so it makes sense to kick the request out quickly in that case -- and with a 401.