Skip to content

feat(authorization): add Cedar authorization recipe - #591

Open
Jeadie wants to merge 2 commits into
trunkfrom
authorization-recipe
Open

feat(authorization): add Cedar authorization recipe#591
Jeadie wants to merge 2 commits into
trunkfrom
authorization-recipe

Conversation

@Jeadie

@Jeadie Jeadie commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

What

A new self-contained recipe, authorization/, that secures datasets with Cedar authorization policies and OIDC/JWT identity. It shows four distinct access-control patterns from a single Spicepod:

Pattern Rule Demonstrated by
Multi-tenancy tenant_id = current_org_id() Acme and Globex users see different rows of customers
Row-level security (RLS) owner = current_user_id() Two users in the same tenant see different rows of deals; an admin sees all
PII masking @mask_email / @mask_ssn, by role Analysts see masked PII; a PII officer sees real values
RBAC Role-gated dataset + deny-by-default Only the hr role may read salaries

Multi-tenancy isolates by organization; RLS isolates by user — a finer grain the tenant filter alone cannot express. The admin role is exempt from the ownership filter and granted an unfiltered read, so a manager sees every deal.

Identity

To keep the recipe self-contained, the identity provider is a small static file server (serve-jwks.py, standard library only) that serves an OIDC discovery document and a public JWKS. Four demo tokens are pre-signed and committed, so the recipe runs with no setup. In production you point issuer_url at your real identity provider and change nothing else.

The demo signing key is not committed — it is generated on demand by generate-tokens.js and gitignored. It is not needed to run: Spice validates the pre-signed tokens against the committed public JWKS.

Notes

  • Requires the Enterprise distribution of Spice.ai — Cedar authorization policies and OIDC identity are enterprise features. The README states this up front.
  • Unregistered from CI — the recipe needs enterprise auth features, so it is intentionally not added to the spice-qa.yml matrix.
  • All data is synthetic (fake tenants acme/globex, example emails, placeholder SSNs).

Test

Verified end-to-end against an enterprise spiced: each README command was run and its output matches the committed expected output — tenant isolation, per-user RLS with the admin override, role-conditional masking, and deny-by-default RBAC all behave as documented.

Add a self-contained recipe that secures datasets with Cedar authorization
policies and OIDC/JWT identity. It shows four distinct patterns from one
Spicepod:

- Multi-tenancy: tenant_id = current_org_id()
- Row-level security: owner = current_user_id(), with an admin override
- PII masking: @mask_email / @mask_ssn, conditioned on role
- RBAC: role-gated dataset with deny-by-default

Identity comes from a small static file server (serve-jwks.py, standard library)
that serves an OIDC discovery document and a public JWKS. Four demo tokens are
pre-signed and committed, so the recipe runs with no setup. The demo signing key
is generated on demand and gitignored — it is not needed to run.

Requires the Enterprise distribution of Spice.ai for the authorization and OIDC
features. Left unregistered from CI, which does not run enterprise recipes.
} else {
const { privateKey } = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" });
fs.writeFileSync(keyPath, privateKeyPem);
The admin override now grants a tenant-filtered read
(tenant_id = current_org_id()) instead of an unfiltered one, so an admin sees
every deal in their own org but not another tenant's. Update the README output
and description to match.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants