Runbooks/Vault Operations

Vault Operations

Operator runbook for IdentityMesh Vault, the privileged-account checkout module: one-time credential release, the one-time credential link, scheduled rotation, the source-missing sweep, rotation targets, and scopes. Everything on this page is new in this release, so treat the first rollout as an acceptance run.

This page is not about the HashiCorp Vault secret-store backend. That is the secret-store provider IdentityMesh can use to hold its own connector secrets, and it is documented in secrets-vault.md. IdentityMesh Vault is the feature that governs privileged accounts in your directories, regardless of which secret-store backend you chose. The two share a word and nothing else.

Credential shown once

A check-out session releases its credential exactly once. The first POST /api/vault/sessions/{id}/view by the requester marks the session viewed and returns the password. A second call returns 409 Conflict with the time of the first view and the way out: check the account in and request it again.

The one view is a single budget shared with the one-time link below. Issuing a link spends it, so a session that has minted a link cannot also be viewed in the portal, and the other way round.

Only the operator who checked the account out can view or mint a link (403 otherwise). Both routes are gated on vault.credential.read and rate-limited by the sensitive limiter.

Sometimes the person who checked an account out is not the thing that needs the password: a service desk hands it to a field technician, or an automation job needs it once. The portal’s Copy one-time link button mints a single-use token and puts it on the clipboard without ever displaying the password.

# Requester only: mint a single-use token for an active, unviewed session.
curl -X POST https://identitymesh.contoso.com/api/vault/sessions/$SESSION_ID/credential-token \
     -H "Authorization: Bearer $TOKEN"
{
  "token": "…",
  "redeemUrl": "https://identitymesh.contoso.com/api/vault/credential/redeem",
  "expiresUtc": "2026-09-23T15:00:00Z"
}

The token expires with the session, so a link minted near the end of a check-out window is short-lived by design. A refusal (session closed, expired, already viewed, already linked) comes back as 409 naming the reason.

The recipient redeems it once, with no portal account:

curl -X POST https://identitymesh.contoso.com/api/vault/credential/redeem \
     -H "Content-Type: application/json" \
     -d '{ "token": "…" }'
{ "credential": "…", "expires_utc": "2026-09-23T15:00:00Z" }

Redeem is anonymous and rate-limited. The token travels in the request body, never the path or query string, so no proxy or request log captures it. Every miss (unknown, spent, expired, session closed) answers 404 and nothing else, so the route cannot be used as an oracle for guessing tokens. Once redeemed the session counts as viewed, and the portal’s Show password on that session returns 409.

If the operator’s browser has no clipboard access (a hardened kiosk, a remote session), the portal falls back to a modal that hides its Copy button and selects the token text on click, so it can still be copied by hand.

Scheduled rotation

Rotation on check-in and on expiry closes the window an operator was holding. It does nothing for an account nobody has checked out in two years, whose password a service desk once saw. The schedule is the timer that closes that.

Policy cadence

Each Vault policy carries an optional rotation cadence in days (the Rotate every field on the policy form, scheduledRotationEveryDays on PATCH /api/vault/policies/{id}, gated on vault.admin).

What the sweep skips

Settings

Both keys live in the Admin API’s appsettings.json (C:\Program Files\IdentityMesh\api\appsettings.json); the sweep runs inside the Admin API service, so restart IdentityMeshAdmin after a change.

KeyDefaultMeaning
IdentityMesh:Vault:ScheduledRotationSweepMinutes60How often the sweep runs. 0 or less disables it and logs a warning at startup.
IdentityMesh:Vault:ScheduledRotationRetryHours24How long an account whose last rotation attempt failed is held off. 0 retries every pass.

The sweep logs one summary line per pass (rotated, held off, deferred), not one line per account. Per-account detail is at Debug level for whoever is chasing a specific account.

Source-missing sweep

A vaulted account is a pointer at a directory object. When that object is deleted upstream nothing else notices: the vault keeps offering the account for check-out and rotation keeps failing against a target that no longer exists. The source-missing sweep reconciles governed accounts against the Management Space.

Lifecycle

  1. An account whose Management Space row carries a delete tombstone becomes SourceMissing. New check-outs are blocked and the audit history is kept.
  2. If the row reappears (a moved OU, a botched import, a disabled account re-enabled) the account returns to Active.
  3. After the policy’s grace period (sourceMissingGraceDays, default 7) the account is Archived, with an audit row whose reason is SourceMissingGraceExpired.

