| id |
name |
namespace |
version |
status |
package |
actions |
owner |
fixtures |
caring |
activation |
metadata |
| tenant-engine.write-api.mutate |
tenant-engine Write API authorization |
tenant-engine:tenant |
v1 |
ready |
flexauth.tenant_engine.write_api |
| tenant.create |
| tenant.role.grant |
| tenant.role.revoke |
| tenant.plan.assign |
|
team:platform-security |
|
| profile |
enforce |
canonical_roles |
organization_relations |
scopes |
planes |
capabilities |
exposure_modes |
conditions |
restrictions |
| caring-0.4.0-rc2 |
false |
|
|
| level |
id |
tenant |
| Platform |
platform:tenant-engine |
tenant:platform |
|
|
|
| Create |
| Grant |
| Revoke |
| Bind |
| Audit |
|
|
|
| PrivilegeEscalationBlocked |
|
|
|
| source |
flex_auth_contract |
| examples/tenant-engine/policy_package.md |
protected-system-v0 |
|
tenant-engine Write API authorization
This package authorizes tenant-engine's write API
(TEN-WP-0003's authz.FlexAuthWriteAuthorizer). tenant-engine keeps
custody of tenant records, role-grant audit trails, and plan assignments;
flex-auth decides whether a specific write is allowed now.
Scope note: this policy governs who may call tenant-engine's admin
API (an operator/service-identity question) — it does not evaluate a
tenant's capability roles (PLTF/IAM/VEN/CUS, ADR-0014). Those are
tenant state a different protected system's policy might consult via
tenant-engine's live-lookup endpoint (FLEX-WP-0008-T03); conflating the
two would authorize the wrong thing.
Rules
import future.keywords.contains
import future.keywords.if
import future.keywords.in
valid_actions := {
"tenant.create",
"tenant.role.grant",
"tenant.role.revoke",
"tenant.plan.assign",
}
known_operators := {"tenant-engine"}
decision := {"effect": "allow", "reason": "write_api_policy_matched"} if {
allowed
} else := {"effect": "deny", "reason": first_denial} if {
true
}
allowed if {
input.resource.system == "tenant-engine"
input.action in valid_actions
input.subject.type == "service"
input.subject.id in known_operators
}
default first_denial := "no_matching_rule"
first_denial := "wrong_system" if {
input.resource.system != "tenant-engine"
} else := "unknown_action" if {
not input.action in valid_actions
} else := "wrong_subject_type" if {
input.subject.type != "service"
} else := "unknown_subject" if {
not input.subject.id in known_operators
}
Tests
package flexauth.tenant_engine.write_api_test
import future.keywords.if
import data.flexauth.tenant_engine.write_api
base_request := {
"id": "check:tenant-engine-create",
"tenant": "tenant:friendly:binky",
"subject": {"id": "tenant-engine", "type": "service"},
"action": "tenant.create",
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"}
}
test_known_operator_create_allowed if {
write_api.decision.effect == "allow" with input as base_request
}
test_role_grant_allowed if {
write_api.decision.effect == "allow" with input as {
"subject": {"id": "tenant-engine", "type": "service"},
"action": "tenant.role.grant",
"resource": {"id": "t-1", "type": "role-grant", "system": "tenant-engine"}
}
}
test_unknown_subject_denied if {
write_api.decision.reason == "unknown_subject" with input as {
"subject": {"id": "some-other-service", "type": "service"},
"action": "tenant.create",
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"}
}
}
test_wrong_system_denied if {
write_api.decision.reason == "wrong_system" with input as {
"subject": {"id": "tenant-engine", "type": "service"},
"action": "tenant.create",
"resource": {"id": "t-1", "type": "tenant", "system": "some-other-system"}
}
}
test_unknown_action_denied if {
write_api.decision.reason == "unknown_action" with input as {
"subject": {"id": "tenant-engine", "type": "service"},
"action": "tenant.delete",
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"}
}
}
test_wrong_subject_type_denied if {
write_api.decision.reason == "wrong_subject_type" with input as {
"subject": {"id": "tenant-engine", "type": "human"},
"action": "tenant.create",
"resource": {"id": "t-1", "type": "tenant", "system": "tenant-engine"}
}
}