Skip to main content

Access rules

Access rules are needed in order for any kind of request to Treasury to succeed. Without them, requests will be denied by default.

Setup

For the examples, we will assume a fresh treasury instance or demo, which you can start to follow along.

treasury demo start --port 8777 --pull
info

While you can create rules & resources using the treasury CLI, using the CSL interpreter is often easier & more consistent.

Open the CSL interpreter by running:

treasury script --sign-with root-key

Note that the demo comes configured with a few rules built-in, including this rule which permits the "root" user to do anything.

allow access-rule root { action = "any/action", resource = "any/resource", initiate = "users/root" }

For the examples, we'll create an alice & bob users that doesn't yet have permission to do anything.

# create a fresh role called "demo"
treasury roles create demo

# create users alice & bob
treasury users create machine alice --role demo
treasury users create machine bob --role demo

# create invite codes
treasury credentials create-invite alice "alices_invite_code"
treasury credentials create-invite bob "bobs_invite_code"

# create + enroll new local client credentials that alice & bob can sign with.
treasury credentials register alice-key --invite "alices_invite_code" --create-new
treasury credentials register bob-key --invite "bobs_invite_code" --create-new

# test sending requests as both alice + bob
treasury users heartbeat --sign-with alice-key
treasury users heartbeat --sign-with bob-key

Dry-running

Note that at any point you can dry-run various requests without having to sign any request. Such dry-runs do not actually cause any state change, but can be helpful for testing or debugging policies.

Dry-runs will return helpful traces on rules that matched the request. You'll be able to see how each rule evaluated.

Using curl:

curl -H 'dry-run: user=root'  -X POST -d '{"from":"chains/SOL/addresses/<from>", "to":"chains/SOL/addresses/<to>", "amount":"100", "asset":"chains/SOL/assets/SOL"}' localhost:8777/v1/transfers

Using CLI:

treasury transfers create --from "<from>" --to "<to>" --chain SOL 100 --dry-run 'user=root'

Examples

Default deny

By default, users cannot do anything unless they are included in a matching rule, whether by their username or by their role (or wildcard).

# Doesn't work
set sign.with = alice-key
create machine user carol

Allow rule

We could permit alice or bob to create addresses, either by their specific user name(s), or by their role ("roles/demo").

# allow alice
create allow access-rule ALLOW_ADDRESSES { resource = "Address", initiate = "users/alice", action = ["create", "update", "delete"] }

# alice creates an address
set sign.with = alice-key
create internal address for SOL

Deny rule

Let's permit any with "demo" role to create addresses, but we deny alice from doing so.

create allow access-rule ALLOW_ADDRESSES { resource = "Address", initiate = "roles/demo", action = ["create", "update", "delete"] }
create deny access-rule DENY_ADDRESSES { resource = "Address", initiate = "users/alice", action = ["create", "update", "delete"] }

# bob is allowed
set sign.with = bob-key
treasury addresses create SOL --sign-with alice-key

# but not alice
set sign.with = alice-key
treasury addresses create SOL --sign-with alice-key

Require rule

Let's require that creating addresses needs an approval. Approval conditions can also be used with allow rules, but those would only apply to the specific rule.

The require variant on the other hand, must always be satisfied if it matches a request. Note that you always need to have a matching allow rule for a request to pass; a require rule by itself is not sufficient.

create allow access-rule ALLOW_ADDRESSES { resource = "Address", initiate = "roles/demo", action = ["create", "update", "delete"] }
create require access-rule REQUIRE_ADDRESSES { resource = "Address", initiate = "roles/demo", approve="roles/demo", approvals=1, action = ["create", "update", "delete"] }
# delete any deny rules you may have made
_, _ = delete access-rule DENY_ADDRESSES

To test this out:

# note this returns an operation in `authorizing` state.
treasury addresses create SOL --sign-with alice-key

# another roles/demo user will need to approve to complete:
treasury operations approve "<operation-id>" --sign-with bob-key

Data filters

We can match rules based on any filter in the data of the target resource.

Let's suppose we have a special key and we want to require approvals for who can sign with it.

# create a key called "COLD_KEY"
treasury keys create --algorithm ed255 COLD_KEY
# create a key called "HOT_KEY"
treasury keys create --algorithm ed255 HOT_KEY

Now we can require that any signature request needs an approval from a "roles/demo" user.

# permit people to create signatures
create allow access-rule ALLOW_SIGNATURES { resource = "Signature", initiate = "roles/demo", action = "create" }
# require approval for using the COLD_KEY
create require access-rule REQUIRE_SIGNATURES { resource = "Signature", data = {key = "keys/COLD_KEY"}, initiate = "any/user", approve="roles/demo", approvals=1, action = "create" }

To try this out, we can see that we can payloads using the "HOT_KEY" without approval.

treasury signatures create --key HOT_KEY --message 1234 --sign-with alice-key

Using "COLD_KEY" will require approval.

treasury signatures create --key COLD_KEY --message 1234 --sign-with alice-key

# approve
treasury operations approve "<operation-id>" --sign-with bob-key

Approve only

To permit someone only to approve, you need only omit the initiate and pass only the approve & approvals conditions.

Wildcards are specified explicity with either any/action, any/resource, or any/user.

allow access-rule APPROVE_ONLY { creator = "users/root", version = 1, action = "any/action", resource = "any/resource", approve = "users/root", approvals = 1 }