Set Up Just-In-Time Access / Zero Standing Privilege for AWS CLI
Every AWS account starts the same way: an IAM user gets created, an access key pair gets generated, and those credentials land in…
Set Up Just-In-Time Access / Zero Standing Privilege for AWS CLI
Photo by Clint Patterson on Unsplash
Every AWS account starts the same way: an IAM user gets created, an access key pair gets generated, and those credentials land in ~/.aws/credentials. They sit there indefinitely. The user accumulates policies over months — AdministratorAccess because “we needed it once for a migration,” PowerUserAccess because “the developer needed to test Lambda.” Nobody revokes them. Nobody reviews them.
This is standing privilege, and it’s the default state of nearly every AWS CLI setup in production today.
Zero standing privilege (ZSP) flips this model. No one holds persistent elevated access. Instead, engineers request time-bound credentials when they need them, use them for the task at hand, and the credentials expire automatically. The AWS CLI session works identically from the engineer’s perspective — but the blast radius of a compromised credential drops from “unlimited, indefinite” to “scoped, minutes.”
This post walks through how to implement JIT access for AWS CLI operations practically.
Why Standing AWS CLI Credentials Are Dangerous
An IAM user’s long-lived access key is a permanent credential. It doesn’t expire unless you manually rotate or delete it. If it leaks (committed to a repo, logged in CI output, exfiltrated from a developer laptop), the attacker has the same access as the engineer — for as long as the key exists.
The numbers are grim. AWS reports that credential exposure is the most common initial access vector in cloud breaches. A key with AdministratorAccess leaked to a public GitHub repo gives an attacker unrestricted control of your account within minutes. Automated scanners constantly trawl repositories for AWS key patterns.
Beyond breach risk, standing privilege violates every modern compliance framework. SOC 2 CC6.3 requires removing access when no longer needed. ISO 27001 A.9 mandates formal provisioning and deprovisioning. Cyber insurance questionnaires now explicitly ask whether you use time-bound access controls.
The Architecture: How JIT Works for AWS CLI
The JIT model for AWS CLI relies on temporary credentials issued through AWS STS (Security Token Service). Instead of a permanent access key, the engineer receives short-lived credentials — an access key, secret key, and session token — that expire after a configured duration (typically 1–4 hours).
The flow:
- Baseline state: The engineer’s IAM identity has minimal standing permissions (read-only, or none at all).
- Request: The engineer requests elevated access — specifying the role, account, and justification.
- Approval: A policy engine or human approver validates the request. Credential issuance: STS issues temporary credentials scoped to the approved role and duration.
- CLI usage: The engineer’s AWS CLI uses the temporary credentials. Commands work normally.
- Expiry: When the TTL hits zero, the credentials stop working. No manual revocation needed.
Implementation Path 1: AWS IAM Identity Center (SSO) + CLI
AWS IAM Identity Center (formerly AWS SSO) is the most straightforward native path to JIT-style CLI access.
# Configure the AWS CLI to use Identity Center
aws configure sso
# Follow prompts: SSO start URL, region, account, role
# Authenticate and get temporary credentials
aws sso login --profile my-elevated-profile
# Use the profile for commands
aws s3 ls --profile my-elevated-profile
When you run aws sso login, the CLI opens a browser for authentication. Upon success, temporary credentials are cached locally and used for subsequent commands. These credentials expire based on the session duration configured in Identity Center (default: 1 hour, max: 12 hours).
The limitation: Identity Center gives you temporary credentials, but it doesn’t enforce approval workflows. Anyone assigned a permission set can activate it at will. It’s time-bound, but not truly JIT — there’s no gate between “I want access” and “I have access.”
Implementation Path 2: AssumeRole with MFA + Reduced Session Duration
For teams not using Identity Center, sts:AssumeRole with MFA provides a manual JIT pattern:
# Assume an elevated role with MFA
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/ElevatedDBARole \
--role-session-name "jit-session-abhiram-ticket-1234" \
--duration-seconds 3600 \
--serial-number arn:aws:iam::123456789012:mfa/abhiram \
--token-code 123456
# Export the temporary credentials
export AWS_ACCESS_KEY_ID="<from response>"
export AWS_SECRET_ACCESS_KEY="<from response>"
export AWS_SESSION_TOKEN="<from response>"
# Now CLI commands use the elevated, time-bound credentials
aws rds describe-db-instances
Key configuration on the role’s trust policy:
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::123456789012:user/abhiram" },
"Action": "sts:AssumeRole",
"Condition": {
"Bool": { "aws:MultiFactorAuthPresent": "true" },
"NumericLessThanEquals": { "aws:MaxSessionDuration": "3600" }
}
}
This enforces that elevation requires MFA and caps session duration. But it’s still self-service — there’s no approval step, no audit trail beyond CloudTrail, and no policy engine deciding whether this particular elevation makes sense right now.
Implementation Path 3: Purpose-Built JIT with Approval Workflows
True zero standing privilege requires a system that interposes between “request” and “grant.” This is where purpose-built JIT platforms operate.
The workflow becomes:
- Engineer runs a request (via CLI, Slack, or a portal): “I need PowerUserAccess on production account for 2 hours to debug a Lambda timeout. Ticket: OPS-4521.”
- The request routes to the on-call approver (or auto-approves based on policy — e.g., “read-only requests under 1 hour from on-call engineers auto-approve”).
- Upon approval, the platform calls sts: AssumeRole on behalf of the engineer and delivers temporary credentials — either injected into the CLI session or available via a credential helper.
- CloudTrail logs every API call during the session, tagged with the session name (which includes the engineer’s identity and ticket number).
- Credentials expire. No cleanup required.
This approach gives you the three things native AWS tooling lacks in combination: time-bounding + approval gates + audit correlation.
Hardening the Setup
Once JIT is operational, lock down the edges:
- Delete long-lived access keys. Run aws iam list-access-keys across all users. Any key older than 90 days without rotation is a liability. If the user has JIT access, they don’t need a standing key.
- Enforce SCP guardrails. Use Service Control Policies to deny iam:CreateAccessKey org-wide (with exceptions for break-glass). This prevents shadow credentials from being generated.
- Tag sessions for attribution. Use meaningful — role-session-name values: jit-<username>-<ticket>-<timestamp>. CloudTrail captures this, making forensic correlation trivial.
- Set maximum session durations aggressively. Start with 1 hour for admin roles. Extend only if teams demonstrate a genuine need for longer sessions.
- Alert on direct console/CLI access without JIT. Any AssumeRole call that doesn’t originate from your JIT system is suspicious. Build a CloudWatch alarm for it.
The Operational Reality
Teams worry that JIT adds friction. In practice, well-implemented JIT with Slack-based approval takes under 2 minutes from request to working credentials. Auto-approval policies for low-risk, time-bound requests (read-only access, non-production accounts) reduce friction further.
The security gain is non-negotiable: if credentials leak, they’re scoped and expired. If an insider goes rogue, the audit trail is identity-stamped and time-correlated. If an auditor asks “who had admin access to production last Tuesday at 3pm,” you answer in seconds, not days.
Standing privilege is a solved problem. The AWS CLI works perfectly with temporary credentials. The only question is whether you enforce that structurally or continue hoping nobody’s ~/.aws/credentials file ends up somewhere it shouldn’t.
Topic credits: *Cloudanix*
메타데이터
- post_id
- ede6e5f2d319
- slug
- set-up-just-in-time-access-zero-standing-privilege-for-aws-cli-ede6e5f2d319
- url
- https://medium.com/@cdxlabs.abhiram/set-up-just-in-time-access-zero-standing-privilege-for-aws-cli-ede6e5f2d319
- canonical_url
- https://medium.com/@cdxlabs.abhiram/set-up-just-in-time-access-zero-standing-privilege-for-aws-cli-ede6e5f2d319
- author_url
- https://medium.com/@cdxlabs.abhiram
- status
- ok
- fetched_at
- 2026-08-02 02:13:39