You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is an in progress document containing the brainstorming around how we want to handle authorization in bindle. This comes from a HackMD where various maintainers collaborated on figuring things out and it has been cleaned up and updated. Any ideas or feedback is welcome!
Goals/Non-goals
The following goals and non-goals are specifically for 1.0. This doesn't mean we don't want them in the future.
Goals:
OAuth tokens can be authorized against resources
File-based ACL rules
Non-goals:
Database (or other datasource) ACL rule sources
Role configuration endpoint (TODO: Maybe we actually want this for 1.0?)
Per parcel rules (i.e. access to only specific parcels of a Bindle)
Use cases
Verbs
There are two main verbs used across all bindle resources:
get
create
For invoices, there is an additional verb called yank. If necessary, this could be changed to delete to match other conventions.
Expected user interactions
Below is the list of expected interactions with the Bindle server covered by authorization flow:
TODO: Allow version specific restrictions
Anonymous read access: This will be the default authorization mode for all bindles (a la dockerhub)
Read (get) access: A user can only access an invoice and its parcels if logged in and granted access
This kind of access can be granted on specific bindles (example.com/foo), but not specific versions of a bindle (example.com/foo/1.0.0)
This access can also be granted on any subpath of a bindle. So given a bindle of example.com/catblog/foo/1.0.0, access can be granted to anything under the example.com subpath or it can be granted to example.com/catblog to further restrict access
Create (create) access: A user can only create an invoice and upload parcels for invoices if logged in and granted access
This kind of access can be granted on specific bindles (example.com/foo), but not specific versions of a bindle (example.com/foo/1.0.0)
This access can also be granted on any subpath of a bindle. So given a bindle of example.com/catblog/foo/1.0.0, access can be granted to anything under the example.com subpath or it can be granted to example.com/catblog to further restrict access. In the example.com case, a user would be able to create invoices and upload parcels with any ID starting with example.com. In the example.com/catblog example, a user would be able to create any number of bindles and parcels under that subpath.
Yank (yank) access: A user can only yank an invoice if logged in and granted access
This kind of access can be granted on specific invoices (example.com/foo), but not specific versions of an invoice (example.com/foo/1.0.0)
This access can also be granted on any subpath of a bindle. So given a bindle of example.com/catblog/foo/1.0.0, access can be granted to anything under the example.com subpath or it can be granted to example.com/catblog to further restrict access. In the example.com case, a user would be able to yank invoices with any ID starting with example.com. In the example.com/catblog example, a user would be able to yank any number of invoices under that subpath.
Type restrictions
It is important to note that any access control lists will also need to specify types due to the arbitrarily pathy nature of Bindle IDs. When mapping roles for an invoice, an additional type restriction must be specified. These types are specified below:
bindle: Indicates that this path is a full bindle path and isn't a subpath. So a create role on example.com/foo with a bindle type means that only an example.com/foo bindle can be created. It will prevent a user from creating an example.com/foo/bar bindle. This is the default rule if no type is specified
subpath: Indicates that this path is a subpath, granting the user the right to do anything with the allowed verb under that subpath. So a create role on example.com/foo with a subpath type means that user can arbitrarily create any bindle starting with the example.com/foo subpath, but CANNOT create a bindle with that exact path.
Authorization flow
This section discusses how the authorization flow will work in our code at a high level.
Groups/User mapping
Both types of authentication must have a type that implements the Authorizable trait:
pubtraitAuthorizable{/// Returns the identity or username of the authenticated userfnprincipal(&self) -> String;/// Returns the groups the authenticated user is a member of, generally embedded on something/// like a JWT or fetched from an upstream serverfngroups(&self) -> Vec<String>;}
This will allow the server to be able to check the authenticated user against the configured ACL list.
Token based
The username from a JWT will be pulled from the sub claim. If this is not present, the token will not be accepted. For simpler group management (i.e. not needing to contact an external server to fetch the groups), we will require the presence of a custom groups claim. This is a common field on many JWTs and so should not be much of a hassle to use with third party OAuth providers. The list of groups from the token would be returned wholesale using the groups() method.
Option 2: Biscuit tokens
Another option could be to use biscuit tokens, as a way to contain the ACL for the request rather than with specific file based ACL rules (as described below)
ACL creation and maintenance
For 1.0, the plan will be to only use a config file for ACL policies (most likely a TOML file). The structure of this file will be determined by the library we end up using for the rules engine and so it is not defined here.
As stated before, database support is non-goal, but is something we want to add in the future. Accessing the rules should be behind a trait for easy extension in the future.
Rules engine
This is the biggest unknown at the current time. Early ideas for the rules engine involve something similar to the Upspin project for handling the ACLs and actual authorization. However, this project is written in Go and would be hard to consume within Rust. It does lead us to the other option of implementing our own rules engine, possibly based on Upspin. The downside of this option, no matter how it is implemented, is that we'd have a whole engine to use from scratch. This upside is we could design it as a separate crate with flexibility in rule sources and contribute something useful to the Rust community. The Oso project also looks interesting, but it is new and little-used. It also has the additional downside of locking us into its custom "Polar" language format for our rules.
The text was updated successfully, but these errors were encountered:
This is an in progress document containing the brainstorming around how we want to handle authorization in bindle. This comes from a HackMD where various maintainers collaborated on figuring things out and it has been cleaned up and updated. Any ideas or feedback is welcome!
Goals/Non-goals
The following goals and non-goals are specifically for 1.0. This doesn't mean we don't want them in the future.
Goals:
Non-goals:
Use cases
Verbs
There are two main verbs used across all bindle resources:
get
create
For invoices, there is an additional verb called
yank
. If necessary, this could be changed todelete
to match other conventions.Expected user interactions
Below is the list of expected interactions with the Bindle server covered by authorization flow:
TODO: Allow version specific restrictions
get
) access: A user can only access an invoice and its parcels if logged in and granted accessexample.com/catblog/foo/1.0.0
, access can be granted to anything under theexample.com
subpath or it can be granted toexample.com/catblog
to further restrict accesscreate
) access: A user can only create an invoice and upload parcels for invoices if logged in and granted accessexample.com/catblog/foo/1.0.0
, access can be granted to anything under theexample.com
subpath or it can be granted toexample.com/catblog
to further restrict access. In theexample.com
case, a user would be able to create invoices and upload parcels with any ID starting withexample.com
. In theexample.com/catblog
example, a user would be able to create any number of bindles and parcels under that subpath.yank
) access: A user can only yank an invoice if logged in and granted accessexample.com/catblog/foo/1.0.0
, access can be granted to anything under theexample.com
subpath or it can be granted toexample.com/catblog
to further restrict access. In theexample.com
case, a user would be able to yank invoices with any ID starting withexample.com
. In theexample.com/catblog
example, a user would be able to yank any number of invoices under that subpath.Type restrictions
It is important to note that any access control lists will also need to specify types due to the arbitrarily pathy nature of Bindle IDs. When mapping roles for an invoice, an additional type restriction must be specified. These types are specified below:
bindle
: Indicates that this path is a full bindle path and isn't a subpath. So acreate
role onexample.com/foo
with abindle
type means that only anexample.com/foo
bindle can be created. It will prevent a user from creating anexample.com/foo/bar
bindle. This is the default rule if no type is specifiedsubpath
: Indicates that this path is a subpath, granting the user the right to do anything with the allowed verb under that subpath. So acreate
role onexample.com/foo
with asubpath
type means that user can arbitrarily create any bindle starting with theexample.com/foo
subpath, but CANNOT create a bindle with that exact path.Authorization flow
This section discusses how the authorization flow will work in our code at a high level.
Groups/User mapping
Both types of authentication must have a type that implements the
Authorizable
trait:This will allow the server to be able to check the authenticated user against the configured ACL list.
Token based
The username from a JWT will be pulled from the
sub
claim. If this is not present, the token will not be accepted. For simpler group management (i.e. not needing to contact an external server to fetch the groups), we will require the presence of a customgroups
claim. This is a common field on many JWTs and so should not be much of a hassle to use with third party OAuth providers. The list of groups from the token would be returned wholesale using thegroups()
method.Option 2: Biscuit tokens
Another option could be to use biscuit tokens, as a way to contain the ACL for the request rather than with specific file based ACL rules (as described below)
ACL creation and maintenance
For 1.0, the plan will be to only use a config file for ACL policies (most likely a TOML file). The structure of this file will be determined by the library we end up using for the rules engine and so it is not defined here.
As stated before, database support is non-goal, but is something we want to add in the future. Accessing the rules should be behind a trait for easy extension in the future.
Rules engine
This is the biggest unknown at the current time. Early ideas for the rules engine involve something similar to the Upspin project for handling the ACLs and actual authorization. However, this project is written in Go and would be hard to consume within Rust. It does lead us to the other option of implementing our own rules engine, possibly based on Upspin. The downside of this option, no matter how it is implemented, is that we'd have a whole engine to use from scratch. This upside is we could design it as a separate crate with flexibility in rule sources and contribute something useful to the Rust community. The Oso project also looks interesting, but it is new and little-used. It also has the additional downside of locking us into its custom "Polar" language format for our rules.
The text was updated successfully, but these errors were encountered: