diff --git a/app/authzed/guides/setting-up-private-networking/page.mdx b/app/authzed/guides/setting-up-private-networking/page.mdx index ee1a773..9a42939 100644 --- a/app/authzed/guides/setting-up-private-networking/page.mdx +++ b/app/authzed/guides/setting-up-private-networking/page.mdx @@ -114,30 +114,30 @@ Most users of AuthZed Dedicated on GCP privately connect to SpiceDB with GCP [Pr 1. Navigate to “Private Service Connect” and make sure you are on the “Connected Endpoints” tab. 1. Click “Connect Endpoint” - | Option | Selection | - |------------------------|------------------------------------------------| - | Target | “Published service” | - | Target service | This will be provided to you by Authzed | - | Endpoint name | Name this whatever you want | - | Network and subnetwork | Select the networks you need connectivity from | - | IP address | Choose whatever IP you'd like | + | Option | Selection | + | ---------------------- | ---------------------------------------------- | + | Target | “Published service” | + | Target service | This will be provided to you by Authzed | + | Endpoint name | Name this whatever you want | + | Network and subnetwork | Select the networks you need connectivity from | + | IP address | Choose whatever IP you'd like | ### Enable DNS 1. Navigate to Cloud DNS and create a zone - | Option | Selection | - |-----------|---------------------------------------------------------------------------| - | Zone type | private | - | DNS Name | This will be provided to you by Authzed | - | Networks | Select the network where the Private Service Connect endpoint is deployed | + | Option | Selection | + | --------- | ------------------------------------------------------------------------- | + | Zone type | private | + | DNS Name | This will be provided to you by Authzed | + | Networks | Select the network where the Private Service Connect endpoint is deployed | 1. Add record set - | Option | Selection | - |------------|------------------------------------------------| - | DNS name | This will be provided to you by Authzed | - | IP address | Enter your Private Service Connect endpoint IP | + | Option | Selection | + | ---------- | ---------------------------------------------- | + | DNS name | This will be provided to you by Authzed | + | IP address | Enter your Private Service Connect endpoint IP | ### Add Permission System @@ -150,15 +150,15 @@ Most users of AuthZed Dedicated on GCP privately connect to SpiceDB with GCP [Pr Verify connectivity from client machine with the [Zed CLI tool](https://github.com/authzed/zed) -``` zed +```zed zed context set permission_system_name example.com:443 sdbst_h256_123 ``` -``` zed +```zed zed schema write example.yaml ``` -``` zed +```zed zed schema read ``` diff --git a/app/spicedb/concepts/_meta.ts b/app/spicedb/concepts/_meta.ts index b4dc96d..b9120ee 100644 --- a/app/spicedb/concepts/_meta.ts +++ b/app/spicedb/concepts/_meta.ts @@ -4,6 +4,7 @@ export default { relationships: "Writing Relationships", caveats: "Writing Relationships with Caveats", "expiring-relationships": "Writing Relationships that Expire", + "querying-data": "Querying Data", commands: "SpiceDB Commands & Parameters", consistency: "Consistency", datastores: "Datastores", diff --git a/app/spicedb/concepts/commands/page.mdx b/app/spicedb/concepts/commands/page.mdx index 8fd57da..e41f4eb 100644 --- a/app/spicedb/concepts/commands/page.mdx +++ b/app/spicedb/concepts/commands/page.mdx @@ -27,13 +27,12 @@ A database that stores and computes permissions ### Children commands -- [spicedb datastore](#reference-spicedb-datastore) - datastore operations -- [spicedb lsp](#reference-spicedb-lsp) - serve language server protocol -- [spicedb man](#reference-spicedb-man) - Generate man page -- [spicedb serve](#reference-spicedb-serve) - serve the permissions database -- [spicedb serve-testing](#reference-spicedb-serve-testing) - test server with an in-memory datastore -- [spicedb version](#reference-spicedb-version) - displays the version of SpiceDB - +- [spicedb datastore](#reference-spicedb-datastore) - datastore operations +- [spicedb lsp](#reference-spicedb-lsp) - serve language server protocol +- [spicedb man](#reference-spicedb-man) - Generate man page +- [spicedb serve](#reference-spicedb-serve) - serve the permissions database +- [spicedb serve-testing](#reference-spicedb-serve-testing) - test server with an in-memory datastore +- [spicedb version](#reference-spicedb-version) - displays the version of SpiceDB ## Reference: `spicedb datastore` @@ -49,11 +48,10 @@ Operations against the configured datastore ### Children commands -- [spicedb datastore gc](#reference-spicedb-datastore-gc) - executes garbage collection -- [spicedb datastore head](#reference-spicedb-datastore-head) - compute the head (latest) database migration revision available -- [spicedb datastore migrate](#reference-spicedb-datastore-migrate) - execute datastore schema migrations -- [spicedb datastore repair](#reference-spicedb-datastore-repair) - executes datastore repair - +- [spicedb datastore gc](#reference-spicedb-datastore-gc) - executes garbage collection +- [spicedb datastore head](#reference-spicedb-datastore-head) - compute the head (latest) database migration revision available +- [spicedb datastore migrate](#reference-spicedb-datastore-migrate) - execute datastore schema migrations +- [spicedb datastore repair](#reference-spicedb-datastore-repair) - executes datastore repair ## Reference: `spicedb datastore gc` @@ -148,8 +146,6 @@ spicedb datastore gc [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb datastore head` compute the head (latest) database migration revision available @@ -181,8 +177,6 @@ spicedb datastore head [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb datastore migrate` Executes datastore schema migrations for the datastore. @@ -222,8 +216,6 @@ spicedb datastore migrate [revision] [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb datastore repair` Executes a repair operation for the datastore @@ -317,8 +309,6 @@ spicedb datastore repair [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb lsp` serve language server protocol @@ -342,12 +332,10 @@ spicedb lsp [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb man` Generate a man page for SpiceDB. - The output can be redirected to a file and installed to the system: +The output can be redirected to a file and installed to the system: ``` spicedb man > spicedb.1 @@ -355,7 +343,6 @@ Generate a man page for SpiceDB. sudo mandb # Update man page database ``` - ``` spicedb man ``` @@ -368,8 +355,6 @@ spicedb man --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb serve` start a SpiceDB server @@ -558,8 +543,6 @@ spicedb serve [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb serve-testing` An in-memory spicedb server which serves completely isolated datastores per client-supplied auth token used. @@ -621,8 +604,6 @@ spicedb serve-testing [flags] --skip-release-check if true, skips checking for new SpiceDB releases ``` - - ## Reference: `spicedb version` displays the version of SpiceDB @@ -644,6 +625,3 @@ spicedb version [flags] --log-level string verbosity of logging ("trace", "debug", "info", "warn", "error") (default "info") --skip-release-check if true, skips checking for new SpiceDB releases ``` - - - diff --git a/app/spicedb/concepts/querying-data/page.mdx b/app/spicedb/concepts/querying-data/page.mdx new file mode 100644 index 0000000..6299d6d --- /dev/null +++ b/app/spicedb/concepts/querying-data/page.mdx @@ -0,0 +1,167 @@ +import { Callout } from "nextra/components"; + +# Querying Data + +This page walks through the main ways to query data in SpiceDB. The options are listed roughly in the order of how often you should be calling them, and roughly in order of their expected performance. Choose the one that makes sense for your use case, but consider whether your use case actually requires the call you're looking at. + + + In most of the APIs below, if you want to be able to read your write, you can + pass a `consistency` parameter to the queries. Use either `fully_consistent` + or `at_least_as_fresh(revision)` depending on how strict you need to be. See + [Consistency](consistency) for more details. + + + + When invoking any of our APIs, you can send a header `X-Request-ID=somevalue` + and it will be echoed back in the response, which makes correlating logs or + tracing requests easy. + + +## Check Permission + +Send: + +- Subject Type +- Subject ID +- Permission (or relation) +- Object Type +- Object ID + +Receive: + +- Yes/no (or a provisional response if missing caveat data) + +[`CheckPermission`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.CheckPermission) is the go-to for most access checks. It’s designed for high-traffic workloads. + +You can debug a check locally with `zed permission check resource:someresource somepermission user:someuser --explain` to understand how the decision was made. + +When your schema uses [caveats](caveats) and you don't provide all the required context in the request parameters, the API will tell you that in the response that the result is "conditional" instead of simply denying or allowing, and it's up to you to inspect that result. + +The `subject` of the query can be a single user (e.g. `user:someuser`) or a set of users (e.g. `group:engineering#member`). + +### CheckBulkPermissions + +Send Many: + +- Subject Type +- Subject ID +- Permission (or relation) +- Object Type +- Object ID + +Receive Many: + +- Yes/no (or a provisional response if missing caveat data) + +If your app needs to do multiple checks (for example, for various subjects), use the [`CheckBulkPermissions`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.CheckBulkPermissions) API. It's great for UI workloads where you need to check multiple permissions at once: think tables, lists, and dashboards. + +It's also the recommended way to ask "what permissions does a given subject have on a resource?" +Make a check for each permission in your schema. This will require you to update calling code when you add permissions, +but the consuming code will need to be changed to include the logic associated with the new permission in any case. + +It's always preferable to perform one call to `CheckBulkPermissions` with N checks than N calls to `CheckPermission`, unless you don't want to wait for the N checks to finish. + +## LookupResources + +Send Many: + +- Subject Type +- Subject ID +- Permission (or relation) +- Object Type + +Receive many: + +- Object ID + +[`LookupResources`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.LookupResources) is a good choice when you need to find all resources of a given type that a specific subject can access. It supports cursoring and works well for moderate result sizes. + +It's a good way to do [prefiltering of results](/spicedb/modeling/protecting-a-list-endpoint#filtering-with-lookupresources) in +a List endpoint, but it's a heavy request that can cause performance problems when more than 10k results are involved. +In that case we recommend postfiltering with [CheckBulk](#checkbulkpermissions), and if that still doesn't work, +we recommend evaluating [Materialize](/authzed/concepts/authzed-materialize). + +## LookupSubjects + +Send Many: + +- Subject Type +- Permission (or relation) +- Object Type +- Object ID + +Receive many: + +- Subject ID + +[`LookupSubjects`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.LookupSubjects) returns +all subjects that have access to a specific resource. It does not support cursoring. + +It's commonly used to drive UIs and APIs that list users with given permission or set of permissions, such as a table of Admins +on a particular Organization. + +Note that LookupSubjects will do a full path walk between an object and a subject, and will consider all valid paths between object and subject. +If you are looking to find all the subjects that are on a specific relation, use `ReadRelationships` instead of `LookupSubjects`. + +If your schema includes exclusions and wildcards, the response can include a list of subjects that have been explicitly excluded. + +For example, if the schema is + +```zed +definition user {} + +definition document { + relation blocked: user + relation view: user:* + permission viewer = view - blocked +} +``` + +and the relationships are + +```relationship filename="Relationships" +document:finance#view@user:* +document:finance#blocked@user:anne +document:finance#blocked@user:bob +``` + +Then `LookupSubjects` for `document:finance` will return a response of the form `{user:* - [user:anne,user:bob]}`. + +## ReadRelationships + +[`ReadRelationships`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.ReadRelationships) is intended a an escape hatch, +and should only be considered if no other API matches your use case. + +It's considerably more flexible in that you can send any combination of: + +- Subject Type +- Subject ID +- Permission (or relation) +- Object Type +- Object ID + +And receive all relationships that match that filter, but it comes with some important caveats: + +- It's generally less optimized than the `Check` and `Lookup` APIs because of that flexibility +- It does no caching. The `Check` and `Lookup` APIs gain much of their performance by caching the results of subproblem computation; `ReadRelationships` does no caching and will go directly to the database every time. +- The indexes in the backing [datastores](/spicedb/concepts/datastores) are optimized around the `Check` and `Lookup` APIs, so it's possible to + craft a `ReadRelationships` request that misses indexes and requires a full table scan. This is because covering all combinations of filters + with an index would impact write performance too much. + +Some use cases where `ReadRelationships` may be warranted: + +- Deleting all relationships in a subtree, where a simple [RelationshipFilter](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.RelationshipFilter) in a [DeleteRelationships](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.DeleteRelationshipsRequest) would be insufficient +- Admin UIs that show lists of roles or relationships between objects + +## Watch + +The Watch API is not meant to answer permission questions but to serve other use-cases, like auditing. See [the Watch API documentation](/spicedb/concepts/watch) for more details. + +## ExpandPermissionTree + +This [ExpandPermissionTree](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.ExpandPermissionTree) API +comes from the [Zanzibar Paper](https://authzed.com/zanzibar#2.4.5-expand). It allows you to examine the subtree of relationships +around a particular point in the graph, and is useful in scenarios like your UI needing to show which users _and groups_ have access to something. + +In practice we don't see many uses of this API, especially because it only resolves one "hop" in the graph at a time and must be called +repeatedly to get a full picture of a subtree. diff --git a/app/spicedb/getting-started/faq/page.mdx b/app/spicedb/getting-started/faq/page.mdx index 6fabf2a..421645f 100644 --- a/app/spicedb/getting-started/faq/page.mdx +++ b/app/spicedb/getting-started/faq/page.mdx @@ -60,6 +60,14 @@ Choose based on your scale: start with LookupResources, move to CheckBulkPermiss [Learn more]: ../modeling/protecting-a-list-endpoint +## How do I get all of the permissions a subject has on a resource? + +There isn't an API that answers this question directly. Instead, you should use the +[`CheckBulkPermissions`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.CheckBulkPermissions) API and send a check for each of the permissions you want to check. + +It means that you'll need to update your permission checks when you add a new permission, but you'd need to update the calling code +to handle the concept that a new permission represents anyway. + ## How can I get involved with SpiceDB? The best first step is to join [Discord]. diff --git a/app/spicedb/getting-started/first-steps/page.mdx b/app/spicedb/getting-started/first-steps/page.mdx index 24d52a7..8fc3dca 100644 --- a/app/spicedb/getting-started/first-steps/page.mdx +++ b/app/spicedb/getting-started/first-steps/page.mdx @@ -22,9 +22,9 @@ import { InlinePlayground } from "@/components/playground"; We've documented the concepts SpiceDB users should understand: - + After these, we recommend these concepts for running SpiceDB: diff --git a/app/spicedb/modeling/protecting-a-list-endpoint/page.mdx b/app/spicedb/modeling/protecting-a-list-endpoint/page.mdx index 42d3139..f66bdce 100644 --- a/app/spicedb/modeling/protecting-a-list-endpoint/page.mdx +++ b/app/spicedb/modeling/protecting-a-list-endpoint/page.mdx @@ -14,20 +14,16 @@ and SpiceDB and combining the queries into a response. Broadly speaking, there are three ways to do this: -- filtering with [LookupResources] -- checking with [CheckBulkPermissions] +- filtering with [`LookupResources`] +- checking with [`CheckBulkPermissions`] - using [Authzed Materialize] to create a denormalized local view of a user's permissions. Which one you choose will depend on whether the set of accessible resources is much larger than a page of results returned by your API, in addition to the overall size of your data. -[LookupResources]: https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.LookupResources -[CheckBulkPermissions]: https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.CheckBulkPermissions -[Authzed Materialize]: https://authzed.com/products/authzed-materialize - ## Filtering with LookupResources -If the number of resources that a user has access to is sufficiently small, you can use `LookupResources` to get the full +If the number of resources that a user has access to is small (e.g. less than 10,000 resources), you can use the [`LookupResources`] API to get the full list of resources for which a user has a particular permission, and then use that as a filtering clause in your database query. In python pseudocode: @@ -44,14 +40,13 @@ WHERE id = ANY(ARRAY[]) ``` This is the simplest approach from a bookkeeping perspective and is a good place to start. -It should be noted that `LookupResources` can get heavy quickly - with a sufficiently large relation dataset, +It should be noted that [`LookupResources`] can get slow quickly: with a sufficiently large relation dataset, a sufficiently complex schema, or a sufficiently large set of accessible results, you'll need to take a different approach. ## Checking with CheckBulkPermissions -If the number of resources that a user has access to is sufficiently large and `LookupResources` can't satisfy the use case -anymore, another approach is to fetch a page of results and then call `CheckBulkPermissions` to determine which of the -resources are accessible to the user. +If the number of resources that a user has access to is sufficiently large and [`LookupResources`] can't satisfy the use case +anymore, another approach is to fetch a page of resources from your database, and then call [`CheckBulkPermissions`] on those resources to determine which of them are accessible to the user. In python pseudocode: ```python @@ -85,9 +80,9 @@ This approach is handy for search interfaces since the filters on a search can r to the point where checking them via bulk check is relatively easy. - It's recommended to run the various CheckBulkPermissions API calls at the same - revision to get a consistent view of the permissions. (e.g. take the ZedToken - from the first call, and use it in all subsequent calls) + It's recommended to run the various [`CheckBulkPermissions`] API calls at the + same revision to get a consistent view of the permissions. (i.e. take the + ZedToken from the first call, and use it in all subsequent calls). ## Using Materialize @@ -123,3 +118,7 @@ There's a difference between "data exists but the user isn't allowed to see it" In a coarse-grained authorization system, it may make sense to return a 403 as a response from a list endpoint to indicate that the user cannot access anything. In a fine-grained authorization system backed by SpiceDB, it often makes sense to treat "there is no data" and "there is nothing you're authorized to see" as the same, by returning a successful response with an empty result set. + +[`LookupResources`]: https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.LookupResources +[`CheckBulkPermissions`]: https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.CheckBulkPermissions +[Authzed Materialize]: https://authzed.com/products/authzed-materialize