Skip to content

Revoke a platform admin's access

Use this procedure when a Novalien staff member leaves the platform-admin roster — voluntary departure, role change out of on-call, or suspected compromise. Platform admin access spans every customer org (via scoped impersonation), so revocation is higher-stakes than revoking a normal user. This page covers the product-side revocation; adjacent systems (Slack, PagerDuty, VPN, 1Password) are listed because a platform admin with partial access is more dangerous than one with none.

Procedure

  1. Get approval from at least one other platform admin. Paste the revocation request, the reason (departure/role-change/compromise), and the target email into #novavms-platform-ops. Wait for an ack from another platform admin. Self-revocation is allowed only for the compromise case and still requires the ack before the disable call.

  2. Set enabled=false on the platform_users row. Under your own platform JWT:

    Terminal window
    curl -X PATCH https://novavms.novalien.com/api/v1/platform/users/<id> \
    -H "Authorization: Bearer $PLATFORM_JWT" \
    -H "Content-Type: application/json" \
    -d '{"enabled": false}'

    The endpoint is PATCH /api/v1/platform/users/{id} with a body of {"enabled": false} (cloud/internal/platform/users_handler.go:45). There is no /disable sub-route and no reason field on the request — the audit trail is captured implicitly via the disabled_at timestamp on the row. Self-disable is refused with 403 (users_handler.go:118-121) so the platform tier cannot be locked out by a single admin disabling themselves. Note: the PATCH handler does NOT yet cascade-revoke the target’s active impersonation sessions, despite what US-PLAT-2 implies — see GAP-9-09. Until that ships, manually invoke POST /api/v1/platform/end-impersonation for each of the target’s active sessions, or rely on the 30-minute TTL.

  1. Rotate 2FA. Even with the account disabled, a leaked TOTP seed or hardware key should not persist. Use the admin-account console to clear the enrolled factors; the target cannot re-enrol because the account is disabled.
  1. Remove from adjacent systems. All four in the same session:

    • Slack: remove from #novavms-incidents, #novavms-platform-ops, demote to single-channel guest or deactivate.
    • PagerDuty: remove from every on-call rotation and every escalation policy they appear in.
    • VPN (Tailscale): tag their node disabled, expire the node key.
    • 1Password: remove from the novavms-platform-ops vault and the shared-secrets vault.
  2. Hand over on-call duties if the target was an active responder. See Hand over on-call — do this in the same session, not later.

  3. Audit check. The platform_audit_log will NOT yet show a platform.user_disabled row — the PATCH handler does not emit an audit row today (GAP-9-09). To confirm the disable landed, query SELECT id, enabled, disabled_at FROM platform_users WHERE id = '<id>' directly. Any impersonation sessions you ended via step 2’s manual end-impersonation calls will appear as platform.impersonation_ended entries in platform_audit_log and as actor_type='platform_admin_impersonating' rows in each target org’s audit log.

Common variations

  • Suspected compromise, not clean departure: run this procedure first, then escalate to security. Do not wait for full forensic confirmation — revoke first, investigate after. The audit trail survives the disable.
  • Temporary suspension (medical leave, investigation): use the same disable call. Re-enable when the suspension ends. The enrolled 2FA must be re-added, not restored — there is no partial-disable mode.
  • Account owned the last allow_platform_impersonation session for an org mid-investigation: the disable revokes that session too. If Legal needs the impersonation to continue, a different platform admin must mint a fresh token before step 2.