Just-in-time admin access means nobody holds production admin permanently: an engineer requests a role, someone approves it, the cloud grants it for a fixed window, and it is removed automatically. Azure does this natively with Entra Privileged Identity Management (PIM), Google Cloud with Privileged Access Manager (PAM), and AWS with IAM Identity Center plus either TEAM, an open-source tool AWS publishes, or a partner product. The hard parts are not the request form. They are break-glass access, sessions that outlive the grant, and proving to an auditor that the whole thing works.
Key takeaways
- Standing admin is the access an attacker wants and the finding an auditor writes up. Eligible-but-inactive access removes the always-on exposure without slowing incident response.
- Azure and Google Cloud have native JIT. AWS IAM Identity Center does not; TEAM or a validated partner fills the gap, and you own whichever you deploy.
- Expiry is not the same as revocation. Credentials issued just before a grant ends can stay valid for the full session duration, so keep elevated sessions short.
- Every cloud needs two tested break-glass paths that do not depend on the JIT system, the identity provider or approvers being available.
- Send grants from all three clouds to one place and review eligibility against actual use every quarter. Eligibility nobody activates is the next thing to remove.
Standing admin is what auditors and attackers both look for
A permanent Owner or AdministratorAccess assignment is useful to exactly two groups: the person who needs it twice a quarter, and whoever steals that person's session. Phished credentials, a leaked refresh token or a compromised laptop all inherit whatever the identity holds right now. If the answer is "full control of production, always", one mistake becomes an incident.
Time-bound access changes the math. Day to day the identity holds read-only or scoped roles. Privilege exists only during an approved window, with a justification attached, and the grant itself is an audit event. SOC 2 and ISO 27001 auditors ask how privileged access is approved, how long it lasts and how often it is reviewed; a JIT system answers all three with logs instead of a spreadsheet. We cover the audit side in our SOC 2 guide for startups, and the broader identity program in our IAM strategy guide.
JIT does not shrink the role. An engineer who activates Contributor has Contributor for that hour. Pair JIT with right-sized roles, or you have built an approval queue in front of the same blast radius.
Azure: PIM eligible roles
Entra PIM covers three things: Entra directory roles (Global Administrator, Privileged Role Administrator and so on), Azure resource roles on management groups, subscriptions and resource groups, and PIM for Groups, which makes membership of a security group itself time-bound. It needs Microsoft Entra ID P2 or Microsoft Entra ID Governance licenses for everyone with an eligible or time-bound assignment, everyone who approves activations and everyone who performs access reviews.
The model has two assignment types. Active means the role works now. Eligible means the user can activate it, subject to the role's settings: maximum activation duration (one to 24 hours), MFA on activation, justification, ticket number and approval. The target state is eligible-only for every privileged role, with active permanent assignments reserved for break-glass accounts.
There are no native az commands for PIM, so call the Azure Resource Manager API through az rest. This makes an on-call group eligible for Contributor on a subscription for 180 days:
SUB=$(az account show --query id -o tsv)
ROLE=b24988ac-6180-42a0-ab88-20f7382dd24c # Contributor
GROUP=$(az ad group show --group "sre-oncall" --query id -o tsv)
cat > eligible.json <<EOF
{
"properties": {
"principalId": "$GROUP",
"roleDefinitionId": "/subscriptions/$SUB/providers/Microsoft.Authorization/roleDefinitions/$ROLE",
"requestType": "AdminAssign",
"justification": "On-call eligibility, reviewed quarterly",
"scheduleInfo": {
"startDateTime": "2026-03-12T00:00:00Z",
"expiration": { "type": "AfterDuration", "duration": "P180D" }
}
}
}
EOF
az rest --method put \
--url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Authorization/roleEligibilityScheduleRequests/$(uuidgen)?api-version=2020-10-01" \
--body @eligible.jsonEach role at each scope has a role management policy. Tighten it so activations last at most two hours and require MFA, a justification and a ticket number:
POLICY=$(az rest --method get \
--url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Authorization/roleManagementPolicies" \
--url-parameters api-version=2020-10-01 \
"\$filter=roleDefinitionId eq '/subscriptions/$SUB/providers/Microsoft.Authorization/roleDefinitions/$ROLE'" \
--query "value[0].name" -o tsv)
cat > policy.json <<'EOF'
{
"properties": {
"rules": [
{
"id": "Expiration_EndUser_Assignment",
"ruleType": "RoleManagementPolicyExpirationRule",
"isExpirationRequired": true,
"maximumDuration": "PT2H",
"target": { "caller": "EndUser", "operations": ["All"], "level": "Assignment",
"targetObjects": null, "inheritableSettings": null, "enforcedSettings": null }
},
{
"id": "Enablement_EndUser_Assignment",
"ruleType": "RoleManagementPolicyEnablementRule",
"enabledRules": ["MultiFactorAuthentication", "Justification", "Ticketing"],
"target": { "caller": "EndUser", "operations": ["All"], "level": "Assignment",
"targetObjects": null, "inheritableSettings": null, "enforcedSettings": null }
}
]
}
}
EOF
az rest --method patch \
--url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Authorization/roleManagementPolicies/$POLICY?api-version=2020-10-01" \
--body @policy.jsonAdd an Approval_EndUser_Assignment rule with a group of approvers for roles like Owner and User Access Administrator. An engineer then activates for themselves with a SelfActivate request against the same API, pointing at their eligibility with linkedRoleEligibilityScheduleId and asking for a duration inside the policy:
{
"properties": {
"principalId": "<engineer-object-id>",
"roleDefinitionId": "/subscriptions/<sub-id>/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
"requestType": "SelfActivate",
"linkedRoleEligibilityScheduleId": "<eligibility-schedule-id>",
"justification": "INC-4821 failed deployment rollback",
"scheduleInfo": { "expiration": { "type": "AfterDuration", "duration": "PT1H" } }
}
}Entra directory roles use the same model through Microsoft Graph, under roleManagement/directory (roleEligibilityScheduleRequests to assign, roleAssignmentScheduleRequests to activate). Once it works, manage eligibility as code so changes get reviewed.
GCP: Privileged Access Manager entitlements
Google Cloud's Privileged Access Manager has been generally available since September 2024. You define an entitlement on a project, folder or organization: who may request it, which IAM roles it grants, the maximum duration and whether a grant needs approval. A request creates a grant; once approved, PAM adds the role bindings and removes them when the duration ends.
An entitlement for production SRE access, defined as YAML:
privilegedAccess:
gcpIamAccess:
resourceType: cloudresourcemanager.googleapis.com/Project
resource: //cloudresourcemanager.googleapis.com/projects/prod-payments
roleBindings:
- role: roles/cloudsql.admin
- role: roles/compute.instanceAdmin.v1
maxRequestDuration: 7200s
eligibleUsers:
- principals:
- group:sre-oncall@example.com
approvalWorkflow:
manualApprovals:
requireApproverJustification: true
steps:
- approvalsNeeded: 1
approvers:
- principals:
- group:sre-leads@example.com
requesterJustificationConfig:
unstructured: {}
additionalNotificationTargets:
adminEmailRecipients:
- security-alerts@example.comCreate it, request a grant, and approve it:
gcloud pam check-onboarding-status --project=prod-payments --location=global
gcloud pam entitlements create prod-sre-admin \
--project=prod-payments --location=global \
--entitlement-file=prod-sre-admin.yaml
# Engineer requests one hour
gcloud pam grants create \
--entitlement=prod-sre-admin --project=prod-payments --location=global \
--requested-duration=3600s \
--justification="INC-4821: Cloud SQL failover stuck"
# Approver finds and approves it
gcloud pam grants search --entitlement=prod-sre-admin \
--project=prod-payments --location=global --caller-relationship=can-approve
gcloud pam grants approve GRANT_ID \
--entitlement=prod-sre-admin --project=prod-payments --location=global \
--reason="Matches open incident"Constraints to design around: the maximum request duration must sit between 30 minutes and 168 hours. In the v1 API an approval workflow has a single step needing one approval, so "two people must approve" is not something the GA entitlement expresses. Role bindings can carry an IAM condition to scope a grant further, though tags are not supported in those conditions. Grant events land in Cloud Audit Logs under the privilegedaccessmanager.googleapis.com service, which is what you export for reviews.
AWS: Identity Center plus TEAM or an approval workflow
IAM Identity Center has no built-in request-and-approve feature. AWS's own documentation points to validated partner integrations (CyberArk, Okta and Tenable among them) and to TEAM, the Temporary Elevated Access Management solution it publishes on GitHub under the MIT-0 license. TEAM has had regular releases since 2023, most recently in January 2026.
TEAM is a serverless application: an Amplify front end reached from the Identity Center portal, AppSync and DynamoDB for requests and policies, Step Functions for the workflow, and CloudTrail Lake for session activity logs. On approval it creates an Identity Center account assignment; at the end of the window it deletes it. It runs in the account delegated to administer Identity Center and, by design, cannot grant access to the management account.
AWS describes TEAM as sample code that you are responsible for testing, securing and running in production, so treat it as a privileged system you operate. The mechanism underneath is two API calls, and a small Step Functions workflow behind your ticketing system can drive them directly:
# On approval: grant
aws sso-admin create-account-assignment \
--instance-arn "$SSO_INSTANCE_ARN" \
--target-id 111122223333 --target-type AWS_ACCOUNT \
--permission-set-arn "$PS_PROD_ADMIN" \
--principal-type USER --principal-id "$USER_ID"
# Assignment is asynchronous: poll the request until it succeeds
aws sso-admin describe-account-assignment-creation-status \
--instance-arn "$SSO_INSTANCE_ARN" \
--account-assignment-creation-request-id "$REQUEST_ID"
# At expiry: revoke
aws sso-admin delete-account-assignment \
--instance-arn "$SSO_INSTANCE_ARN" \
--target-id 111122223333 --target-type AWS_ACCOUNT \
--permission-set-arn "$PS_PROD_ADMIN" \
--principal-type USER --principal-id "$USER_ID"Whichever you choose, set the elevated permission set's session duration to the minimum. Identity Center session durations run from one to 12 hours, and removing an assignment stops new sessions but does not end credentials already issued:
aws sso-admin update-permission-set \
--instance-arn "$SSO_INSTANCE_ARN" --permission-set-arn "$PS_PROD_ADMIN" \
--session-duration PT1H
aws sso-admin provision-permission-set \
--instance-arn "$SSO_INSTANCE_ARN" --permission-set-arn "$PS_PROD_ADMIN" \
--target-type ALL_PROVISIONED_ACCOUNTSOne request flow across three clouds
Engineers do not want three request portals. There are two workable designs.
Identity provider in front. If Entra ID is your identity provider for all three clouds, PIM for Groups can be the single request point. Each privileged group maps to a permission set in Identity Center and to IAM bindings in Google Cloud, and activating membership grants access once the group change reaches the cloud. The catch: membership travels by SCIM provisioning, which runs on a cycle (roughly every 40 minutes for the standard incremental run), so measure activation-to-access latency before you promise it to on-call engineers. Dynamic groups and groups synchronized from on-premises Active Directory cannot be used with PIM for Groups.
Native per cloud, shared evidence. Engineers request in each cloud's own tool, and the shared layer is the evidence: one log store holding every grant, one review, one set of approver groups maintained in the identity provider. Grants take effect within the cloud's own control plane, with no provisioning hop.
| Identity provider in front | Native per cloud | |
|---|---|---|
| Request experience | One portal | One per cloud |
| Time to access | Bounded by provisioning cycle | Minutes, inside the cloud's control plane |
| Revocation | Depends on the sync, plus session lifetime | Cloud removes the binding directly |
| Licensing | Entra ID P2 or ID Governance for eligible users and approvers | Per cloud (PIM licenses for Azure; TEAM runs on billed AWS services) |
| Failure mode | Identity provider or sync outage blocks all three clouds | Each cloud fails independently |
We usually start native, because each cloud's grant is enforced where the access is used, and add the identity provider layer only when request volume justifies it.
Break-glass done right
JIT adds a dependency: if PIM, PAM, TEAM, the identity provider or every approver is unavailable, nobody can get in. Break-glass access is the path that works anyway, and it must not depend on any of them.
- Azure: at least two cloud-only emergency accounts on the
onmicrosoft.comdomain, not federated or synced, with Global Administrator as a permanent active assignment. Microsoft recommends phishing-resistant, passwordless sign-in for them (FIDO2 passkeys or certificate-based authentication), different from your normal admin method, and excluding them from Conditional Access policies that block sign-in. One PIM trap: if every Global Administrator and Privileged Role Administrator is eligible-only, approval is required and no approvers are configured, the tenant is locked. - AWS: a path that works when Identity Center is down, such as direct SAML federation from your identity provider into critical accounts or dedicated break-glass IAM users with hardware MFA, plus the root user protected with MFA. TEAM depends on regional services, so it is not your emergency path.
- GCP: more than one super administrator account, each separate from the person's daily account and protected with security keys, plus an organization-level admin path that does not go through PAM.
Store credentials in two physically separate places, alert on every use (Entra sign-in logs, CloudTrail ConsoleLogin, Cloud Audit Logs), and test each account at least every 90 days. Write the procedure into your incident response playbook so whoever is on call at 3 a.m. does not have to find it.
Automating entitlement reviews
A review has two inputs: who is eligible for what, and what was actually activated. Pull both from each cloud on a schedule.
# Azure: eligibility at subscription scope, and PIM activations in Entra
az rest --method get \
--url "https://management.azure.com/subscriptions/$SUB/providers/Microsoft.Authorization/roleEligibilitySchedules?api-version=2020-10-01" \
> azure-eligible.json
az rest --method get \
--url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleRequests" \
--query "value[?action=='selfActivate'].{who:principalId, role:roleDefinitionId, at:createdDateTime, why:justification, status:status}" \
> entra-activations.json
# GCP: entitlements and their grants
gcloud pam entitlements list --project=prod-payments --location=global --format=json > gcp-entitlements.json
gcloud pam grants list --entitlement=prod-sre-admin \
--project=prod-payments --location=global --format=json > gcp-grants.json
# AWS: Identity Center assignment events (Event history keeps 90 days; run in the Identity Center Region)
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=CreateAccountAssignment \
--start-time 2025-12-12T00:00:00Z --output json > aws-assignments.jsonThe review logic is simple. Eligibility never activated in the quarter gets removed unless the owner writes down why it stays (on-call rotation, DR role). Activations without a ticket reference get followed up. Anyone who activated the same role every working day needs a properly scoped standing role instead. Entra access reviews can run this natively for PIM roles and remove access when reviewers do not respond. Keep the exported files: CloudTrail Event history only covers 90 days, Entra keeps audit logs for 30 days on P1 and P2, and for PAM the durable record is Cloud Audit Logs rather than the grant list, so route all three to storage you control. This is the same evidence trail a zero-trust architecture depends on.
Native vs third-party PAM
| Need | Native tools | Third-party platform |
|---|---|---|
| JIT for cloud control plane roles | Covered in Azure and GCP; AWS via TEAM or DIY | Covered, one policy model |
| One request UI across clouds | No, unless you put the IdP in front | Yes |
| Multi-step approvals, on-call schedule integration | Limited and different per cloud | Usually built in |
| SSH, RDP, database and Kubernetes session access | Not covered | Often covered, with session recording |
| Cost | Licenses you may already own, plus AWS compute for TEAM | Separate contract |
| New attack surface | Low, inside each provider | A system that can grant admin in every cloud |
Native first is the right default for most teams with a few dozen privileged users or fewer. A platform earns its cost when you need one policy model across clouds, session recording, or approvals wired into an on-call tool, and when you will protect it as the most privileged system you run.
What goes wrong in production
- Sessions outlive the grant. AWS credentials issued a minute before TEAM removes the assignment stay valid for the permission set's session duration, up to 12 hours. Keep elevated permission sets at one hour and keep a deny-based revocation path for real incidents.
- Permission set roles get recreated. When the last assignment of a permission set in an account is deleted, Identity Center deletes the
AWSReservedSSO_role. The next grant creates a new role with a different suffix, which breaks KMS key policies and EKSaws-authentries that referenced the old ARN. Keep one permanent assignment of that permission set in accounts where policies reference it, or reference a role you create in IAM. - Terraform removes JIT bindings. Authoritative IAM resources such as
google_project_iam_policyorgoogle_project_iam_bindingrewrite the whole policy or role on the next apply and will strip an active PAM grant. Use non-authoritative member resources on anything PAM manages. - The activation request fails policy. A
SelfActivaterequest asking for longer than the role's maximum is rejected withRoleAssignmentRequestPolicyValidationFailednaming theExpirationRule; a missing justification or ticket number fails withJustificationRuleorTicketingRule. Put the limits in your runbook so engineers do not discover them during an incident. - License expiry changes access silently. If Entra ID P2 or ID Governance licenses lapse, eligible assignments are removed and active time-bound assignments become permanent. That is the opposite of what you want.
- Approvers are the outage. A single approver group in one time zone turns a 2 a.m. incident into a wait. Approver coverage needs the same rotation planning as on-call.
Frequently Asked Questions
What is the best way to manage privileged access across AWS, Azure and GCP?
Remove standing admin and make every privileged role something a person requests, gets approved for and loses automatically. Use Entra PIM eligible assignments in Azure, Privileged Access Manager entitlements in Google Cloud, and IAM Identity Center with TEAM or a partner tool in AWS. Keep two tested break-glass paths per cloud and send every grant to one log store for a quarterly review.
Does AWS have native just-in-time access?
Not as a built-in IAM Identity Center feature. AWS points customers to validated partner integrations and to TEAM, an open-source solution it publishes that creates and deletes Identity Center account assignments on a schedule after approval. You can also build a small approval workflow on the same Identity Center APIs, but you own its security and uptime.
What is Google Cloud Privileged Access Manager?
Privileged Access Manager (PAM) is Google Cloud's native just-in-time access service, generally available since September 2024. An administrator defines an entitlement listing who may request it, which IAM roles it grants on a project, folder or organization, the maximum duration and an optional approval step. Approved grants add the role bindings and PAM removes them when the duration ends, with every step written to Cloud Audit Logs.
What is the difference between PIM and PAM?
PIM, Privileged Identity Management, is Microsoft's name for its Entra feature that makes roles eligible and activated on demand. PAM, privileged access management, is the general industry term for controlling admin access, and it is also the name of Google Cloud's Privileged Access Manager. Commercial PAM suites often add password vaulting and session recording for servers and databases, which the cloud-native tools do not cover.
How do you automate cloud entitlement reviews?
Export who is eligible for which privileged role and every activated grant, from all three clouds, on a schedule. Eligibility that nobody activated during the quarter is a removal candidate. Use Entra access reviews for PIM roles, gcloud for PAM entitlements and grants, and CloudTrail for Identity Center assignment events, then send the result to owners to confirm or remove.
Can one tool provide JIT access across all three clouds?
Yes, third-party platforms and identity provider driven designs can front all three clouds with one request flow. The cost is another highly privileged system to secure, provisioning delays and sessions that can outlive the approved window. Many teams get further with the native tool in each cloud plus one shared log and review process.
Need help with cloud IAM?
We design cloud access for teams that run production, then stay on the hook for it: eligibility models, approval paths, break-glass procedures and the review evidence auditors ask for. Senior engineers do the work, and if we built it, we're on the pager for it.
