Files
metacrypt/POLICY.md
Kyle Isom fbd6d1af04 Add policy CRUD, cert management, and web UI updates
- Add PUT /v1/policy/rule endpoint for updating policy rules; expose
  full policy CRUD through the web UI with a dedicated policy page
- Add certificate revoke, delete, and get-cert to CA engine and wire
  REST + gRPC routes; fix missing interceptor registrations
- Update ARCHITECTURE.md to reflect v2 gRPC as the active implementation,
  document ACME endpoints, correct CA permission levels, and add policy/cert
  management route tables
- Add POLICY.md documenting the priority-based ACL engine design
- Add web/templates/policy.html for policy management UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 19:41:11 -07:00

6.2 KiB

Metacrypt Policy Engine

Metacrypt includes a priority-based access control policy engine that governs which authenticated users may perform which operations on which engine resources. This document explains the policy model, rule structure, evaluation algorithm, and how to manage rules via the API and web UI.

Overview

Every request to POST /v1/engine/request is evaluated against the policy engine before being dispatched to the underlying cryptographic engine. The policy engine enforces a default-deny posture: unless a matching allow rule exists, non-admin users are denied.

Admin bypass: Users with the admin role in MCIAS always pass policy evaluation unconditionally. Policy rules only affect non-admin users.

Rule Structure

A policy rule is a JSON object with the following fields:

Field Type Required Description
id string Yes Unique identifier for the rule
priority integer Yes Evaluation order; lower number = higher priority
effect "allow" or "deny" Yes Decision when this rule matches
usernames []string No Match specific usernames (case-insensitive). Empty = any
roles []string No Match any of these roles (case-insensitive). Empty = any
resources []string No Glob patterns for the resource path. Empty = any
actions []string No "read" or "write". Empty = any

Resource Paths

Resources follow the pattern engine/<mount>/<operation>. For example:

  • engine/pki/list-certs — list certificates on the pki mount
  • engine/pki/issue — issue a certificate on the pki mount
  • engine/transit/* — any operation on the transit mount

Glob patterns use standard filepath matching (* matches within a path segment; ** is not supported — use engine/pki/* to match all operations on a mount).

Actions

Operations are classified as either read or write:

Action Operations
read list-issuers, list-certs, get-cert, get-root, get-chain, get-issuer
write All other operations (issue, renew, sign-csr, create-issuer, delete-issuer, etc.)

Evaluation Algorithm

  1. If the caller has the admin role → allow immediately (bypass all rules).
  2. Load all rules from the barrier.
  3. Sort rules by priority ascending (lower number = evaluated first).
  4. Iterate rules in order; for each rule, check:
    • If usernames is non-empty, the caller's username must match one entry.
    • If roles is non-empty, the caller must have at least one matching role.
    • If resources is non-empty, the resource must match at least one glob pattern.
    • If actions is non-empty, the action must match one entry.
    • All specified conditions must match (AND logic within a rule).
  5. The first matching rule wins; return its effect.
  6. If no rule matches → deny (default deny).

Managing Rules via the REST API

All policy endpoints require an authenticated admin token (Authorization: Bearer <token>).

List Rules

GET /v1/policy/rules

Returns a JSON array of all policy rules.

Create a Rule

POST /v1/policy/rules
Content-Type: application/json

{
  "id": "allow-users-read-pki",
  "priority": 10,
  "effect": "allow",
  "roles": ["user"],
  "resources": ["engine/pki/*"],
  "actions": ["read"]
}

Returns 201 Created with the created rule on success.

Get a Rule

GET /v1/policy/rule?id=allow-users-read-pki

Update a Rule

PUT /v1/policy/rule?id=allow-users-read-pki
Content-Type: application/json

{ ... updated rule fields ... }

Delete a Rule

DELETE /v1/policy/rule?id=allow-users-read-pki

Managing Rules via the Web UI

Navigate to Policy in the top navigation bar (visible to admin users only).

The policy page shows:

  • A table of all active rules with their ID, priority, effect, and match conditions.
  • A Create Rule form (expandable) for adding new rules.
  • A Delete button on each row to remove a rule.

Managing Rules via gRPC

The PolicyService gRPC service (defined in proto/metacrypt/v2/policy.proto) provides equivalent operations:

RPC Description
CreatePolicy Create a new rule
ListPolicies List all rules
GetPolicy Get a rule by ID
DeletePolicy Delete a rule by ID

Common Patterns

Allow users to read PKI resources

{
  "id": "allow-users-read-pki",
  "priority": 10,
  "effect": "allow",
  "roles": ["user"],
  "resources": ["engine/pki/*"],
  "actions": ["read"]
}

Allow a specific user to issue certificates

{
  "id": "allow-alice-issue",
  "priority": 5,
  "effect": "allow",
  "usernames": ["alice"],
  "resources": ["engine/pki/issue"],
  "actions": ["write"]
}

Deny guests all access to a mount

{
  "id": "deny-guests-transit",
  "priority": 1,
  "effect": "deny",
  "roles": ["guest"],
  "resources": ["engine/transit/*"]
}

Allow users read-only access to all mounts

{
  "id": "allow-users-read-all",
  "priority": 50,
  "effect": "allow",
  "roles": ["user"],
  "actions": ["read"]
}

Role Summary

Role Default access
admin Full access to everything (policy bypass)
user Denied by default; grant access via policy rules
guest Denied by default; grant access via policy rules

Storage

Policy rules are stored in the encrypted barrier under the prefix policy/rules/<id>. They are encrypted at rest with the master encryption key and are only accessible when the service is unsealed.