Policy Definitions & Assignments
Creating and managing security policies with policy definitions and assignments
Policy definitions and assignments are the two building blocks for configuring Unified Security. A policy definition is a reusable policy template attached to a connection. An assignment binds that policy definition to an actor and fills in the concrete parameter values.
Policy Definitions
A policy definition is a connection-scoped template. It describes what security rules to apply, but not who they apply to.
Each policy definition can include any combination of:
- CLS config -- connection string or file path template with placeholders
- SLS config -- schema routing rules
- RLS config -- row-level filter rules with expressions
At least one of these must be present. A policy definition without any config is invalid.
Placeholders
Policy definitions use {{ placeholder }} syntax for values that differ per actor. Placeholders are resolved at runtime from assignment params or token securityParams.
This policy definition has three placeholders: password@secret, tenantDatabase, and tenant_id. Their values come from assignments.
Key Properties
| Property | Description |
|---|---|
name | Unique name within the connection (e.g., "Tenant Data Access") |
connectionId | The connection this policy definition applies to |
clsConfig | Connection template or file path templates with params |
slsConfig | Schema routing config |
rlsConfig | Row-level security rules |
Policy definitions are inert
A policy definition has no effect on queries until it is assigned to an actor. You can create and edit policy definitions on a connection without impacting any running dashboards.
One Policy Definition, Many Assignments
A single policy definition can be assigned to multiple actors. For example, a "Tenant Data Access" policy definition might be assigned to every tenant in your project, each with different parameter values for tenantDatabase and tenant_id.
Assignments
An assignment binds a policy definition to a specific actor scope and provides the concrete parameter values for that actor.
This assignment says: "Apply the Tenant Data Access policy definition to the Acme tenant, using database acme_prod, filtering rows where tenant_id = 'acme', and connecting with the given password."
Uniqueness
Each (policy definition, scope type, actor) combination allows at most one assignment. You cannot assign the same policy definition to the same tenant twice. To update parameter values, edit the existing assignment.
Scope Types
The scope type determines which actor the assignment targets.
| Scope | Required Fields | Description | Use Case |
|---|---|---|---|
ALL_TENANTS | (none) | Shared baseline for every tenant | Default RLS rules that all tenants inherit |
TENANT | tenantId | Targets a specific tenant | Tenant-specific database, schema, or params |
TENANT_USER | tenantUserId | Targets an end user within a tenant | Narrow access for specific users within a tenant |
ORG_USER | orgUserId | Targets an organization user | Internal employee with scoped data access |
Choosing the Right Scope
- Use
ALL_TENANTSfor rules that every tenant should share, like a common RLS predicate. - Use
TENANTwhen tenants have different databases, schemas, or parameter values. - Use
TENANT_USERwhen specific users within a tenant need additional restrictions. - Use
ORG_USERfor internal users who need access to customer data with specific constraints.
Inheritance and Merging
When a tenant user accesses data, Semaphor collects assignments from multiple scope levels and merges them in priority order.
Merge Order
For tenant-scoped actors (TENANT and TENANT_USER), assignments merge from broadest to narrowest:
Each layer can only restrict access -- never widen it. If the ALL_TENANTS layer sets an RLS rule, lower layers cannot remove it.
Merge Rules by Policy Type
| Policy | Merge Behavior |
|---|---|
| CLS | Lower layers overlay parameter values onto the inherited connection or file path structure. The template itself (connection string shape) is inherited, not replaced. |
| SLS | Lower layers select a schema within the inherited boundary. If an allowlist is set at a higher layer, lower layers can only pick schemas from that list. |
| RLS | Rules from all layers combine with AND (intersection). Lower layers can add new rules but cannot remove inherited ones. |
Example: Three-Layer Merge
The effective policy for jane@acme.com:
- SLS routes to schema
acme_data - RLS applies
tenant_id = 'acme' AND department = 'sales'
Organization Users
ORG_USER assignments are independent -- they do not participate in the tenant inheritance chain. Each org user assignment stands alone.
Parameter Sources
Parameters that fill policy definition placeholders come from three sources, applied in merge order:
1. Policy definition defaults
Parameters embedded in the policy definition config itself. These serve as defaults when no assignment or runtime param overrides them.
2. Assignment-bound params
Concrete values stored in the assignment. These are the authoritative boundary for the actor.
3. Runtime / token securityParams
Supplied at token generation time via the securityParams field. These can fill unresolved placeholders or narrow within the existing boundary, but cannot override persisted assignment values for RLS-referenced parameters.
securityParams cannot widen access
Persisted assignment params are the authoritative security boundary. Runtime securityParams supplied at token time can fill missing placeholders or narrow further, but they cannot override values that are already bound by persisted assignments. Attempting to override a persisted RLS parameter will cause a resolution error.
Unassigned Actors
If an actor has no matching assignments on a unified-mode connection, no Unified Security policy is applied. The actor uses the base connection without restrictions.
This is intentional: assignments are policy attachments, not access grants. An admin explicitly opts actors into policies by creating assignments. The absence of an assignment means "no Unified Security enforcement" -- the connection behaves as if it were in legacy mode for that actor.
Audit your assignments
Before switching a connection to unified mode, verify that all actors who need security restrictions have assignments. Use the Resolution Preview to check any actor's effective policy.
Admin Workflow
Managing Policy Definitions
- Navigate to Project Settings > Security.
- Open the Policy Definitions tab.
- Click Create Policy Definition and select a connection.
- Configure the CLS, SLS, and/or RLS settings with placeholder syntax.
- Save the policy definition.
Each policy definition targets a specific connection. You can create multiple policy definitions per connection for different policy patterns.
Managing Assignments
- Open the Assignments tab.
- Click Create Assignment.
- Select a policy definition, choose a scope type, and pick the target actor.
- Fill in the parameter values for the policy definition's placeholders.
- Save the assignment.
Resolution Preview
The Preview panel lets you test the effective security for any actor before going live. Select an actor and connection to see the resolved CLS, SLS, and RLS context -- exactly what will be enforced at query time.
Use this to verify:
- All required parameters resolve correctly
- The inheritance chain produces the expected result
- No actors are missing assignments they need
Next Steps
- Policy Types -- CLS, SLS, and RLS configuration details, matcher types, and combination semantics
- Token Integration -- supply runtime parameters and policy overlays through embed tokens
- Unified Security API -- programmatic management of policy definitions and assignments