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.
One-time credential link
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).
- Blank means rotate only on check-in or expiry. This is the default and matches the previous release.
- A number of days rotates every governed account under that policy once that many days have passed since its last rotation. A never-rotated account dates its cadence from nomination.
- Blanking the field on an existing policy switches the
schedule off for every account under it. There is no separate
enable toggle. Through the API, send
0in the PATCH to clear it; omitting the field leaves the cadence unchanged.
What the sweep skips
- Checked-out accounts are deferred, not rotated. Rotating under a live session pulls the password out from under the operator holding it. The account stays due and the next pass after check-in (or check-in’s own rotation) picks it up.
- Only Active accounts are considered.
SourceMissingaccounts are mid-grace-period andArchivedones are refused by the rotation path anyway. - Failing accounts are held off. A failed rotation leaves the
account Active with its last-rotated stamp untouched, so without
a backoff it would be due again on the very next pass and write
a
RotationFailedaudit row every hour, forever. The backoff isIdentityMesh:Vault:ScheduledRotationRetryHours, default24; set it to0to retry on every pass.
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.
| Key | Default | Meaning |
|---|---|---|
IdentityMesh:Vault:ScheduledRotationSweepMinutes | 60 | How often the sweep runs. 0 or less disables it and logs a warning at startup. |
IdentityMesh:Vault:ScheduledRotationRetryHours | 24 | How 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
- An account whose Management Space row carries a delete tombstone becomes SourceMissing. New check-outs are blocked and the audit history is kept.
- If the row reappears (a moved OU, a botched import, a disabled account re-enabled) the account returns to Active.
- After the policy’s grace period (
sourceMissingGraceDays, default7) the account is Archived, with an audit row whose reason isSourceMissingGraceExpired.
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:
- 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.
- 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.
| Key | Default | Meaning |
|---|---|---|
IdentityMesh:Vault:SourceMissingSweepMinutes | 15 | How often the sweep runs. 0 or less disables it. |
IdentityMesh:Vault:SourceMissingArchiveMaxPerPass | 10 | Archive 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 type | How the password is set | What the service identity needs |
|---|---|---|
| Active Directory | LDAP over the connector’s own bind | Reset-password rights on the governed accounts |
| SQL Server | ALTER LOGIN over the connector’s own connection | ALTER ANY LOGIN on the instance |
| Entra ID | Microsoft Graph passwordProfile update | User-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:
- Vault only means the group exists in the mesh and can be bound to a Vault scope, but is not provisioned to a target connector.
- Provisioning means the rule is also flagged to create the
group in the target connector (
imProvision=true).
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.
- Approvers open the approvals queue from the notification. Requesters land on their check-outs.
- Approver-role members come from the roles assigned in Settings. Users assigned directly are included. A group assignment counts the group’s current members.
- At most 25 approvers are notified for one request.
- Nothing is sent for self-approved requests, cancellations or expiry.
See the Email runbook.
Rollout checklist
- Put every governed account into a scope before upgrading, or
set
Vault:UnscopedAccountsOpen=truefor the transition and remove it afterwards. - 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.
- Grant
User-PasswordProfile.ReadWrite.Allto the Entra app registration andALTER ANY LOGINto the SQL connector’s login before nominating accounts on those connectors. - 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.
- Confirm audit retention covers the Vault audit table for as
long as your policy requires; see
audit-retention.md.
Related
- Vault — what IdentityMesh Vault is, how it compares, and its current scope.
audit-retention.md— the retention sweep that trims the hash-chained Vault audit table.secrets-vault.md— the HashiCorp Vault secret-store provider, which is a different thing.