BetterIAM
Privileged access

Privileged access

Keep standing privilege low and access time-bound with eligible roles, expiring identities, access packages, reports, and configuration as code.

Most breaches and audit findings involve access that nobody needed any more: an administrator role granted for one incident and never removed, a contractor account that outlived the contract, an API key nobody remembers issuing. The longer powerful access sits unused, the more likely it is to be misused or stolen.

The privileged access features attack that problem from two sides. They keep (powerful access someone holds all the time) close to zero, and they put an end date on access so it goes away without anyone remembering to remove it. This section explains how the pieces fit; the authorization guides cover the building blocks such as roles and temporary access.

Standing versus eligible roles

A connects a role to a person or group. By default a binding is standing: the role applies whenever the binding exists. That is right for everyday access, such as an editor role for a writer, but wrong for an administrator role that is needed a few times a month.

Three properties narrow a binding without changing the role:

PropertyWhat it doesWhen to use it
startsAtFuture-dates the binding. It is listed with its start date but grants nothing until then.Access that begins on the first day of a contract.
expiresAtMakes the binding temporary. It stops granting at that instant and the purge worker deletes it. Group memberships can carry an expiresAt too, which ends every grant and activation the membership carried.Projects, contracts, and anything with a known end.
windowMakes the binding recurring ({ from, to, timeZone, days? }): it applies only inside the hours and days you name, in that time zone.Support staff who work business hours.

An (eligible: true) goes further. It records that someone may hold a role, but grants nothing by itself. When the person needs the role, they activate the binding with bindings.activate, and the role applies only for a bounded time: maxActivationMs, one hour by default and seven days at most. Each such period is an .

Use eligibility for administrator, auditor, incident-response, and production-access roles. The person is entitled to the role but holds it only while they need it, and every activation leaves a record with a reason.

Engineers may take the production admin role for up to two hours
await iam.api.bindings.create(credential, {
  tenantId,
  roleId: productionAdmin.id,
  subjectType: 'group',
  subjectId: engineers.id,
  eligible: true,
  maxActivationMs: 2 * 3_600_000,
  requireJustification: true,
  requireMfa: true,
});

Just-in-time elevation covers activation, approvals, approver groups, and the organization-wide rules.

The lifecycle at a glance

Access has a life: it starts when someone joins or takes on a task, changes as they work, and should end when they move on. Each stage has a feature that makes it automatic.

  • Joining. An is a named set of roles and group memberships granted together, such as an onboarding kit. Assigning a package grants the whole set in one call, a package rule grants it to everyone who matches (for example everyone in engineering), and startsAt lets access begin on a set day.
  • Working. The everyday baseline is small. Privileged roles are eligible and activated for a bounded time, with a justification, MFA, or a second person's approval.
  • Changing. expiresAt ends identities, bindings, memberships, and package assignments by themselves. The access report shows what ends soon, and its emails tell owners and the people themselves.
  • Leaving. identities.offboard disables a person and removes everything that granted them access in one transaction, handing what they owned to a successor.

Every step is audited. The lifecycle events, such as binding:activate when someone elevates or identity:expire when an account runs out, can be sent to a for alerting.

In this section

Putting it together

A common baseline for an organization, in five steps:

Nobody holds a standing administrator role

Put everyone in an Everyone group and give that group a Member role with iam:bindings:activate, the permission to activate bindings one is eligible for. Add iam:packages:request if members may ask for access packages themselves.

const member = await iam.api.roles.create(credential, {
  tenantId,
  name: 'Member',
  permissions: ['iam:bindings:activate', 'iam:packages:request'],
});
await iam.api.bindings.create(credential, {
  tenantId,
  roleId: member.id,
  subjectType: 'group',
  subjectId: everyone.id,
});

Privileged roles are eligible

Bind administrator and production roles to the relevant groups as eligible, with requireJustification and requireMfa. For the most sensitive roles add requireApproval with a named approver group, so a second person signs off every activation. A tenant access policy can make these rules the minimum for every eligible binding at once.

Contractors and integrations expire

Give contractors an expiresAt, so their accounts stop working on the last day of the contract. Give integrations scoped, labeled API keys whose last use you can review. See access lifecycle.

A nightly job keeps it honest

Schedule three jobs. purge (iam.purgeDeleted()) disables expired identities and deletes expired grants. report prints the access report for a channel or ticket. config-plan --fail-on-drift fails when production no longer matches the reviewed configuration file. When the deployment sends email, add digest (the report emailed to owners) and remind (a note to each person whose access ends soon). See scheduling.

better-iam purge --config better-iam.config.mjs
BETTER_IAM_TOKEN=... better-iam report --config better-iam.config.mjs --tenant TENANT_ID
BETTER_IAM_TOKEN=... better-iam config-plan --config better-iam.config.mjs --tenant TENANT_ID --input tenant.json --fail-on-drift

Leavers are offboarded

When someone leaves, call identities.offboard with a successor. It disables the account, removes every grant, and hands the resources and reports the leaver owned to the successor.

Was this page helpful?

Better IAM is created by Sean Filimon

Last updated

On this page