Access policies add attribute-based rules (ABAC) on top of roles and groups. A policy looks at who is asking, what they want to do and in what context, and permits or denies. Use policies to restrict what roles and groups would otherwise allow, for example “nobody may send critical commands from outside the plant network” or “firmware may only be assigned from a session signed in with a passkey”. Policies are an advanced tool: most organisations need only roles and groups.
You need the Owner role. Open Settings > Access Policies (address /admin/access-policies).
How a decision is made
For each guarded request:
- Every active policy whose target matches (its actions and resource types) and whose conditions all hold is collected, in priority order (lower runs first).
- If any of them denies, the request is refused. Deny always wins.
- Otherwise, if one permits, the request goes ahead.
- If no policy applies, the role, group and matrix decision stands (“RBAC fallback”).
Policies are additive restrictions: write requirements as Deny policies. A Permit policy whose conditions do not hold does not refuse anything; the request simply falls back to the role decision.
Which requests policies see
Policies are checked on routes that call the policy engine. Most pages and API routes of Hermetry do; a few do not, because there is no signed-in member to judge (sign-in itself, device connections, webhook callbacks, scheduled jobs, requests with an API key’s own contract such as SCIM). The Coverage page lists exactly which routes reach the engine and, for the others, “What guards it instead”. Check it before you rely on a policy.
Important
IoT pages and the IoT API pass the action (the permission) and the caller to policies, but no device attributes. You cannot write a policy for one device or one site, and a member who may view devices sees all devices of the organisation. If groups of people must never see each other’s devices, put those devices in separate organisations. Always test a policy in the access tester and in shadow mode first.
Create a policy
- Select New policy (or Load examples to start from ready-made policies).
- Enter a Name, the Effect (Permit, or Deny (overrides any permit)) and the Priority (lower runs first). Select Create & edit.
- In Definition, set:
- Actions (comma-separated, empty = all): permission ids such as
iot_rpc.send.critical, iot_ota.assign. - Resource types (comma-separated, empty = all).
- Description: why the policy exists.
- Status: Active or Inactive. Select Save definition.
- Actions (comma-separated, empty = all): permission ids such as
- Under Conditions, select Add condition for each test. “All conditions must hold (AND) for the policy to apply.” Select Save conditions.
A policy without conditions applies to every request that matches its target.
Conditions
Each condition is an Attribute, an Operator and a Value (or Values (comma-separated)).
| Attribute | Meaning |
|---|---|
subject.role | The built-in role: OWNER, ADMIN, USER |
subject.roles | The role plus the member’s group keys |
subject.permissions | The permissions the member’s groups grant |
subject.id, subject.email | The member |
subject.department, subject.jobTitle | From the member’s profile, when set |
subject.amr | How the session signed in: pwd, otp, mfa, hwk (passkey), fed:saml, fed:<provider> |
subject.acr | The assurance level from it: NONE, LOW (password or federated alone), SUBSTANTIAL (a verified second factor), HIGH (a passkey) |
environment.ip | The caller’s address |
environment.now, environment.method, environment.userAgent, environment.host | Time, HTTP method, browser, host name |
action | The permission being checked |
Operators: equals, not equals, in list, not in list, contains, greater than, less than, exists, matches regex, DN equals (RDN).
An absent attribute reads as empty, which satisfies not equals and not in list. That is why deny rules are safe and permit rules are not.
Examples
Deny critical and raw commands unless the session used a second factor or a passkey:
| Field | Value |
|---|---|
| Effect | Deny |
| Actions | iot_rpc.send.critical, iot_rpc.send.raw |
| Condition | subject.acr not in list SUBSTANTIAL, HIGH |
Keep members of a contractors group from writing attributes or sending commands, whatever their role:
| Field | Value |
|---|---|
| Effect | Deny |
| Actions | iot_device.attributes.write, iot_rpc.send.basic, iot_rpc.send.privileged |
| Condition | subject.roles contains contractors |
To give a right only to one group, the Access Rights matrix is usually simpler than a policy: untick the permission for Admin and tick it for the group. See Groups and permissions.
Shadow mode, the access tester and the decision log
| Tool | Where | Use |
|---|---|---|
| Shadow Mode | Settings on the policies page (Access Control Settings) | “Policies are evaluated and decisions are logged, but a “deny” NEVER blocks the request.” Off by default. Turn it on before you enforce a new policy, watch the log, then turn it off. |
| Access tester | Simulator | “Dry-run a decision against live policies — nothing is persisted or logged.” Enter Subject id, Subject role, Action, Resource type, Resource ownerId, Environment IP and an RBAC fallback role, then Evaluate. The Policy trace shows each policy’s target and rules. |
| Decision log | Decision log | Every evaluated request with Effect, Action, Reason (Policy permit, Explicit deny, RBAC fallback, Default deny, Not applicable) and Subject. Shadow-mode denies are marked Shadow. |
Decision Log Mode (All decisions, Deny only, Off; default all) and Permit Log Sample Rate (%) decide how much goes into the audit log. Denies are always logged.
Good practice
- Start with Load examples and read them before writing your own.
- Use deny policies with narrow action lists. Avoid policies with no actions: they judge every request.
- Never lock out the owners: test every policy with an owner’s role in the access tester.
- Changes take effect at once on every node.

