Most companies using AWS IAM Identity Center assign permission sets once and forget them. An engineer gets AdministratorAccess on the production account during an incident, the incident closes, and the assignment quietly stays active for months. When a SOC 2 auditor samples that account six months later, there's no way to explain why a permission that was needed for four hours is still standing — because nobody revoked it and nobody was tracking an expiration.
Just-in-time (JIT) access flips this: permission sets are granted for a bounded window, tied to a ticket or approval, and automatically expire. We build this pattern for clients running Identity Center across multi-account AWS Organizations who need standing-access exposure to shrink without slowing engineers down.
Why Standing Permission Sets Fail Audits
Identity Center permission set assignments don't have a native expiration field. Once you assign PowerUserAccess or a custom permission set to a user or group for an account, it's there until someone manually removes it. That's fine for a five-person startup. It's a liability at 100+ employees with a compliance obligation, because:
- Auditors sample active assignments and ask "why does this person have this, right now" — not "why did they need it three months ago"
- Nobody owns the removal step, so assignments accumulate rather than shrink
- Break-glass access for incidents gets granted the same way as routine access, with no distinction in the review process
The JIT Pattern We Build
The core architecture is a Step Functions workflow triggered by a ticket (Jira, ServiceNow, or a Slack workflow) that:
- Validates the requester and requested permission set against an approved catalog — not arbitrary self-service to any permission set
- Calls
sso-admin:CreateAccountAssignmentto grant the permission set for the specific account - Schedules an EventBridge rule to fire after the approved duration (commonly 4, 8, or 24 hours)
- On expiration, calls
sso-admin:DeleteAccountAssignmentautomatically, with no human step required to revoke
import boto3
from datetime import datetime, timedelta
sso = boto3.client("sso-admin")
scheduler = boto3.client("scheduler")
def grant_jit_access(instance_arn, permission_set_arn, account_id, principal_id, duration_hours=8):
sso.create_account_assignment(
InstanceArn=instance_arn,
TargetId=account_id,
TargetType="AWS_ACCOUNT",
PermissionSetArn=permission_set_arn,
PrincipalType="USER",
PrincipalId=principal_id,
)
expire_at = datetime.utcnow() + timedelta(hours=duration_hours)
scheduler.create_schedule(
Name=f"revoke-{principal_id}-{account_id}",
ScheduleExpression=f"at({expire_at.strftime('%Y-%m-%dT%H:%M:%S')})",
Target={
"Arn": "arn:aws:lambda:us-east-1:<account>:function:revoke-jit-access",
"RoleArn": "<scheduler-execution-role>",
"Input": f'{{"account_id": "{account_id}", "permission_set_arn": "{permission_set_arn}", "principal_id": "{principal_id}"}}',
},
FlexibleTimeWindow={"Mode": "OFF"},
)
Every grant and every revocation logs to CloudTrail with the originating ticket ID attached as a tag on the schedule, which becomes the evidence artifact auditors actually want: a timestamped record showing access was time-bound and automatically removed, not manually tracked in a spreadsheet someone forgets to update.
What Changes for Engineers
The friction concern is legitimate — nobody wants to file a ticket every time they need to check a CloudWatch log. The pattern we deploy typically tiers access: read-only or low-risk permission sets stay standing for day-to-day work, while elevated permission sets (anything touching IAM, billing, or production data) go through the JIT flow. Most engineering teams barely notice the change for routine work and get a much cleaner audit story for the access that actually matters.
Frequently Asked Questions
Does this replace AWS IAM Identity Center's native features?
No — it's built on top of Identity Center's existing APIs (sso-admin), not a replacement. Identity Center doesn't natively support time-bound assignments, so this closes that specific gap without requiring a separate identity platform.
How does this affect our SOC 2 access review evidence?
Instead of screenshotting a permission set list and explaining why each entry is still there, you export the schedule and CloudTrail history showing every grant's requested duration, approval, and automatic revocation timestamp — evidence that survives sampling far better than a manually maintained spreadsheet.
What happens if someone needs an extension mid-task?
The workflow supports a renewal request that re-runs the same approval and scheduling logic, extending the expiration rather than requiring the user to re-request from scratch. Extensions are logged the same way as initial grants.
Can this work with permission sets that use custom IAM policies?
Yes — the pattern operates at the Identity Center assignment level, so it works with AWS-managed and customer-managed permission sets alike, as long as the permission set itself is already defined in Identity Center.
See what an Access & Credential Governance Diagnostic finds in your Identity Center setup → rutagon.com/contact or call 907-841-8407.