Privasys
Enclave Vaults

Access Control

KeyPolicy, principals, OIDC roles, attestation profiles, and live human approvals for Enclave Vaults.

Every key in Enclave Vaults carries a KeyPolicy that controls who can do what, under which attestation conditions, and with which approvals. The policy is part of the sealed state of the vault and is enforced inside the enclave on every call. There is no admin override.

Principals

The vault recognises three kinds of principal.

PrincipalAuthenticationTypical role
OIDC subjectBearer JWT validated against the configured issuer and audience via JWKSOwner, manager, auditor (humans or service accounts).
Attested enclaveMutual RA-TLS; the caller's SGX or TDX quote, MRENCLAVE, and config Merkle root are extracted from the peer X.509 certificateA CI runner, a confidential VM, another enclave.
FIDO2 wallet credentialSigned IssueApprovalToken request from a registered Privasys WalletLive human approval for sensitive operations.

A single call may need to satisfy several principals at once (for example, a calling enclave with the right MRENCLAVE, a manager OIDC token, and a fresh wallet approval).

OIDC roles

The default OIDC roles checked by the vault. Custom roles can be added per deployment.

RoleOperations
vault:ownerCreate and delete keys, update KeyPolicy, list keys, run any operation on owned keys, drive the pending-profile lifecycle (StagePendingProfile, PromotePendingProfile).
vault:managerIssue ApprovalTokens for operations that require live approval. Cannot read, create, or modify keys.
vault:auditorRead the audit log. Cannot perform any operation on keys.

The split between owner and manager is intentional. It keeps a defence-in-depth boundary even if the owner identity is compromised, because sensitive operations still require a separate manager approval.

KeyPolicy

The policy attached to each key is organised into three independent surfaces.

principals

Who is recognised at all for this key: the owner, optional managers, optional auditors, plus optional TEE, FIDO2, and mTLS principals. A principal that is not listed here cannot influence the key in any way.

operations

Per-operation rules of the form "operation X is allowed for principal P when condition C holds". Conditions are composable:

ConditionMeaning
AttestationMatches(profile)The caller presented an RA-TLS certificate whose quote matches profile.
ManagerApproval { manager, fresh_for }A ManagerApproval token from manager, signed within fresh_for, accompanies the request.
TimeWindow { from, until }The current time is inside the window.
CallerHoldsRole(role)The caller's OIDC token includes role.
All(...), Any(...), Not(...)Boolean combinators.

The same operation can have several rules, and all matching rules must succeed for the operation to be allowed.

mutability

Which fields of the policy can change, and under what conditions. The schema separates fields the owner can edit unilaterally, fields the owner can edit only with a quorum of manager approvals, and fields that are immutable for the life of the key. For example, on a platform-managed key, the platform's manager identity is allowed to add a new MRENCLAVE to the attestation profile but cannot change the owner or change auto_migrate_to_next_attestation_profile.

Attestation profiles

An attestation profile describes what a calling enclave must look like.

FieldPurpose
mrenclaveRequired SGX MRENCLAVE (hex).
mrsignerOptional SGX MRSIGNER (hex). Useful for accepting any release signed by a known build pipeline.
mrtdTDX measurement, for confidential VM callers.
config_merkle_rootOptional commitment to the caller's runtime configuration. Lets the policy require not just the right code, but the right configuration of that code.
required_oidsList of (oid, expected_value) claims that must appear in the caller's RA-TLS certificate.

A KeyPolicy typically lists more than one profile (for example, "the production CI enclave plus the on-call recovery enclave") so that operations can continue across deploys without policy churn.

Approval tokens

For operations that require a live human approval, the manager issues an ApprovalToken against a specific key handle and operation:

IssueApprovalToken {
  key_handle: "k-7f3...",
  operation:  "Sign",
  not_before: 2026-04-29T10:00:00Z,
  not_after:  2026-04-29T10:05:00Z,
  nonce:      <random>,
  signed_by:  <wallet FIDO2 credential>
}

The token is signed by the manager's FIDO2 credential through the Privasys Wallet and carries a short TTL. The wallet performs a fresh user-presence ceremony for each token. The vault verifies the signature, the nonce, the TTL, the key handle, and the operation name before counting the token towards the policy's ManagerApproval requirement.

A manager compromised on its own cannot use a stolen token outside its TTL. A calling enclave compromised on its own cannot mint a token. Both must cooperate, and the audit log records every issued and consumed token.

How a typical call is evaluated

For a sensitive Sign call by a CI enclave:

  1. The CI enclave opens a mutual RA-TLS channel to a vault. The vault verifies that the CI enclave's MRENCLAVE matches at least one attestation_profile on the key.
  2. The CI enclave's request envelope carries an OIDC bearer token. The vault verifies the token via JWKS and reads sub and roles. The owner check passes.
  3. The request includes one or more ApprovalTokens from the manager. The vault verifies each (signature, TTL, key handle, operation, nonce). The count must reach the policy's manager-approval threshold.
  4. The vault performs the Sign operation inside the enclave. The signature is returned to the caller. The raw key never leaves the enclave.
  5. Every step is appended to the audit log.

If any check fails, the operation is refused and the failure is logged.

Auditability

Read access to the audit log requires the vault:auditor role and a mutual RA-TLS channel. Each entry is hash-chained to the previous one, so an auditor can detect tampering with the log itself. Streaming export of the log to an external append-only store is on the roadmap; today the log is pulled on demand.

Why this is more than RBAC plus attestation

Classical RBAC says "this user can do this thing". The vault adds two orthogonal axes:

  • The calling code's identity must match. Not just the user, but the exact enclave binary that is acting on the user's behalf. This is what eliminates "secret leaked from a CI runner" as a threat.
  • A fresh act of human consent can be required. Not a long-lived token, but a per-operation FIDO2 ceremony on a phone. This is what eliminates "compromised long-lived credential" as a threat for the operations you care most about.

Combined with the per-vault sealed storage and (for RawShare keys) the Shamir distribution that prevents any single vault from leaking a secret on its own, these properties produce a system where the cost of misuse is high enough to actually deter it, even against a determined insider.

Edit on GitHub