Skip to main content

Policies

The Policies screen lets you manage the policy rules of the tenant, evaluate a Policy Contract request against them, publish the OPA policies as a signed bundle and check the revision each policy engine really runs. Portal path: /security/policies, menu Security and governance > Policies. It is used by security officers and tenant administrators who write the rules, by auditors who read them, and by developers who test a request.

What the screen shows​

The screen (Policies in portal/src/screens/security.tsx) has four sections, from top to bottom.

  • Policies table, read from GET /v1/policies (no paging): columns Name, Version, Engine, Priority, Status, Updated. A click on a row opens a detail panel loaded from GET /v1/policies/{policy_id} (the JSON of the policy). Empty table: "No policy", "Built in policies apply until you add your own."
  • Evaluate a Policy Contract request: a form with one JSON field Request, prefilled with an example (an agent invoking a model). The result shows a large Allow or Deny badge, the decision identifier, the list of the reasons, one badge per obligation and the full JSON answer.
  • Signed OPA bundles table, read from GET /v1/policies/bundles: columns Revision, SHA-256, Signed, Created by, Created. A click on a row shows the row.
  • Policy engines: the JSON answer of GET /v1/policies/engines, "Revision each OPA bundle really runs and the state of the relationship engine" (OPA: configured, delivery, expected revision, reachable, in sync; OpenFGA: configured, reachable).

The create and edit form of a policy has these fields:

FieldTypeDefaultRequiredDescription
NametextyesLowercase letters, digits, _, . and -, up to 100 characters (deny-restricted-external).
DescriptiontextnoFree text.
Enginebuiltin or opayesopa needs a Rego (OPA) text.
Prioritynumber100noLower values are evaluated first.
Statusactive, draft, disablednoThe API stores active when the field is empty.
RulesJSONone deny rule on model.invoke for restricted and secret datanoList of rules: effect, actions, resource_types, conditions, reason.
Rego (OPA)textfor opaModule such as package eai.model_invocation.

Actions​

Button or actionWhat it doesAPI callRoles
New policy (then Create)Creates a policy from the form; a revision is recorded and the change is audited (policy.create).POST /v1/policiestenant_admin, security_officer
Row click or View detailsOpens the detail panel of the policy.GET /v1/policies/{policy_id}Every user of the tenant
Edit (row menu, then Edit)Replaces the policy with the form values, prefilled from the row; a new revision is recorded (policy.update).PUT /v1/policies/{policy_id}tenant_admin, security_officer
Delete (row menu)Opens the destructive confirmation (impact, dependents, risks); you type the name of the policy, then Confirm.GET /v1/lineage/graph, then DELETE /v1/policies/{policy_id}tenant_admin, security_officer
Run (Evaluate a Policy Contract request)Evaluates the request and shows the decision.POST /v1/policies/evaluateEvery user of the tenant
Publish a bundle (then Create)Builds and publishes a signed bundle of the OPA policies, with an optional Revision and a Data JSON.POST /v1/policies/bundlestenant_admin, security_officer (button hidden for others)
Row click (Signed OPA bundles)Shows the bundle row.NoneReaders of the bundles
Refresh icon of a tableReads the list again.GET /v1/policies or GET /v1/policies/bundlesReaders of the list
note

The edit form does not carry the Version of the policy: the API stores its default version 1.0.0 on each save from this screen. Use the API to set an explicit version.

An example of a request for Evaluate a Policy Contract request (the subject is optional: without it, the request is evaluated for you):

{
"action": "model.invoke",
"resource": {"type": "model", "id": "claude-sonnet-eu"},
"context": {"data_classification": "confidential", "region": "eu-central-1"}
}

Roles​

The portal hides only the Publish a bundle button, shown to ROLES.delegationAdmins (tenant_admin, security_officer in portal/src/lib/kit.ts). Every other control is shown and the Control Plane decides (services/control-plane/src/eai/domains/policies/__init__.py):

  • list, detail and evaluation: any user of the tenant;
  • create, edit, delete, publish a bundle: tenant_admin, security_officer;
  • list of the bundles and state of the engines: tenant_admin, security_officer, auditor;
  • platform_admin passes every role check.

A tenant_admin or a security_officer may evaluate a request on behalf of another subject of the tenant (what-if): the evaluation is then audited as policy.simulate. For any other user, the subject is always the caller.

Typical tasks​

Add a deny rule for restricted data​

  1. Open the form. A policy of the tenant adds to the built in ones. Click New policy. Expected result: a side panel with the fields prefilled (rule deny on model.invoke). If it fails: no table means the list did not load; click the refresh icon.
  2. Fill the policy. Enter a Name such as deny-restricted-external, keep Engine builtin, set Priority and adapt Rules. Expected result: the form accepts the JSON. If it fails: "Invalid JSON" under Rules means the JSON does not parse.
  3. Create. Click Create. Expected result: the message Created and a new row with status active. If it fails: forbidden (HTTP 403) means a missing role; conflict (HTTP 409) means the name already exists; validation_error (HTTP 422) means a name outside the allowed characters, or opa without Rego (OPA).
  4. Test it. In Evaluate a Policy Contract request, send a request with "data_classification": "restricted" and click Run. Expected result: a Deny badge with the reason of your rule. If it fails: an Allow badge means the rule does not match (check actions, resource_types and conditions).

Publish the OPA policies for the engines​

  1. Publish. OPA polls a signed archive instead of receiving each module. Click Publish a bundle, leave Revision empty or enter one, then Create. Expected result: a new row in Signed OPA bundles with Signed checked and its SHA-256. If it fails: conflict means the revision already exists; the button is missing when you are neither tenant_admin nor security_officer.
  2. Check the engines. OPA must run the revision just published. Read Policy engines. Expected result: in_sync is true and expected_revision is the new revision. If it fails: reachable: false shows the error of OPA; wait for its next poll and reload the page.

Troubleshooting​

SymptomCauseFix
forbidden (HTTP 403) on create, edit or deleteYour roles are neither tenant_admin nor security_officer.Ask for one of these roles.
validation_error (HTTP 422) on createName outside ^[a-z0-9][a-z0-9_.-]{0,99}$, or "rego is required for engine opa".Fix the name, or fill Rego (OPA).
validation_error with contract: policy-contract on RunThe request does not follow the Policy Contract schema.Start again from the prefilled example.
conflict (HTTP 409)A policy with this name, or a bundle with this revision, already exists.Choose another name or revision.
policy_engine_unavailable (HTTP 503)The Control Plane could not push the Rego module to OPA, or remove it on a delete (nothing is deleted then).Check that OPA runs, or use the bundle delivery.
not_found on the detail panelThe policy was deleted, or its identifier is not a UUID.Refresh the table.
Policy engines or Signed OPA bundles show forbiddenThese reads need tenant_admin, security_officer or auditor.Ask for one of these roles.
tenant_required (HTTP 403)The account acts without a tenant.Sign in with an account of the tenant.