Policy patterns
Each pattern is a custom control. It is one Rego file in a pbac.controls.<name> package that adds denial reasons, and it reads one data row that you own. You change who or what a pattern covers by writing its row, not by editing the Rego.
All five patterns guard the same example resource type, urn:example:reports, with the scopes read and write. Set it up once.
A pattern stays deployed until you delete its rule, so it also judges the requests of every pattern you try after it. The order matters. The attribute-based pattern denies every client with no department claim, which includes the set-up client. Remove a pattern before you try the next. This finds the attribute-based rule by its path and deletes it. For another pattern, use the path from its Deploy step.
id=$(curl -fsS "$POLICYARC_URL/admin/api/policy-rules" -H "X-Admin-API-Key: $POLICYARC_ADMIN_KEY" |
jq -er '.[] | select(.path == "pbac/controls/reports_department.rego") | .id')
curl -fsS -X DELETE "$POLICYARC_URL/admin/api/policy-rules/$id" -H "X-Admin-API-Key: $POLICYARC_ADMIN_KEY"
| Pattern | What it denies | Its data row |
|---|---|---|
| Deny by default | Every client that is not on an allowlist | custom.reports_allowlist |
| Time-bound access | Writes outside a window of UTC hours. It also shortens tokens to 15 minutes. | custom.reports_hours |
| Attribute-based access | Clients whose software statement names a department that is not allowed | custom.reports_department |
| Delegation chains | Token exchange by a client that is not an approved delegate | custom.reports_delegates |
| Agent trust tiers | All calls from untrusted agents and writes from limited agents. It also shortens tokens to 5 minutes. | custom.agent_tiers |
Set up the examples
You need the Admin API key and jq. Set two values.
export POLICYARC_URL="https://your-environment.example"
export POLICYARC_ADMIN_KEY="paste the Admin API key"
Add the resource type to the resource registry control. The request sets one key of the pbac.operator.controls.resource_registry row and leaves the rest alone.
curl -fsS -X PATCH "$POLICYARC_URL/admin/api/policy-data/by-key?dataKey=pbac.operator.controls.resource_registry&path=resource.types.urn:example:reports" \
-H "X-Admin-API-Key: $POLICYARC_ADMIN_KEY" \
-H 'Content-Type: application/json' \
-d '{"scopes": ["read", "write"]}'
Register a client and keep its credentials.
reg=$(curl -fsS -X POST "$POLICYARC_URL/register" \
-H 'Content-Type: application/json' \
-d '{"client_name": "reports-agent", "redirect_uris": ["https://reports-agent.example/cb"], "token_endpoint_auth_method": "client_secret_basic"}')
export CLIENT_ID=$(jq -r .client_id <<<"$reg")
export CLIENT_SECRET=$(jq -r .client_secret <<<"$reg")
A client registered this way may use only the authorization_code and refresh_token grants. Entitle it to the client credentials grant and to the example resource type through the client entitlements control.
curl -fsS -X PATCH "$POLICYARC_URL/admin/api/policy-data/by-key?dataKey=pbac.operator.controls.client_entitlements&path=client_id.$CLIENT_ID" \
-H "X-Admin-API-Key: $POLICYARC_ADMIN_KEY" \
-H 'Content-Type: application/json' \
-d '{"grant_types": ["client_credentials"], "granted_resources": [{"type": "urn:example:reports", "scopes": ["read", "write"]}]}'
Ask for a token.
curl -sS -u "$CLIENT_ID:$CLIENT_SECRET" "$POLICYARC_URL/token" \
-d grant_type=client_credentials -d 'scope=read write' -d resource_types=urn:example:reports
Before any pattern is deployed, the response carries "scope":"read write" and "expires_in":3600.
The policy engine loads a data change a few seconds after the write. When we sent this request straight after the entitlement, it returned access_denied with the reason grant_type_not_allowed. If that happens, wait a few seconds and send it again.
How the patterns combine
You can deploy several patterns at once. Their denial reasons add up, and any one of them denies the action. When two patterns shorten the token, the shortest lifetime wins. With the time-bound pattern (900 seconds) and the agent trust tiers pattern (300 seconds) both deployed, our tokens came back with "expires_in":300.
To write your own control, see Write a policy. To deploy one safely and undo it, see Deploy and roll back policy.
Send feedback about this page