Absence is not deletion. An account with no Management Space row at all is left alone. A connector that has not imported yet, an account nominated ahead of its first import, or a Management Space that was purged would otherwise mark every governed account missing and archive the lot one grace period later. Only an explicit tombstone, which is what the import path writes when an object disappears from the source, counts.

Mass-archival cap

A single pass may archive at most IdentityMesh:Vault:SourceMissingArchiveMaxPerPass accounts, default 10. Above the cap the pass archives none of them and logs an error naming the count, the cap, and the affected connectors. That many at once usually means a connector’s import scope narrowed (an OU filter, a partition credential returning a subset, an object-type scope change), not that many people leaving.

When you see that error:

  1. Check the connector’s import scope and the last import’s counters. If the scope narrowed, restore it and run an import. The accounts return to Active on the next pass.
  2. If the departures are real, raise the cap for one pass, or set it to 0 (no cap) while you understand why the batch is large, then put it back.

Settings

Both keys live in the Admin API’s appsettings.json; restart IdentityMeshAdmin after a change.

KeyDefaultMeaning
IdentityMesh:Vault:SourceMissingSweepMinutes15How often the sweep runs. 0 or less disables it.
IdentityMesh:Vault:SourceMissingArchiveMaxPerPass10Archive cap per pass. 0 means no cap. Above the cap, nothing is archived and an error is logged.

The sweep runs regardless of licence tier, for the same reason the expiry sweep does: if a licence lapses, an account whose user left should still age out.

Rotation targets

Rotation is delegated to a password setter registered for the connector type. A connector type with no setter is refused at nomination rather than half-supported.

Connector typeHow the password is setWhat the service identity needs
Active DirectoryLDAP over the connector’s own bindReset-password rights on the governed accounts
SQL ServerALTER LOGIN over the connector’s own connectionALTER ANY LOGIN on the instance
Entra IDMicrosoft Graph passwordProfile updateUser-PasswordProfile.ReadWrite.All application permission, with admin consent

SQL Server and Entra ID rotation are new in this release. A Graph rotation without the permission above fails with a message naming it. The AD connector must use LDAPS; a plain-LDAP connector is refused with LdapsRequired because the directory only accepts a password write over an encrypted channel.

The new password is staged in the secret store under a pending reference before it is written to the target, and promoted to the account’s current reference only after the target accepts it. A refused rotation therefore never loses the live credential: the current reference is untouched and the orphaned pending value is simply overwritten on the next attempt.

Scopes: access by relationship

A Vault scope binds a set of governed accounts to one or more mesh groups. Who may request an account is derived from group membership the mesh already holds (imported from AD or built by Composer rules), not from a hand-maintained list.

Behaviour change in this release: an account in no scope is refused to everyone until an administrator adds it to one. vault.admin does not bypass the rule on checkout. The previous release left unscoped accounts open to any requester. To restore that behaviour during a rollout, set:

{ "Vault": { "UnscopedAccountsOpen": true } }

in the Admin API’s appsettings.json. Leave it unset (or false) once every governed account is in a scope. Scope routes live under /api/vault/scopes and are gated on vault.admin.

Because access is derived from membership, the requester’s sign-in must resolve to exactly one mesh person. An ambiguous match (two mesh objects with the same sign-in) resolves to no access, by design.

Composer badge

An enabled Composer rule shows a badge beside its switch:

A group does not need to be provisioned anywhere to gate Vault access, which is the normal case for a break-glass or on-call group that exists only for the vault.

Approval notifications

When a check-out request needs approval, every member of the account’s approver role gets an inbox notification and, when email is set up under Settings → Email, an email. The requester gets the decision the same way: approved with the minutes granted, or denied with the reason.

See the Email runbook.

Rollout checklist

  1. Put every governed account into a scope before upgrading, or set Vault:UnscopedAccountsOpen=true for the transition and remove it afterwards.
  2. Decide a cadence per policy. Start with the schedule off (blank), confirm on-demand rotation against each target type works, then turn the schedule on.
  3. Grant User-PasswordProfile.ReadWrite.All to the Entra app registration and ALTER ANY LOGIN to the SQL connector’s login before nominating accounts on those connectors.
  4. Watch the engine log after the first source-missing pass. A mass-archival error on the first pass almost always means an import-scope problem, not a wave of leavers.
  5. Confirm audit retention covers the Vault audit table for as long as your policy requires; see audit-retention.md.