From 3b7e6f1a6b165ceaff79c280f079053ea79e5931 Mon Sep 17 00:00:00 2001 From: adinhodovic Date: Tue, 13 May 2025 17:04:05 -0400 Subject: [PATCH 01/11] docs(spicedb): Add best practises --- pages/spicedb/_meta.json | 3 +- pages/spicedb/best-practices/_meta.json | 3 + .../spicedb/best-practices/best-practices.mdx | 237 ++++++++++++++++++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 pages/spicedb/best-practices/_meta.json create mode 100644 pages/spicedb/best-practices/best-practices.mdx diff --git a/pages/spicedb/_meta.json b/pages/spicedb/_meta.json index 6da5a260..542a66f1 100644 --- a/pages/spicedb/_meta.json +++ b/pages/spicedb/_meta.json @@ -4,5 +4,6 @@ "modeling": "Modeling & Integrating", "ops": "Operations", "api": "API Reference", - "links": "Links" + "links": "Links", + "best-practices": "Best Practices" } diff --git a/pages/spicedb/best-practices/_meta.json b/pages/spicedb/best-practices/_meta.json new file mode 100644 index 00000000..3ff44db0 --- /dev/null +++ b/pages/spicedb/best-practices/_meta.json @@ -0,0 +1,3 @@ +{ + "best-practices": "Best Practices" +} diff --git a/pages/spicedb/best-practices/best-practices.mdx b/pages/spicedb/best-practices/best-practices.mdx new file mode 100644 index 00000000..4cd1d716 --- /dev/null +++ b/pages/spicedb/best-practices/best-practices.mdx @@ -0,0 +1,237 @@ +# Best Practises + +### Rule Categories + +#### Priority A: Essential + +The essential rules are the most important ones. Use them to ensure that your SpiceDB cluster is performant, your schema is sane, and your authorization logic is sound. Exceptions to these rules should be rare and well justified. + +#### Priority B: Strongly Recommended + +The strong recommendation rules will improve the schema design, developer experience, and performance of your SpiceDB cluster. In most cases, these rules should be followed. + +#### Priority C: Recommended + +The recommended rules reflect how we would run our own systems, but may not apply to every use case and may not make sense in every situation. Follow them if you can and ignore them if you can’t. + +### Priority A Rules: Essential + +#### Don’t truncate your tables when running Postgres + +Tags: **operations** + +If you truncate your Postgres table, your SpiceDB instances will become unresponsive until you run spicedb datastore repair. We recommend either dropping the tables entirely and recreating them with spicedb datastore migrate head or deleting the data using a DeleteRelationships call instead. + +To ensure that every request, whether cached or not, gets a consistent point-in-time view of the underlying data, SpiceDB uses Multi-Version Concurrency Control. Some datastores provide this natively; in others we’ve implemented it on top of the datastore. In Postgres, the implementation of MVCC depends on the internals of the transaction counter being stored as data in the tables, so if you truncate the relationships table you desync the transaction counter with the stored relationships. + +#### Tune Connections to Datastores + +Tags: **operations** + +To size your SpiceDB connection pools, start by determining the maximum number of allowed connections based on the documentation for your selected datastore, divide that number by the number of SpiceDB pods you’ve deployed, then split it between read and write pools. + +Use these values to set the --datastore-conn-pool-read-max-open and --datastore-conn-pool-write-max-open flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. + +#### Test Your Schema + +Tags: **schema** + +You should be testing the logic of your schema to ensure that it behaves the way you expect. +- For unit testing and TDD, use test relations + assertions and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). +- For snapshot testing, use test relations + expected relations and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). +- For integration testing, use the SpiceDB test server with spicedb [serve-testing](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#integration-test-server). + +#### Prefer Relations to Caveats + +Tags: **schema** + +If an authorization concept can be expressed using relations, it should be. We provide caveats as an escape hatch; they should only be used for context that’s only available at request time, or else ABAC logic that cannot be expressed in terms of relationships. + +Some examples: +- A banlist - this could be expressed as a list in caveat context, but it can also be expressed as a relation with negation. +- A notion of public vs internal - boolean flags seem like an obvious caveat use case, but they can also be expressed using self relations. +- Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a spicedb schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. + +This is because caveats come with a performance penalty. A caveated relationship is both harder to cache and also slows down computation of the graph walk required to compute a permission. + +#### Make sure your schema fails closed + +Tags: **schema** + +This is related to the idea of using negation sparingly, and of phrasing your schema additively. Give thought to what happens if your application fails to write a relation: should the user have access in that case? The answer is almost always `no`. + +#### Make Your Writes Idempotent + +Tags: **application** + +Relations in SpiceDB are binary (a relation is present or it’s not), and WriteRelationships calls are atomic. As much as possible, we recommend that you use the TOUCH semantic for your write calls, because it means that you can easily retry writes and recover from failures. + +If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using preconditions. + +### Priority B Rules: Strongly Recommended + +#### Understand your consistency needs + +Tags: **operations** + +While designing your authorization, it’s important to plan ahead for how quickly an update is guaranteed, while trading off performance via cache effectiveness. By default, SpiceDB sets the Quanitzation Interval to 5s; check operations are cached within this window. To change this value, set `--datastore-revision-quantization-interval` longer or shorter. + +When it comes to write consistency, SpiceDB defaults to high safety, especially in distributed database writing scenarios, guaranteeing a visibility order. Individual datastores may also allow a relaxation of this guarantee, based on your scenario; for example, [setting CockroachDB’s overlap strategy](https://authzed.com/docs/spicedb/concepts/datastores#overlap-strategy), trading some authorization visibility safety across domains for greatly increased write throughput. + +#### Keep Permission Logic in SpiceDB + +Tags: **schema** + +One of the big benefits to using a centralized authorization system like SpiceDB is that there’s one place to look for your authorization logic, and authorization logic isn’t duplicated across services. It can be tempting to define the authorization logic for an endpoint as being the AND or OR of the checks of other permissions, especially when the alternative is writing a new schema. However, this increases the likelihood of drift across your system, hides the authorization logic for a system in that system’s codebase, and increases the load on SpiceDB. + +#### Avoid Cycles in your Schema + +Tags: **schema** + +Recursive schemas can be very powerful, but can also lead to large performance issues when used incorrectly. A good rule of thumb is, if you need a schema definition to recur, have it refer to itself (eg, groups can have subgroups). Avoid situations where a definition points to a separate definition that, further down the permission chain, points to the original definition by accident. + +Avoid: + +```zed +definition user { + relation org: organization +} + +definition group { + relation member: user +} + +definition organization { + relation subgroup: group +} +``` + +Preferred: + +```zed +definition user {} + +definition group { + relation member: user | group +} +``` + +#### Phrase Permissions Additively/Positively + +Tags: **schema** + +A more comprehensible permission system is a more secure permission system. One of the easiest ways to maintain your authorization logic is to treat permissions as `positive` or `additive`: a user gains permissions when relations are written. This reduces the number of ways that permission logic can interact, and prevents the granting of permission accidentally. + +In concrete terms, that means use wildcards and negations sparingly. Start with no access and build up; don’t start with full access and pare down. + +#### Use GRPC When Possible + +Tags: **application** + +SpiceDB can be configured to expose both an [HTTP API](https://authzed.com/docs/spicedb/getting-started/client-libraries#http-clients) and associated Swagger documentation. While this can be helpful for initial exploration, we strongly recommend using one of our gRPC-based official client libraries if your networking and calling language support it. gRPC is significantly more performant and lower-latency than HTTP, and client-streaming services like ImportBulk can’t be used with the HTTP API. + +#### Use Unique Identifiers for Object Identifiers + +Tags: **application** + +Because you typically want to centralize your permissions in SpiceDB, that also means that most of the IDs of objects in SpiceDB are references to external entities. These external entities shouldn’t overlap. To that end, we recommend either using UUIDs or using another identifier from the upstream that you can be sure will be unique, such as the unique sub field assigned to a user token by your IDP. + +#### Avoid ReadRelationships API + +Tags: **application** + +The ReadRelationships API should be treated as an escape hatch, used mostly for data introspection. Using it for permission logic is a code smell. All checks and listing of IDs should use Check, CheckBulk, LookupResources, and LookupSubjects. If you find yourself reaching for the ReadRelationships API for permission logic, there’s probably a way to modify your schema to use one of the check APIs instead. + +#### Prefer CheckBulk To LookupResources + +Tags: **application** + +Both CheckBulk and LookupResources can be used to determine whether a subject has access to a list of objects. Where possible, we recommend CheckBulk, because its work is bounded to the list of requested checks, whereas the wrong LookupResources call can return the entire world and choke both your datastore and your client. + +LookupResources generally requires a lot of work, causes a higher load, and subsequently has some of the highest latencies. If you need its semantics but its performance is insufficient, we recommend checking out our [Materialize](https://authzed.com/products/authzed-materialize) offering. + +### Priority C Rules: Recommended + +#### Enable schema watch cache + +Tags: **operations** + +In order to minimize load on the database, you can enable schema watch cache using the flag `-enable-experimental-watchable-schema-cache`. The schema watch cache is a mechanism that improves performance and responsiveness by caching the currently loaded schema and watching for changes in real time. + +For postgres `track_commit_timestamp` must be set to `on` for the Watch API to be enabled. + +#### Load Test + +Tags: **operations** + +To evaluate the performance and capabilities of your SpiceDB cluster and its underlying datastore, AuthZed provides [Thumper](https://github.com/authzed/thumper) — a load testing tool. You can use Thumper to simulate workloads and validate schema updates before deploying them to a production environment. + +#### Treat Writing Schema like Writing DB Migrations + +Tags: **operations** + +We recommend treating your SpiceDB schema as though it were a database migration. Keep it in your codebase, test it before deployment, and write it to your SpiceDB cluster as a part of your continuous integration process. This ensures that updates to your schema are properly controlled. + +#### Use the Operator + +Tags: **operations** + +To ensure seamless rollouts, upgrades, and schema migrations, it is recommended to use the SpiceDB Kubernetes Operator if you’re using Kubernetes. The Operator automates many operational tasks and helps maintain consistency across environments. You can find the official documentation for the SpiceDB operator [here](https://authzed.com/docs/spicedb/concepts/operator). + +#### Metrics, traces and profiles + +Tags: **operations** + +To gain deeper insights into the performance of your SpiceDB cluster, the pods expose both metrics and pprof profiling endpoints. You can also configure tracing to export data to compatible OpenTelemetry backends. + +- Refer to the [SpiceDB Prometheus documentation](https://authzed.com/docs/spicedb/ops/observability#prometheus) for details on collecting metrics. + - AuthZed Cloud supports exporting metrics to Datadog via the official [AuthZed cloud datadog integration](https://docs.datadoghq.com/integrations/authzed_cloud/). + - To gain a complete picture of your SpiceDB cluster’s performance, it’s important to export metrics from the underlying datastore. These metrics help identify potential bottlenecks and performance issues. AuthZed Cloud provides access to both CockroachDB and PostgreSQL metrics via its cloud telemetry endpoints, enabling deeper visibility into database behavior. +- The [profiling documentation](https://authzed.com/docs/spicedb/ops/observability#profiling) explains how to use the pprof endpoints. +- The [tracing documentation](https://authzed.com/docs/spicedb/ops/observability#opentelemetry-tracing) walks you through sending trace data to a Jaeger endpoint. + +#### Ensure that SpiceDB Can Talk To Itself + +Tags: **operations** + +In SpiceDB, dispatching subproblems refers to the internal process of breaking down a permission check or relationship evaluation into smaller logical components. These subproblems are dispatched horizontally between SpiceDB nodes, which shares the workload and increases cache hit rate - this is [SpiceDB’s horizontal scalability](https://authzed.com/blog/consistent-hash-load-balancing-grpc). For this to work, the SpiceDB nodes must be configured to be aware of each other. + +In our experience, running SpiceDB on Kubernetes with our [Operator](https://authzed.com/docs/spicedb/concepts/operator) is the easiest and best way to achieve this. It’s possible to configure dispatch using DNS as well, but non-Kubernetes based dispatching relies upon DNS updates, which means it can become stale if DNS is changing. This is not recommended unless DNS updates are rare. + +#### Choose the Right Load Balancer + +Tags: **operations** + +In our experience, TCP-level L4 load balancers play more nicely with gRPC clients than HTTP-level L7 load balancers. For example, we’ve found that even though AWS Application Load Balancers purport to support gRPC, they have a tendency to drop connections and otherwise misbehave; AWS Network Load Balancers seem to work better. + +#### Use Partials + Composable Schema to Organize your Schema + +Tags: **schema** + +As a schema grows in size and complexity, it can become difficult to navigate and grok. We implemented [Composable Schemas](https://authzed.com/docs/spicedb/modeling/composable-schemas) to solve this problem, allowing you to break down a schema into multiple files and definitions into multiple problems. + +#### When In Doubt, Add Another Permission + +Tags: **schema** + +When adding a new feature or service, it can be tempting to re-use existing permissions that currently match the semantics you’re looking for, rather than doing the work of modifying the schema to introduce a new permission. However, if the authorization business logic changes between use cases, you’ll not only have to do the work of modifying the permission, but also modifying the call site, so we recommend frontloading that work. + +#### Use Expiration Feature for Expiration Logic + +Tags: **schema** + +Expiration is a common use case – at some future time, a permission is revoked. It’s so common, it’s now [a built-in feature](https://authzed.com/docs/spicedb/concepts/expiring-relationships), and is far more efficient for SpiceDB to handle than doing the same with caveats! + +#### Prefer Checking Permissions Instead of Relationships + +Tags: **application** + +t’s possible to make a Check call with a relation as the “permission.” Even in a simple schema, we recommend instead that you have a permission that points at the relation and to check the relation. This is because if the logic of the check needs to change, it’s easy to change the definition of a permission and difficult to change the definition of a relation (it often requires a data migration). + +#### Use ZedTokens and “At Least As Fresh” for Best Caching + +Tags: **application** + +SpiceDB’s fully consistent mode (`fully_consistent`) forces the use of the most recent datastore revision, which might not be the most optimal, and reduces cache hit rate, increasing latency and load on the datastore. + +If possible, we recommend using `at_least_as_fresh` with `ZedTokens` instead. Capture the `ZedToken` returned by your initial request, then include it in all subsequent calls. SpiceDB will guarantee you see a state at least as fresh as that token while still leveraging in-memory and datastore caches to deliver low-latency responses From 757983985133241d87779190f8c482143967e917 Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Thu, 15 May 2025 12:14:12 -0600 Subject: [PATCH 02/11] polish --- pages/_meta.json | 4 + pages/{spicedb => }/best-practices/_meta.json | 0 pages/best-practices/best-practices.mdx | 289 ++++++++++++++++++ .../spicedb/best-practices/best-practices.mdx | 237 -------------- 4 files changed, 293 insertions(+), 237 deletions(-) rename pages/{spicedb => }/best-practices/_meta.json (100%) create mode 100644 pages/best-practices/best-practices.mdx delete mode 100644 pages/spicedb/best-practices/best-practices.mdx diff --git a/pages/_meta.json b/pages/_meta.json index b5a72cb0..084a6854 100644 --- a/pages/_meta.json +++ b/pages/_meta.json @@ -10,5 +10,9 @@ "authzed": { "title": "AuthZed Product Documentation", "type": "page" + }, + "best-practices": { + "title": "Best Practices", + "type": "page" } } diff --git a/pages/spicedb/best-practices/_meta.json b/pages/best-practices/_meta.json similarity index 100% rename from pages/spicedb/best-practices/_meta.json rename to pages/best-practices/_meta.json diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx new file mode 100644 index 00000000..269804f2 --- /dev/null +++ b/pages/best-practices/best-practices.mdx @@ -0,0 +1,289 @@ +# Best Practises + +### Rule Categories + +#### Priority A: Essential + +The essential rules are the most important ones. +Use them to ensure that your SpiceDB cluster is performant, your schema is sane, and your authorization logic is sound. +Exceptions to these rules should be rare and well justified. + +#### Priority B: Strongly Recommended + +The strong recommendation rules will improve the schema design, developer experience, and performance of your SpiceDB cluster. +In most cases, these rules should be followed. + +#### Priority C: Recommended + +The recommended rules reflect how we would run our own systems, but may not apply to every use case and may not make sense in every situation. +Follow them if you can and ignore them if you can’t. + +### Priority A Rules: Essential + +#### Make sure your schema fails closed + +Tags: **schema** + +This is related to the idea of using negation sparingly, and of phrasing your schema additively. +Give thought to what happens if your application fails to write a relation: should the user have access in that case? The answer is almost always `no`. + +#### Tune Connections to Datastores + +Tags: **operations** + +To size your SpiceDB connection pools, start by determining the maximum number of allowed connections based on the documentation for your selected datastore, divide that number by the number of SpiceDB pods you’ve deployed, then split it between read and write pools. + +Use these values to set the --datastore-conn-pool-read-max-open and --datastore-conn-pool-write-max-open flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. + +#### Test Your Schema + +Tags: **schema** + +You should be testing the logic of your schema to ensure that it behaves the way you expect. +- For unit testing and TDD, use test relations + assertions and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). +- For snapshot testing, use test relations + expected relations and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). +- For integration testing, use the SpiceDB test server with spicedb [serve-testing](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#integration-test-server). + +#### Prefer Relations to Caveats + +Tags: **schema** + +If an authorization concept can be expressed using relations, it should be. +We provide caveats as an escape hatch; they should only be used for context that’s only available at request time, or else ABAC logic that cannot be expressed in terms of relationships. + +Some examples: +- A banlist - this could be expressed as a list in caveat context, but it can also be expressed as a relation with negation. +- A notion of public vs internal - boolean flags seem like an obvious caveat use case, but they can also be expressed using self relations. +- Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a spicedb schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. + +This is because caveats come with a performance penalty. +A caveated relationship is both harder to cache and also slows down computation of the graph walk required to compute a permission. + +#### Make Your Writes Idempotent + +Tags: **application** + +Relations in SpiceDB are binary (a relation is present or it’s not), and WriteRelationships calls are atomic. +As much as possible, we recommend that you use the TOUCH semantic for your write calls, because it means that you can easily retry writes and recover from failures. + +If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using preconditions. + +#### Don’t truncate your tables when running Postgres + +Tags: **operations** + +If you truncate your Postgres table, your SpiceDB instances will become unresponsive until you run spicedb datastore repair. +We recommend either dropping the tables entirely and recreating them with spicedb datastore migrate head or deleting the data using a DeleteRelationships call instead. + +To ensure that every request, whether cached or not, gets a consistent point-in-time view of the underlying data, SpiceDB uses Multi-Version Concurrency Control. +Some datastores provide this natively; in others we’ve implemented it on top of the datastore. +In Postgres, the implementation of MVCC depends on the internals of the transaction counter being stored as data in the tables, so if you truncate the relationships table you desync the transaction counter with the stored relationships. + +### Priority B Rules: Strongly Recommended + +#### Understand your consistency needs + +Tags: **operations** + +While designing your authorization, it’s important to plan ahead for how quickly an update is guaranteed, while trading off performance via cache effectiveness. +By default, SpiceDB sets the Quanitzation Interval to 5s; check operations are cached within this window. +To change this value, set `--datastore-revision-quantization-interval` longer or shorter. + +When it comes to write consistency, SpiceDB defaults to high safety, especially in distributed database writing scenarios, guaranteeing a visibility order. +Individual datastores may also allow a relaxation of this guarantee, based on your scenario; for example, [setting CockroachDB’s overlap strategy](https://authzed.com/docs/spicedb/concepts/datastores#overlap-strategy), trading some authorization visibility safety across domains for greatly increased write throughput. + +#### Use GRPC When Possible + +Tags: **application** + +SpiceDB can be configured to expose both an [HTTP API](https://authzed.com/docs/spicedb/getting-started/client-libraries#http-clients) and associated Swagger documentation. +While this can be helpful for initial exploration, we strongly recommend using one of our gRPC-based official client libraries if your networking and calling language support it. +gRPC is significantly more performant and lower-latency than HTTP, and client-streaming services like ImportBulk can’t be used with the HTTP API. + +#### Keep Permission Logic in SpiceDB + +Tags: **schema** + +One of the big benefits to using a centralized authorization system like SpiceDB is that there’s one place to look for your authorization logic, and authorization logic isn’t duplicated across services. +It can be tempting to define the authorization logic for an endpoint as being the AND or OR of the checks of other permissions, especially when the alternative is writing a new schema. +However, this increases the likelihood of drift across your system, hides the authorization logic for a system in that system’s codebase, and increases the load on SpiceDB. + +#### Avoid Cycles in your Schema + +Tags: **schema** + +Recursive schemas can be very powerful, but can also lead to large performance issues when used incorrectly. +A good rule of thumb is, if you need a schema definition to recur, have it refer to itself (eg, groups can have subgroups). +Avoid situations where a definition points to a separate definition that, further down the permission chain, points to the original definition by accident. + +Avoid: + +```zed +definition user { + relation org: organization +} + +definition group { + relation member: user +} + +definition organization { + relation subgroup: group +} +``` + +Preferred: + +```zed +definition user {} + +definition group { + relation member: user | group +} +``` + +#### Phrase Permissions Additively/Positively + +Tags: **schema** + +A more comprehensible permission system is a more secure permission system. +One of the easiest ways to maintain your authorization logic is to treat permissions as `positive` or `additive`: a user gains permissions when relations are written. +This reduces the number of ways that permission logic can interact, and prevents the granting of permission accidentally. + +In concrete terms, that means use wildcards and negations sparingly. +Start with no access and build up; don’t start with full access and pare down. + +#### Use Unique Identifiers for Object Identifiers + +Tags: **application** + +Because you typically want to centralize your permissions in SpiceDB, that also means that most of the IDs of objects in SpiceDB are references to external entities. +These external entities shouldn’t overlap. +To that end, we recommend either using UUIDs or using another identifier from the upstream that you can be sure will be unique, such as the unique sub field assigned to a user token by your IDP. + +#### Avoid ReadRelationships API + +Tags: **application** + +The ReadRelationships API should be treated as an escape hatch, used mostly for data introspection. +Using it for permission logic is a code smell. +All checks and listing of IDs should use Check, CheckBulk, LookupResources, and LookupSubjects. +If you find yourself reaching for the ReadRelationships API for permission logic, there’s probably a way to modify your schema to use one of the check APIs instead. + +#### Prefer CheckBulk To LookupResources + +Tags: **application** + +Both CheckBulk and LookupResources can be used to determine whether a subject has access to a list of objects. +Where possible, we recommend CheckBulk, because its work is bounded to the list of requested checks, whereas the wrong LookupResources call can return the entire world and choke both your datastore and your client. + +LookupResources generally requires a lot of work, causes a higher load, and subsequently has some of the highest latencies. +If you need its semantics but its performance is insufficient, we recommend checking out our [Materialize](https://authzed.com/products/authzed-materialize) offering. + +### Priority C Rules: Recommended + +#### Treat Writing Schema like Writing DB Migrations + +Tags: **operations** + +We recommend treating your SpiceDB schema as though it were a database migration. +Keep it in your codebase, test it before deployment, and write it to your SpiceDB cluster as a part of your continuous integration process. +This ensures that updates to your schema are properly controlled. + +#### Load Test + +Tags: **operations** + +To evaluate the performance and capabilities of your SpiceDB cluster and its underlying datastore, AuthZed provides [Thumper](https://github.com/authzed/thumper) — a load testing tool. +You can use Thumper to simulate workloads and validate schema updates before deploying them to a production environment. + +#### Use ZedTokens and “At Least As Fresh” for Best Caching + +Tags: **application** + +SpiceDB’s fully consistent mode (`fully_consistent`) forces the use of the most recent datastore revision, which might not be the most optimal, and reduces cache hit rate, increasing latency and load on the datastore. + +If possible, we recommend using `at_least_as_fresh` with `ZedTokens` instead. +Capture the `ZedToken` returned by your initial request, then include it in all subsequent calls. +SpiceDB will guarantee you see a state at least as fresh as that token while still leveraging in-memory and datastore caches to deliver low-latency responses + +#### Prefer Checking Permissions Instead of Relationships + +Tags: **application** + +t’s possible to make a Check call with a relation as the “permission.” Even in a simple schema, we recommend instead that you have a permission that points at the relation and to check the relation. +This is because if the logic of the check needs to change, it’s easy to change the definition of a permission and difficult to change the definition of a relation (it often requires a data migration). + +#### Enable schema watch cache + +Tags: **operations** + +In order to minimize load on the database, you can enable schema watch cache using the flag `--enable-experimental-watchable-schema-cache`. +The schema watch cache is a mechanism that improves performance and responsiveness by caching the currently loaded schema and watching for changes in real time. + +While we recommend enabling this, it isn't enabled by default because it requires additional configuration and knowledge of your datastore. +For Postgres, [`track_commit_timestamp`](https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-TRACK-COMMIT-TIMESTAMP) must be set to `on` for the Watch API to be enabled. +For Spanner, there are a maximum of 5 changefeeds available globally for a table, and this consumes one of them. + +#### Use the Operator + +Tags: **operations** + +To ensure seamless rollouts, upgrades, and schema migrations, it is recommended to use the SpiceDB Kubernetes Operator if you’re using Kubernetes. +The Operator automates many operational tasks and helps maintain consistency across environments. +You can find the official documentation for the SpiceDB operator [here](https://authzed.com/docs/spicedb/concepts/operator). + +#### Ensure that SpiceDB Can Talk To Itself + +Tags: **operations** + +In SpiceDB, dispatching subproblems refers to the internal process of breaking down a permission check or relationship evaluation into smaller logical components. +These subproblems are dispatched horizontally between SpiceDB nodes, which shares the workload and increases cache hit rate - this is [SpiceDB’s horizontal scalability](https://authzed.com/blog/consistent-hash-load-balancing-grpc). +For this to work, the SpiceDB nodes must be configured to be aware of each other. + +In our experience, running SpiceDB on Kubernetes with our [Operator](https://authzed.com/docs/spicedb/concepts/operator) is the easiest and best way to achieve this. +It’s possible to configure dispatch using DNS as well, but non-Kubernetes based dispatching relies upon DNS updates, which means it can become stale if DNS is changing. +This is not recommended unless DNS updates are rare. + +#### Choose the Right Load Balancer + +Tags: **operations** + +In our experience, TCP-level L4 load balancers play more nicely with gRPC clients than HTTP-level L7 load balancers. +For example, we’ve found that even though AWS Application Load Balancers purport to support gRPC, they have a tendency to drop connections and otherwise misbehave; AWS Network Load Balancers seem to work better. + +#### Use the Provided Metrics, Traces, and Profiles + +Tags: **operations** + +To gain deeper insights into the performance of your SpiceDB cluster, the pods expose both metrics and pprof profiling endpoints. +You can also configure tracing to export data to compatible OpenTelemetry backends. + +- Refer to the [SpiceDB Prometheus documentation](https://authzed.com/docs/spicedb/ops/observability#prometheus) for details on collecting metrics. + - AuthZed Cloud supports exporting metrics to Datadog via the official [AuthZed cloud datadog integration](https://docs.datadoghq.com/integrations/authzed_cloud/). + - To gain a complete picture of your SpiceDB cluster’s performance, it’s important to export metrics from the underlying datastore. + These metrics help identify potential bottlenecks and performance issues. + AuthZed Cloud provides access to both CockroachDB and PostgreSQL metrics via its cloud telemetry endpoints, enabling deeper visibility into database behavior. +- The [profiling documentation](https://authzed.com/docs/spicedb/ops/observability#profiling) explains how to use the pprof endpoints. +- The [tracing documentation](https://authzed.com/docs/spicedb/ops/observability#opentelemetry-tracing) walks you through sending trace data to a Jaeger endpoint. + +#### Use Partials + Composable Schema to Organize your Schema + +Tags: **schema** + +As a schema grows in size and complexity, it can become difficult to navigate and grok. +We implemented [Composable Schemas](https://authzed.com/docs/spicedb/modeling/composable-schemas) to solve this problem, allowing you to break down a schema into multiple files and definitions into multiple problems. + +#### When In Doubt, Add Another Permission + +Tags: **schema** + +When adding a new feature or service, it can be tempting to re-use existing permissions that currently match the semantics you’re looking for, rather than doing the work of modifying the schema to introduce a new permission. +However, if the authorization business logic changes between use cases, you’ll not only have to do the work of modifying the permission, but also modifying the call site, so we recommend frontloading that work. + +#### Use Expiration Feature for Expiration Logic + +Tags: **schema** + +Expiration is a common use case – at some future time, a permission is revoked. +It’s so common, it’s now [a built-in feature](https://authzed.com/docs/spicedb/concepts/expiring-relationships), and is far more efficient for SpiceDB to handle than doing the same with caveats! diff --git a/pages/spicedb/best-practices/best-practices.mdx b/pages/spicedb/best-practices/best-practices.mdx deleted file mode 100644 index 4cd1d716..00000000 --- a/pages/spicedb/best-practices/best-practices.mdx +++ /dev/null @@ -1,237 +0,0 @@ -# Best Practises - -### Rule Categories - -#### Priority A: Essential - -The essential rules are the most important ones. Use them to ensure that your SpiceDB cluster is performant, your schema is sane, and your authorization logic is sound. Exceptions to these rules should be rare and well justified. - -#### Priority B: Strongly Recommended - -The strong recommendation rules will improve the schema design, developer experience, and performance of your SpiceDB cluster. In most cases, these rules should be followed. - -#### Priority C: Recommended - -The recommended rules reflect how we would run our own systems, but may not apply to every use case and may not make sense in every situation. Follow them if you can and ignore them if you can’t. - -### Priority A Rules: Essential - -#### Don’t truncate your tables when running Postgres - -Tags: **operations** - -If you truncate your Postgres table, your SpiceDB instances will become unresponsive until you run spicedb datastore repair. We recommend either dropping the tables entirely and recreating them with spicedb datastore migrate head or deleting the data using a DeleteRelationships call instead. - -To ensure that every request, whether cached or not, gets a consistent point-in-time view of the underlying data, SpiceDB uses Multi-Version Concurrency Control. Some datastores provide this natively; in others we’ve implemented it on top of the datastore. In Postgres, the implementation of MVCC depends on the internals of the transaction counter being stored as data in the tables, so if you truncate the relationships table you desync the transaction counter with the stored relationships. - -#### Tune Connections to Datastores - -Tags: **operations** - -To size your SpiceDB connection pools, start by determining the maximum number of allowed connections based on the documentation for your selected datastore, divide that number by the number of SpiceDB pods you’ve deployed, then split it between read and write pools. - -Use these values to set the --datastore-conn-pool-read-max-open and --datastore-conn-pool-write-max-open flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. - -#### Test Your Schema - -Tags: **schema** - -You should be testing the logic of your schema to ensure that it behaves the way you expect. -- For unit testing and TDD, use test relations + assertions and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). -- For snapshot testing, use test relations + expected relations and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). -- For integration testing, use the SpiceDB test server with spicedb [serve-testing](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#integration-test-server). - -#### Prefer Relations to Caveats - -Tags: **schema** - -If an authorization concept can be expressed using relations, it should be. We provide caveats as an escape hatch; they should only be used for context that’s only available at request time, or else ABAC logic that cannot be expressed in terms of relationships. - -Some examples: -- A banlist - this could be expressed as a list in caveat context, but it can also be expressed as a relation with negation. -- A notion of public vs internal - boolean flags seem like an obvious caveat use case, but they can also be expressed using self relations. -- Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a spicedb schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. - -This is because caveats come with a performance penalty. A caveated relationship is both harder to cache and also slows down computation of the graph walk required to compute a permission. - -#### Make sure your schema fails closed - -Tags: **schema** - -This is related to the idea of using negation sparingly, and of phrasing your schema additively. Give thought to what happens if your application fails to write a relation: should the user have access in that case? The answer is almost always `no`. - -#### Make Your Writes Idempotent - -Tags: **application** - -Relations in SpiceDB are binary (a relation is present or it’s not), and WriteRelationships calls are atomic. As much as possible, we recommend that you use the TOUCH semantic for your write calls, because it means that you can easily retry writes and recover from failures. - -If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using preconditions. - -### Priority B Rules: Strongly Recommended - -#### Understand your consistency needs - -Tags: **operations** - -While designing your authorization, it’s important to plan ahead for how quickly an update is guaranteed, while trading off performance via cache effectiveness. By default, SpiceDB sets the Quanitzation Interval to 5s; check operations are cached within this window. To change this value, set `--datastore-revision-quantization-interval` longer or shorter. - -When it comes to write consistency, SpiceDB defaults to high safety, especially in distributed database writing scenarios, guaranteeing a visibility order. Individual datastores may also allow a relaxation of this guarantee, based on your scenario; for example, [setting CockroachDB’s overlap strategy](https://authzed.com/docs/spicedb/concepts/datastores#overlap-strategy), trading some authorization visibility safety across domains for greatly increased write throughput. - -#### Keep Permission Logic in SpiceDB - -Tags: **schema** - -One of the big benefits to using a centralized authorization system like SpiceDB is that there’s one place to look for your authorization logic, and authorization logic isn’t duplicated across services. It can be tempting to define the authorization logic for an endpoint as being the AND or OR of the checks of other permissions, especially when the alternative is writing a new schema. However, this increases the likelihood of drift across your system, hides the authorization logic for a system in that system’s codebase, and increases the load on SpiceDB. - -#### Avoid Cycles in your Schema - -Tags: **schema** - -Recursive schemas can be very powerful, but can also lead to large performance issues when used incorrectly. A good rule of thumb is, if you need a schema definition to recur, have it refer to itself (eg, groups can have subgroups). Avoid situations where a definition points to a separate definition that, further down the permission chain, points to the original definition by accident. - -Avoid: - -```zed -definition user { - relation org: organization -} - -definition group { - relation member: user -} - -definition organization { - relation subgroup: group -} -``` - -Preferred: - -```zed -definition user {} - -definition group { - relation member: user | group -} -``` - -#### Phrase Permissions Additively/Positively - -Tags: **schema** - -A more comprehensible permission system is a more secure permission system. One of the easiest ways to maintain your authorization logic is to treat permissions as `positive` or `additive`: a user gains permissions when relations are written. This reduces the number of ways that permission logic can interact, and prevents the granting of permission accidentally. - -In concrete terms, that means use wildcards and negations sparingly. Start with no access and build up; don’t start with full access and pare down. - -#### Use GRPC When Possible - -Tags: **application** - -SpiceDB can be configured to expose both an [HTTP API](https://authzed.com/docs/spicedb/getting-started/client-libraries#http-clients) and associated Swagger documentation. While this can be helpful for initial exploration, we strongly recommend using one of our gRPC-based official client libraries if your networking and calling language support it. gRPC is significantly more performant and lower-latency than HTTP, and client-streaming services like ImportBulk can’t be used with the HTTP API. - -#### Use Unique Identifiers for Object Identifiers - -Tags: **application** - -Because you typically want to centralize your permissions in SpiceDB, that also means that most of the IDs of objects in SpiceDB are references to external entities. These external entities shouldn’t overlap. To that end, we recommend either using UUIDs or using another identifier from the upstream that you can be sure will be unique, such as the unique sub field assigned to a user token by your IDP. - -#### Avoid ReadRelationships API - -Tags: **application** - -The ReadRelationships API should be treated as an escape hatch, used mostly for data introspection. Using it for permission logic is a code smell. All checks and listing of IDs should use Check, CheckBulk, LookupResources, and LookupSubjects. If you find yourself reaching for the ReadRelationships API for permission logic, there’s probably a way to modify your schema to use one of the check APIs instead. - -#### Prefer CheckBulk To LookupResources - -Tags: **application** - -Both CheckBulk and LookupResources can be used to determine whether a subject has access to a list of objects. Where possible, we recommend CheckBulk, because its work is bounded to the list of requested checks, whereas the wrong LookupResources call can return the entire world and choke both your datastore and your client. - -LookupResources generally requires a lot of work, causes a higher load, and subsequently has some of the highest latencies. If you need its semantics but its performance is insufficient, we recommend checking out our [Materialize](https://authzed.com/products/authzed-materialize) offering. - -### Priority C Rules: Recommended - -#### Enable schema watch cache - -Tags: **operations** - -In order to minimize load on the database, you can enable schema watch cache using the flag `-enable-experimental-watchable-schema-cache`. The schema watch cache is a mechanism that improves performance and responsiveness by caching the currently loaded schema and watching for changes in real time. - -For postgres `track_commit_timestamp` must be set to `on` for the Watch API to be enabled. - -#### Load Test - -Tags: **operations** - -To evaluate the performance and capabilities of your SpiceDB cluster and its underlying datastore, AuthZed provides [Thumper](https://github.com/authzed/thumper) — a load testing tool. You can use Thumper to simulate workloads and validate schema updates before deploying them to a production environment. - -#### Treat Writing Schema like Writing DB Migrations - -Tags: **operations** - -We recommend treating your SpiceDB schema as though it were a database migration. Keep it in your codebase, test it before deployment, and write it to your SpiceDB cluster as a part of your continuous integration process. This ensures that updates to your schema are properly controlled. - -#### Use the Operator - -Tags: **operations** - -To ensure seamless rollouts, upgrades, and schema migrations, it is recommended to use the SpiceDB Kubernetes Operator if you’re using Kubernetes. The Operator automates many operational tasks and helps maintain consistency across environments. You can find the official documentation for the SpiceDB operator [here](https://authzed.com/docs/spicedb/concepts/operator). - -#### Metrics, traces and profiles - -Tags: **operations** - -To gain deeper insights into the performance of your SpiceDB cluster, the pods expose both metrics and pprof profiling endpoints. You can also configure tracing to export data to compatible OpenTelemetry backends. - -- Refer to the [SpiceDB Prometheus documentation](https://authzed.com/docs/spicedb/ops/observability#prometheus) for details on collecting metrics. - - AuthZed Cloud supports exporting metrics to Datadog via the official [AuthZed cloud datadog integration](https://docs.datadoghq.com/integrations/authzed_cloud/). - - To gain a complete picture of your SpiceDB cluster’s performance, it’s important to export metrics from the underlying datastore. These metrics help identify potential bottlenecks and performance issues. AuthZed Cloud provides access to both CockroachDB and PostgreSQL metrics via its cloud telemetry endpoints, enabling deeper visibility into database behavior. -- The [profiling documentation](https://authzed.com/docs/spicedb/ops/observability#profiling) explains how to use the pprof endpoints. -- The [tracing documentation](https://authzed.com/docs/spicedb/ops/observability#opentelemetry-tracing) walks you through sending trace data to a Jaeger endpoint. - -#### Ensure that SpiceDB Can Talk To Itself - -Tags: **operations** - -In SpiceDB, dispatching subproblems refers to the internal process of breaking down a permission check or relationship evaluation into smaller logical components. These subproblems are dispatched horizontally between SpiceDB nodes, which shares the workload and increases cache hit rate - this is [SpiceDB’s horizontal scalability](https://authzed.com/blog/consistent-hash-load-balancing-grpc). For this to work, the SpiceDB nodes must be configured to be aware of each other. - -In our experience, running SpiceDB on Kubernetes with our [Operator](https://authzed.com/docs/spicedb/concepts/operator) is the easiest and best way to achieve this. It’s possible to configure dispatch using DNS as well, but non-Kubernetes based dispatching relies upon DNS updates, which means it can become stale if DNS is changing. This is not recommended unless DNS updates are rare. - -#### Choose the Right Load Balancer - -Tags: **operations** - -In our experience, TCP-level L4 load balancers play more nicely with gRPC clients than HTTP-level L7 load balancers. For example, we’ve found that even though AWS Application Load Balancers purport to support gRPC, they have a tendency to drop connections and otherwise misbehave; AWS Network Load Balancers seem to work better. - -#### Use Partials + Composable Schema to Organize your Schema - -Tags: **schema** - -As a schema grows in size and complexity, it can become difficult to navigate and grok. We implemented [Composable Schemas](https://authzed.com/docs/spicedb/modeling/composable-schemas) to solve this problem, allowing you to break down a schema into multiple files and definitions into multiple problems. - -#### When In Doubt, Add Another Permission - -Tags: **schema** - -When adding a new feature or service, it can be tempting to re-use existing permissions that currently match the semantics you’re looking for, rather than doing the work of modifying the schema to introduce a new permission. However, if the authorization business logic changes between use cases, you’ll not only have to do the work of modifying the permission, but also modifying the call site, so we recommend frontloading that work. - -#### Use Expiration Feature for Expiration Logic - -Tags: **schema** - -Expiration is a common use case – at some future time, a permission is revoked. It’s so common, it’s now [a built-in feature](https://authzed.com/docs/spicedb/concepts/expiring-relationships), and is far more efficient for SpiceDB to handle than doing the same with caveats! - -#### Prefer Checking Permissions Instead of Relationships - -Tags: **application** - -t’s possible to make a Check call with a relation as the “permission.” Even in a simple schema, we recommend instead that you have a permission that points at the relation and to check the relation. This is because if the logic of the check needs to change, it’s easy to change the definition of a permission and difficult to change the definition of a relation (it often requires a data migration). - -#### Use ZedTokens and “At Least As Fresh” for Best Caching - -Tags: **application** - -SpiceDB’s fully consistent mode (`fully_consistent`) forces the use of the most recent datastore revision, which might not be the most optimal, and reduces cache hit rate, increasing latency and load on the datastore. - -If possible, we recommend using `at_least_as_fresh` with `ZedTokens` instead. Capture the `ZedToken` returned by your initial request, then include it in all subsequent calls. SpiceDB will guarantee you see a state at least as fresh as that token while still leveraging in-memory and datastore caches to deliver low-latency responses From f1dca2dc48ec2294223e91d0e523d3881ed736fb Mon Sep 17 00:00:00 2001 From: adinhodovic Date: Thu, 15 May 2025 15:04:44 -0400 Subject: [PATCH 03/11] docs(spicedb): Fix nits with spelling and code sections Signed-off-by: adinhodovic --- pages/best-practices/best-practices.mdx | 43 +++++++++++++------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index 269804f2..fae3b94e 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -1,4 +1,4 @@ -# Best Practises +# Best Practices ### Rule Categories @@ -33,7 +33,7 @@ Tags: **operations** To size your SpiceDB connection pools, start by determining the maximum number of allowed connections based on the documentation for your selected datastore, divide that number by the number of SpiceDB pods you’ve deployed, then split it between read and write pools. -Use these values to set the --datastore-conn-pool-read-max-open and --datastore-conn-pool-write-max-open flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. +Use these values to set the `--datastore-conn-pool-read-max-open` and `--datastore-conn-pool-write-max-open` flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. #### Test Your Schema @@ -63,8 +63,8 @@ A caveated relationship is both harder to cache and also slows down computation Tags: **application** -Relations in SpiceDB are binary (a relation is present or it’s not), and WriteRelationships calls are atomic. -As much as possible, we recommend that you use the TOUCH semantic for your write calls, because it means that you can easily retry writes and recover from failures. +Relations in SpiceDB are binary (a relation is present or it's not), and `WriteRelationships` calls are atomic. +As much as possible, we recommend that you use the `TOUCH` semantic for your write calls, because it means that you can easily retry writes and recover from failures. If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using preconditions. @@ -72,8 +72,8 @@ If you’re concerned about sequencing your writes, or your writes have dependen Tags: **operations** -If you truncate your Postgres table, your SpiceDB instances will become unresponsive until you run spicedb datastore repair. -We recommend either dropping the tables entirely and recreating them with spicedb datastore migrate head or deleting the data using a DeleteRelationships call instead. +If you truncate your Postgres table, your SpiceDB pods will become unresponsive until you run SpiceDB datastore repair. +We recommend either dropping the tables entirely and recreating them with spicedb datastore migrate head or deleting the data using a `DeleteRelationships` call instead. To ensure that every request, whether cached or not, gets a consistent point-in-time view of the underlying data, SpiceDB uses Multi-Version Concurrency Control. Some datastores provide this natively; in others we’ve implemented it on top of the datastore. @@ -104,16 +104,16 @@ gRPC is significantly more performant and lower-latency than HTTP, and client-st Tags: **schema** -One of the big benefits to using a centralized authorization system like SpiceDB is that there’s one place to look for your authorization logic, and authorization logic isn’t duplicated across services. -It can be tempting to define the authorization logic for an endpoint as being the AND or OR of the checks of other permissions, especially when the alternative is writing a new schema. -However, this increases the likelihood of drift across your system, hides the authorization logic for a system in that system’s codebase, and increases the load on SpiceDB. +One of the big benefits to using a centralized authorization system like SpiceDB is that there's one place to look for your authorization logic, and authorization logic isn't duplicated across services. +It can be tempting to define the authorization logic for an endpoint as being the `AND` or `OR` of the checks of other permissions, especially when the alternative is writing a new schema. +However, this increases the likelihood of drift across your system, hides the authorization logic for a system in that system's codebase, and increases the load on SpiceDB. #### Avoid Cycles in your Schema Tags: **schema** Recursive schemas can be very powerful, but can also lead to large performance issues when used incorrectly. -A good rule of thumb is, if you need a schema definition to recur, have it refer to itself (eg, groups can have subgroups). +A good rule of thumb is, if you need a schema definition to recur, have it refer to itself (e.g., groups can have subgroups). Avoid situations where a definition points to a separate definition that, further down the permission chain, points to the original definition by accident. Avoid: @@ -157,25 +157,25 @@ Start with no access and build up; don’t start with full access and pare down. Tags: **application** -Because you typically want to centralize your permissions in SpiceDB, that also means that most of the IDs of objects in SpiceDB are references to external entities. -These external entities shouldn’t overlap. -To that end, we recommend either using UUIDs or using another identifier from the upstream that you can be sure will be unique, such as the unique sub field assigned to a user token by your IDP. +Because you typically want to centralize your permissions in SpiceDB, that also means that most of the `IDs` of objects in SpiceDB are references to external entities. +These external entities shouldn't overlap. +To that end, we recommend either using `UUIDs` or using another identifier from the upstream that you can be sure will be unique, such as the unique sub field assigned to a user token by your IDP. #### Avoid ReadRelationships API Tags: **application** -The ReadRelationships API should be treated as an escape hatch, used mostly for data introspection. +The `ReadRelationships` API should be treated as an escape hatch, used mostly for data introspection. Using it for permission logic is a code smell. -All checks and listing of IDs should use Check, CheckBulk, LookupResources, and LookupSubjects. -If you find yourself reaching for the ReadRelationships API for permission logic, there’s probably a way to modify your schema to use one of the check APIs instead. +All checks and listing of IDs should use `Check`, `CheckBulk`, `LookupResources`, and `LookupSubjects`. +If you find yourself reaching for the `ReadRelationships` API for permission logic, there's probably a way to modify your schema to use one of the check APIs instead. #### Prefer CheckBulk To LookupResources Tags: **application** -Both CheckBulk and LookupResources can be used to determine whether a subject has access to a list of objects. -Where possible, we recommend CheckBulk, because its work is bounded to the list of requested checks, whereas the wrong LookupResources call can return the entire world and choke both your datastore and your client. +Both `CheckBulk` and `LookupResources` can be used to determine whether a subject has access to a list of objects. +Where possible, we recommend `CheckBulk`, because its work is bounded to the list of requested checks, whereas the wrong `LookupResources` call can return the entire world and choke both your datastore and your client. LookupResources generally requires a lot of work, causes a higher load, and subsequently has some of the highest latencies. If you need its semantics but its performance is insufficient, we recommend checking out our [Materialize](https://authzed.com/products/authzed-materialize) offering. @@ -211,8 +211,9 @@ SpiceDB will guarantee you see a state at least as fresh as that token while sti Tags: **application** -t’s possible to make a Check call with a relation as the “permission.” Even in a simple schema, we recommend instead that you have a permission that points at the relation and to check the relation. -This is because if the logic of the check needs to change, it’s easy to change the definition of a permission and difficult to change the definition of a relation (it often requires a data migration). +It's possible to make a `Check` call with a relation as the permission. +Even in a simple schema, we recommend instead that you have a permission that points at the relation and to check the relation. +This is because if the logic of the check needs to change, it's easy to change the definition of a permission and difficult to change the definition of a relation (it often requires a data migration). #### Enable schema watch cache @@ -256,7 +257,7 @@ For example, we’ve found that even though AWS Application Load Balancers purpo Tags: **operations** -To gain deeper insights into the performance of your SpiceDB cluster, the pods expose both metrics and pprof profiling endpoints. +To gain deeper insights into the performance of your SpiceDB cluster, the pods expose both Prometheus metrics and `pprof` profiling endpoints. You can also configure tracing to export data to compatible OpenTelemetry backends. - Refer to the [SpiceDB Prometheus documentation](https://authzed.com/docs/spicedb/ops/observability#prometheus) for details on collecting metrics. From 1857889862bcffedcb69570e798692b002b450ba Mon Sep 17 00:00:00 2001 From: adinhodovic Date: Thu, 15 May 2025 15:11:24 -0400 Subject: [PATCH 04/11] style(best-practises): Fix linting issues --- pages/best-practices/best-practices.mdx | 77 +++++++++++++------------ 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index fae3b94e..81ee0b20 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -1,33 +1,34 @@ # Best Practices -### Rule Categories +## Rule Categories -#### Priority A: Essential +### Priority A: Essential The essential rules are the most important ones. Use them to ensure that your SpiceDB cluster is performant, your schema is sane, and your authorization logic is sound. Exceptions to these rules should be rare and well justified. -#### Priority B: Strongly Recommended +### Priority B: Strongly Recommended The strong recommendation rules will improve the schema design, developer experience, and performance of your SpiceDB cluster. In most cases, these rules should be followed. -#### Priority C: Recommended +### Priority C: Recommended The recommended rules reflect how we would run our own systems, but may not apply to every use case and may not make sense in every situation. Follow them if you can and ignore them if you can’t. -### Priority A Rules: Essential +## Priority A Rules: Essential -#### Make sure your schema fails closed +### Make sure your schema fails closed Tags: **schema** This is related to the idea of using negation sparingly, and of phrasing your schema additively. -Give thought to what happens if your application fails to write a relation: should the user have access in that case? The answer is almost always `no`. +Give thought to what happens if your application fails to write a relation: should the user have access in that case? +The answer is almost always `no`. -#### Tune Connections to Datastores +### Tune Connections to Datastores Tags: **operations** @@ -35,16 +36,17 @@ To size your SpiceDB connection pools, start by determining the maximum number o Use these values to set the `--datastore-conn-pool-read-max-open` and `--datastore-conn-pool-write-max-open` flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. -#### Test Your Schema +### Test Your Schema Tags: **schema** You should be testing the logic of your schema to ensure that it behaves the way you expect. + - For unit testing and TDD, use test relations + assertions and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). - For snapshot testing, use test relations + expected relations and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). - For integration testing, use the SpiceDB test server with spicedb [serve-testing](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#integration-test-server). -#### Prefer Relations to Caveats +### Prefer Relations to Caveats Tags: **schema** @@ -52,6 +54,7 @@ If an authorization concept can be expressed using relations, it should be. We provide caveats as an escape hatch; they should only be used for context that’s only available at request time, or else ABAC logic that cannot be expressed in terms of relationships. Some examples: + - A banlist - this could be expressed as a list in caveat context, but it can also be expressed as a relation with negation. - A notion of public vs internal - boolean flags seem like an obvious caveat use case, but they can also be expressed using self relations. - Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a spicedb schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. @@ -59,7 +62,7 @@ Some examples: This is because caveats come with a performance penalty. A caveated relationship is both harder to cache and also slows down computation of the graph walk required to compute a permission. -#### Make Your Writes Idempotent +### Make Your Writes Idempotent Tags: **application** @@ -68,7 +71,7 @@ As much as possible, we recommend that you use the `TOUCH` semantic for your wri If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using preconditions. -#### Don’t truncate your tables when running Postgres +### Don’t truncate your tables when running Postgres Tags: **operations** @@ -79,9 +82,9 @@ To ensure that every request, whether cached or not, gets a consistent point-in- Some datastores provide this natively; in others we’ve implemented it on top of the datastore. In Postgres, the implementation of MVCC depends on the internals of the transaction counter being stored as data in the tables, so if you truncate the relationships table you desync the transaction counter with the stored relationships. -### Priority B Rules: Strongly Recommended +## Priority B Rules: Strongly Recommended -#### Understand your consistency needs +### Understand your consistency needs Tags: **operations** @@ -92,7 +95,7 @@ To change this value, set `--datastore-revision-quantization-interval` longer or When it comes to write consistency, SpiceDB defaults to high safety, especially in distributed database writing scenarios, guaranteeing a visibility order. Individual datastores may also allow a relaxation of this guarantee, based on your scenario; for example, [setting CockroachDB’s overlap strategy](https://authzed.com/docs/spicedb/concepts/datastores#overlap-strategy), trading some authorization visibility safety across domains for greatly increased write throughput. -#### Use GRPC When Possible +### Use GRPC When Possible Tags: **application** @@ -100,7 +103,7 @@ SpiceDB can be configured to expose both an [HTTP API](https://authzed.com/docs/ While this can be helpful for initial exploration, we strongly recommend using one of our gRPC-based official client libraries if your networking and calling language support it. gRPC is significantly more performant and lower-latency than HTTP, and client-streaming services like ImportBulk can’t be used with the HTTP API. -#### Keep Permission Logic in SpiceDB +### Keep Permission Logic in SpiceDB Tags: **schema** @@ -108,7 +111,7 @@ One of the big benefits to using a centralized authorization system like SpiceDB It can be tempting to define the authorization logic for an endpoint as being the `AND` or `OR` of the checks of other permissions, especially when the alternative is writing a new schema. However, this increases the likelihood of drift across your system, hides the authorization logic for a system in that system's codebase, and increases the load on SpiceDB. -#### Avoid Cycles in your Schema +### Avoid Cycles in your Schema Tags: **schema** @@ -142,7 +145,7 @@ definition group { } ``` -#### Phrase Permissions Additively/Positively +### Phrase Permissions Additively/Positively Tags: **schema** @@ -153,15 +156,15 @@ This reduces the number of ways that permission logic can interact, and prevents In concrete terms, that means use wildcards and negations sparingly. Start with no access and build up; don’t start with full access and pare down. -#### Use Unique Identifiers for Object Identifiers +### Use Unique Identifiers for Object Identifiers Tags: **application** Because you typically want to centralize your permissions in SpiceDB, that also means that most of the `IDs` of objects in SpiceDB are references to external entities. -These external entities shouldn't overlap. +These external entities shouldn't overlap. To that end, we recommend either using `UUIDs` or using another identifier from the upstream that you can be sure will be unique, such as the unique sub field assigned to a user token by your IDP. -#### Avoid ReadRelationships API +### Avoid ReadRelationships API Tags: **application** @@ -170,7 +173,7 @@ Using it for permission logic is a code smell. All checks and listing of IDs should use `Check`, `CheckBulk`, `LookupResources`, and `LookupSubjects`. If you find yourself reaching for the `ReadRelationships` API for permission logic, there's probably a way to modify your schema to use one of the check APIs instead. -#### Prefer CheckBulk To LookupResources +### Prefer CheckBulk To LookupResources Tags: **application** @@ -180,9 +183,9 @@ Where possible, we recommend `CheckBulk`, because its work is bounded to the lis LookupResources generally requires a lot of work, causes a higher load, and subsequently has some of the highest latencies. If you need its semantics but its performance is insufficient, we recommend checking out our [Materialize](https://authzed.com/products/authzed-materialize) offering. -### Priority C Rules: Recommended +## Priority C Rules: Recommended -#### Treat Writing Schema like Writing DB Migrations +### Treat Writing Schema like Writing DB Migrations Tags: **operations** @@ -190,14 +193,14 @@ We recommend treating your SpiceDB schema as though it were a database migration Keep it in your codebase, test it before deployment, and write it to your SpiceDB cluster as a part of your continuous integration process. This ensures that updates to your schema are properly controlled. -#### Load Test +### Load Test Tags: **operations** To evaluate the performance and capabilities of your SpiceDB cluster and its underlying datastore, AuthZed provides [Thumper](https://github.com/authzed/thumper) — a load testing tool. You can use Thumper to simulate workloads and validate schema updates before deploying them to a production environment. -#### Use ZedTokens and “At Least As Fresh” for Best Caching +### Use ZedTokens and “At Least As Fresh” for Best Caching Tags: **application** @@ -207,7 +210,7 @@ If possible, we recommend using `at_least_as_fresh` with `ZedTokens` instead. Capture the `ZedToken` returned by your initial request, then include it in all subsequent calls. SpiceDB will guarantee you see a state at least as fresh as that token while still leveraging in-memory and datastore caches to deliver low-latency responses -#### Prefer Checking Permissions Instead of Relationships +### Prefer Checking Permissions Instead of Relationships Tags: **application** @@ -215,7 +218,7 @@ It's possible to make a `Check` call with a relation as the permission. Even in a simple schema, we recommend instead that you have a permission that points at the relation and to check the relation. This is because if the logic of the check needs to change, it's easy to change the definition of a permission and difficult to change the definition of a relation (it often requires a data migration). -#### Enable schema watch cache +### Enable schema watch cache Tags: **operations** @@ -226,7 +229,7 @@ While we recommend enabling this, it isn't enabled by default because it require For Postgres, [`track_commit_timestamp`](https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-TRACK-COMMIT-TIMESTAMP) must be set to `on` for the Watch API to be enabled. For Spanner, there are a maximum of 5 changefeeds available globally for a table, and this consumes one of them. -#### Use the Operator +### Use the Operator Tags: **operations** @@ -234,7 +237,7 @@ To ensure seamless rollouts, upgrades, and schema migrations, it is recommended The Operator automates many operational tasks and helps maintain consistency across environments. You can find the official documentation for the SpiceDB operator [here](https://authzed.com/docs/spicedb/concepts/operator). -#### Ensure that SpiceDB Can Talk To Itself +### Ensure that SpiceDB Can Talk To Itself Tags: **operations** @@ -246,14 +249,14 @@ In our experience, running SpiceDB on Kubernetes with our [Operator](https://aut It’s possible to configure dispatch using DNS as well, but non-Kubernetes based dispatching relies upon DNS updates, which means it can become stale if DNS is changing. This is not recommended unless DNS updates are rare. -#### Choose the Right Load Balancer +### Choose the Right Load Balancer Tags: **operations** In our experience, TCP-level L4 load balancers play more nicely with gRPC clients than HTTP-level L7 load balancers. For example, we’ve found that even though AWS Application Load Balancers purport to support gRPC, they have a tendency to drop connections and otherwise misbehave; AWS Network Load Balancers seem to work better. -#### Use the Provided Metrics, Traces, and Profiles +### Use the Provided Metrics, Traces, and Profiles Tags: **operations** @@ -261,28 +264,28 @@ To gain deeper insights into the performance of your SpiceDB cluster, the pods e You can also configure tracing to export data to compatible OpenTelemetry backends. - Refer to the [SpiceDB Prometheus documentation](https://authzed.com/docs/spicedb/ops/observability#prometheus) for details on collecting metrics. - - AuthZed Cloud supports exporting metrics to Datadog via the official [AuthZed cloud datadog integration](https://docs.datadoghq.com/integrations/authzed_cloud/). - - To gain a complete picture of your SpiceDB cluster’s performance, it’s important to export metrics from the underlying datastore. + - AuthZed Cloud supports exporting metrics to Datadog via the official [AuthZed cloud datadog integration](https://docs.datadoghq.com/integrations/authzed_cloud/). + - To gain a complete picture of your SpiceDB cluster’s performance, it’s important to export metrics from the underlying datastore. These metrics help identify potential bottlenecks and performance issues. AuthZed Cloud provides access to both CockroachDB and PostgreSQL metrics via its cloud telemetry endpoints, enabling deeper visibility into database behavior. - The [profiling documentation](https://authzed.com/docs/spicedb/ops/observability#profiling) explains how to use the pprof endpoints. - The [tracing documentation](https://authzed.com/docs/spicedb/ops/observability#opentelemetry-tracing) walks you through sending trace data to a Jaeger endpoint. -#### Use Partials + Composable Schema to Organize your Schema +### Use Partials + Composable Schema to Organize your Schema Tags: **schema** As a schema grows in size and complexity, it can become difficult to navigate and grok. We implemented [Composable Schemas](https://authzed.com/docs/spicedb/modeling/composable-schemas) to solve this problem, allowing you to break down a schema into multiple files and definitions into multiple problems. -#### When In Doubt, Add Another Permission +### When In Doubt, Add Another Permission Tags: **schema** When adding a new feature or service, it can be tempting to re-use existing permissions that currently match the semantics you’re looking for, rather than doing the work of modifying the schema to introduce a new permission. However, if the authorization business logic changes between use cases, you’ll not only have to do the work of modifying the permission, but also modifying the call site, so we recommend frontloading that work. -#### Use Expiration Feature for Expiration Logic +### Use Expiration Feature for Expiration Logic Tags: **schema** From 842b6e69e3a976036caeb58e1c0c5afa71e96298 Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Thu, 15 May 2025 13:23:14 -0600 Subject: [PATCH 05/11] fix link checker and add links --- pages/best-practices/best-practices.mdx | 4 ++-- pages/spicedb/_meta.json | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index 81ee0b20..ef1217b4 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -67,9 +67,9 @@ A caveated relationship is both harder to cache and also slows down computation Tags: **application** Relations in SpiceDB are binary (a relation is present or it's not), and `WriteRelationships` calls are atomic. -As much as possible, we recommend that you use the `TOUCH` semantic for your write calls, because it means that you can easily retry writes and recover from failures. +As much as possible, we recommend that you use the [`TOUCH`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.RelationshipUpdate) semantic for your write calls, because it means that you can easily retry writes and recover from failures. -If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using preconditions. +If you’re concerned about sequencing your writes, or your writes have dependencies, we recommend using [preconditions](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.Precondition). ### Don’t truncate your tables when running Postgres diff --git a/pages/spicedb/_meta.json b/pages/spicedb/_meta.json index 542a66f1..6da5a260 100644 --- a/pages/spicedb/_meta.json +++ b/pages/spicedb/_meta.json @@ -4,6 +4,5 @@ "modeling": "Modeling & Integrating", "ops": "Operations", "api": "API Reference", - "links": "Links", - "best-practices": "Best Practices" + "links": "Links" } From 9a9feadfc0bb47d9048c8296cc5ab593603edc7a Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Mon, 19 May 2025 12:03:54 -0600 Subject: [PATCH 06/11] Update pages/best-practices/best-practices.mdx Co-authored-by: Maria Ines Parnisari --- pages/best-practices/best-practices.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index ef1217b4..a1cc681a 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -76,7 +76,7 @@ If you’re concerned about sequencing your writes, or your writes have dependen Tags: **operations** If you truncate your Postgres table, your SpiceDB pods will become unresponsive until you run SpiceDB datastore repair. -We recommend either dropping the tables entirely and recreating them with spicedb datastore migrate head or deleting the data using a `DeleteRelationships` call instead. +We recommend either dropping the tables entirely and recreating them with `spicedb datastore migrate head` or deleting the data using a `DeleteRelationships` call instead. To ensure that every request, whether cached or not, gets a consistent point-in-time view of the underlying data, SpiceDB uses Multi-Version Concurrency Control. Some datastores provide this natively; in others we’ve implemented it on top of the datastore. From bf6ce8d77a242bf0a36f6519612b7e3438abcaad Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Mon, 19 May 2025 12:24:27 -0600 Subject: [PATCH 07/11] Update pages/best-practices/best-practices.mdx Co-authored-by: Maria Ines Parnisari --- pages/best-practices/best-practices.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index a1cc681a..ad5f4ccc 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -178,7 +178,7 @@ If you find yourself reaching for the `ReadRelationships` API for permission log Tags: **application** Both `CheckBulk` and `LookupResources` can be used to determine whether a subject has access to a list of objects. -Where possible, we recommend `CheckBulk`, because its work is bounded to the list of requested checks, whereas the wrong `LookupResources` call can return the entire world and choke both your datastore and your client. +Where possible, we recommend `CheckBulk`, because its work is bounded to the list of requested checks, whereas the wrong `LookupResources` call can return the entire world and therefore be slow. LookupResources generally requires a lot of work, causes a higher load, and subsequently has some of the highest latencies. If you need its semantics but its performance is insufficient, we recommend checking out our [Materialize](https://authzed.com/products/authzed-materialize) offering. From 96a33e836ab1158c753d48c60658654d3e62b978 Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Mon, 19 May 2025 12:24:40 -0600 Subject: [PATCH 08/11] Update pages/best-practices/best-practices.mdx Co-authored-by: Maria Ines Parnisari --- pages/best-practices/best-practices.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index ad5f4ccc..63b699a1 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -189,7 +189,7 @@ If you need its semantics but its performance is insufficient, we recommend chec Tags: **operations** -We recommend treating your SpiceDB schema as though it were a database migration. +We recommend treating an update to your SpiceDB schema as though it were a database migration. Keep it in your codebase, test it before deployment, and write it to your SpiceDB cluster as a part of your continuous integration process. This ensures that updates to your schema are properly controlled. From 014c30b0b58b70dd77cc319798d97604d29f0ff5 Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Thu, 15 May 2025 13:23:14 -0600 Subject: [PATCH 09/11] Fix link checker and lint --- pages/best-practices/best-practices.mdx | 84 +++++++++++++++++++++---- pages/spicedb/concepts/datastores.mdx | 15 +---- 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index 63b699a1..56056223 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -18,9 +18,11 @@ In most cases, these rules should be followed. The recommended rules reflect how we would run our own systems, but may not apply to every use case and may not make sense in every situation. Follow them if you can and ignore them if you can’t. + + ## Priority A Rules: Essential -### Make sure your schema fails closed +### Make Sure your Schema Fails Closed Tags: **schema** @@ -28,6 +30,41 @@ This is related to the idea of using negation sparingly, and of phrasing your sc Give thought to what happens if your application fails to write a relation: should the user have access in that case? The answer is almost always `no`. +This example is very simple, but illustrates the basic point: + +#### Avoid + +This schema starts with everyone having access and reduces it as you add users to the deny list. +If you fail to write a user to the deny list, they'll have access when they shouldn't: + +```zed +definition user {} + +definition resource { + relation public: user:* + relation deny: user + + permission view = public - deny +} +``` + +#### Prefer + +By contrast, this schema defaults to nobody having access, and therefore fails closed: + +```zed +definition user {} + +definition resource { + relation user: user + + permission view = user +} +``` + +This is an admittedly simple example, but the concept holds in more complex schemas. +This will also sometimes require a conversation about the business logic of your application. + ### Tune Connections to Datastores Tags: **operations** @@ -36,6 +73,25 @@ To size your SpiceDB connection pools, start by determining the maximum number o Use these values to set the `--datastore-conn-pool-read-max-open` and `--datastore-conn-pool-write-max-open` flags, and set the corresponding min values to half of each, adjusting as needed based on whether your workload leans more heavily on reads or writes. +#### Example + +Let's say you have a database instance that supports 200 connections, and you know that you read more than you write. +You have 4 SpiceDB instances in your cluster. +A starting point for tuning this might be: + +```sh +spicedb serve +# other flags here +--datastore-conn-pool-read-max-open 30 +--datastore-conn-pool-read-min-open 15 +--datastore-conn-pool-write-max-open 20 +--datastore-conn-pool-write-min-open 10 +``` + +This reserves 50 connections per SpiceDB instance and distributes them accordingly. + +The `pgxpool_empty_acquire` metric can help you understand if your SpiceDB pods are starved for connections if you're using Postgres or Cockroach. + ### Test Your Schema Tags: **schema** @@ -44,7 +100,7 @@ You should be testing the logic of your schema to ensure that it behaves the way - For unit testing and TDD, use test relations + assertions and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). - For snapshot testing, use test relations + expected relations and [zed validate](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#zed-validate). -- For integration testing, use the SpiceDB test server with spicedb [serve-testing](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#integration-test-server). +- For integration testing, use the SpiceDB test server with SpiceDB [serve-testing](https://authzed.com/docs/spicedb/modeling/validation-testing-debugging#integration-test-server). ### Prefer Relations to Caveats @@ -53,15 +109,15 @@ Tags: **schema** If an authorization concept can be expressed using relations, it should be. We provide caveats as an escape hatch; they should only be used for context that’s only available at request time, or else ABAC logic that cannot be expressed in terms of relationships. +This is because caveats come with a performance penalty. +A caveated relationship is both harder to cache and also slows down computation of the graph walk required to compute a permission. + Some examples: - A banlist - this could be expressed as a list in caveat context, but it can also be expressed as a relation with negation. - A notion of public vs internal - boolean flags seem like an obvious caveat use case, but they can also be expressed using self relations. - Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a spicedb schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. -This is because caveats come with a performance penalty. -A caveated relationship is both harder to cache and also slows down computation of the graph walk required to compute a permission. - ### Make Your Writes Idempotent Tags: **application** @@ -88,12 +144,18 @@ In Postgres, the implementation of MVCC depends on the internals of the transact Tags: **operations** -While designing your authorization, it’s important to plan ahead for how quickly an update is guaranteed, while trading off performance via cache effectiveness. -By default, SpiceDB sets the Quanitzation Interval to 5s; check operations are cached within this window. -To change this value, set `--datastore-revision-quantization-interval` longer or shorter. +SpiceDB gives the user the ability to make tradeoffs between cache performance and up-to-date visibility using [its consistency options](https://authzed.com/docs/spicedb/concepts/consistency). +In addition to these call-time options, there are also some flags that can provide better cache performance if additional staleness is acceptable. +For example, by default, SpiceDB sets the Quantization Interval to 5s; check operations are cached within this window when using `minimize_latency` or `at_least_as_fresh` calls. +Setting this window to be larger increases the ability of SpiceDB to use cached results with a tradeoff of results staying in the cache longer. +More details about how these flags work together can be found in our [Hotspot Caching blog post](https://authzed.com/blog/hotspot-caching-in-google-zanzibar-and-spicedb). +To change this value, set the `--datastore-revision-quantization-interval` flag. -When it comes to write consistency, SpiceDB defaults to high safety, especially in distributed database writing scenarios, guaranteeing a visibility order. -Individual datastores may also allow a relaxation of this guarantee, based on your scenario; for example, [setting CockroachDB’s overlap strategy](https://authzed.com/docs/spicedb/concepts/datastores#overlap-strategy), trading some authorization visibility safety across domains for greatly increased write throughput. +When it comes to write consistency, SpiceDB defaults to high safety, +especially in distributed database writing scenarios, guaranteeing a visibility order. +Individual datastores may also allow a relaxation of this guarantee, based on your scenario; +for example, [setting CockroachDB’s overlap strategy](https://authzed.com/docs/spicedb/concepts/datastores#overlap-strategy), +can let you trade some ordering and consistency guarantees across domains for greatly increased write throughput. ### Use GRPC When Possible @@ -278,7 +340,7 @@ Tags: **schema** As a schema grows in size and complexity, it can become difficult to navigate and grok. We implemented [Composable Schemas](https://authzed.com/docs/spicedb/modeling/composable-schemas) to solve this problem, allowing you to break down a schema into multiple files and definitions into multiple problems. -### When In Doubt, Add Another Permission +### Don't Re-Use Permissions Across Use Cases Tags: **schema** diff --git a/pages/spicedb/concepts/datastores.mdx b/pages/spicedb/concepts/datastores.mdx index bccdb1bd..49baf2d6 100644 --- a/pages/spicedb/concepts/datastores.mdx +++ b/pages/spicedb/concepts/datastores.mdx @@ -274,19 +274,8 @@ Because this counter is instance-specific, there are ways in which the data in t Two concrete examples are the use of `pg_dump` and `pg_restore` to transfer data between an old instance and a new instance and setting up logical replication between a previously-existing instance and a newly-created instance. -If you encounter this, SpiceDB can behave as though there is no schema written, because the data (including the schema) is associated with a future transaction ID and therefore -isn't "visible" to Spicedb. -You may see an error like this: - -``` -FAILED_PRECONDITION: object definition `some_definition` not found -``` - -If this occurs, you can use `spicedb datastore repair` (along with your usual datastore flags) to roll the transaction counter of the database forward until SpiceDB is able to resume normal operation: - -``` -spicedb datastore repair --datastore-engine=postgres --datastore-conn-uri=$DATASTORE_URI -``` +If you encounter this, SpiceDB can behave as though there is no schema written, because the data (including the schema) is associated with a future transaction ID and therefore isn't "visible" to Spicedb. +If you run into this issue, the fix is [documented here](https://authzed.com/docs/spicedb/concepts/datastores#transaction-ids-and-mvcc) ### Configuration From 2abcb10a42e4b520a64d8e0257e48b22540898f6 Mon Sep 17 00:00:00 2001 From: Maria Ines Parnisari Date: Tue, 20 May 2025 09:17:57 -0700 Subject: [PATCH 10/11] s/spicedb/SpiceDB --- pages/best-practices/best-practices.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index 56056223..aacc4b2c 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -116,7 +116,7 @@ Some examples: - A banlist - this could be expressed as a list in caveat context, but it can also be expressed as a relation with negation. - A notion of public vs internal - boolean flags seem like an obvious caveat use case, but they can also be expressed using self relations. -- Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a spicedb schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. +- Dynamic roles - these could be expressed as a list in caveats, and it’s not immediately obvious how to build them into a SpiceDB schema, but our [Google Cloud IAM example](https://authzed.com/blog/google-cloud-iam-modeling) shows how it’s possible. ### Make Your Writes Idempotent From 6811d6b7432456e8167daca8983a1361d5e59b19 Mon Sep 17 00:00:00 2001 From: Tanner Stirrat Date: Tue, 20 May 2025 10:25:25 -0600 Subject: [PATCH 11/11] Remove errant closing tag --- pages/best-practices/best-practices.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/pages/best-practices/best-practices.mdx b/pages/best-practices/best-practices.mdx index aacc4b2c..bece4203 100644 --- a/pages/best-practices/best-practices.mdx +++ b/pages/best-practices/best-practices.mdx @@ -18,8 +18,6 @@ In most cases, these rules should be followed. The recommended rules reflect how we would run our own systems, but may not apply to every use case and may not make sense in every situation. Follow them if you can and ignore them if you can’t. - - ## Priority A Rules: Essential ### Make Sure your Schema Fails Closed