Replace AWS Access Keys with Short-Lived Credentials
Configure AWS IAM to trust Vouch as an OIDC identity provider
Vouch eliminates static AWS access keys. You configure AWS to trust Vouch as an OIDC identity provider, and developers get temporary STS credentials – valid for up to 1 hour – after authenticating with their YubiKey. Every API call is tied to a verified human identity in CloudTrail.
TL;DR
- Prerequisite: Getting Started (CLI installed, YubiKey enrolled).
- Admin, once: register the OIDC provider and deploy a role; share the role ARN.
- Each developer:
vouch setup aws --role <ROLE_ARN>, then verify withaws sts get-caller-identity --profile vouch. - Rolling this out to a whole team? Follow the Team Rollout playbook.
Step 1 – Register the Vouch OIDC provider
Admin taskVouch uses exactly one OIDC provider per organization. Register it once – in your single AWS account, or in the management account if you use AWS Organizations. An administrator does this before any user can assume a role.
For background on OIDC identity providers in AWS, see Creating OpenID Connect (OIDC) identity providers in the AWS documentation.
aws iam create-open-id-connect-provider \
--url "https://us.vouch.sh" \
--client-id-list "https://us.vouch.sh"
AWSTemplateFormatVersion: "2010-09-09"
Description: Vouch OIDC Identity Provider
Resources:
VouchOIDCProvider:
Type: "AWS::IAM::OIDCProvider"
Properties:
Url: "https://us.vouch.sh"
ClientIdList:
- "https://us.vouch.sh"
resource "aws_iam_openid_connect_provider" "vouch" {
url = "https://us.vouch.sh"
client_id_list = ["https://us.vouch.sh"]
}
Note: AWS fetches the JWKS from
https://us.vouch.sh/oauth/jwksat runtime to verify token signatures. AThumbprintListis no longer required – AWS obtains the root CA thumbprint automatically.
Choose your setup
Admin taskHow your team accesses AWS decides what you deploy next. This is the same question the vouch setup aws wizard asks each developer – “How do you access AWS?” – so admins and developers stay aligned:
| Your AWS layout | What to deploy | Guide |
|---|---|---|
| Single account — one IAM role | One role in this account | Continue to Step 2 below |
| Multiple accounts — a management role that assumes into member roles | A hub role here, plus a spoke role per account | Role chaining |
| Identity Center (SSO) — permission sets | Register Vouch as a trusted token issuer | Identity Center |
If you have an Organization, everything anchors in the management account. Single-account setup continues below.
Step 2 – Deploy a role
Admin taskThis is the role developers federate into with vouch login. Its trust policy is the same no matter what the role can do; only the permissions policy changes – and what the role is allowed to do is your team’s decision. Deploy the shared trust policy below, then attach a permissions policy one of two ways.
The *@example.com condition limits role assumption to anyone with a verified email in your domain (see Tips for restricting access for narrower patterns).
Shared trust policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/us.vouch.sh"
},
"Action": [
"sts:AssumeRoleWithWebIdentity",
"sts:SetSourceIdentity",
"sts:TagSession"
],
"Condition": {
"StringEquals": {
"us.vouch.sh:aud": "https://us.vouch.sh"
},
"StringLike": {
"us.vouch.sh:sub": "*@example.com",
"sts:RoleSessionName": "${us.vouch.sh:sub}"
},
"Bool": {
"sts:RoleAuthorizedByIdp": "true"
}
}
}
]
}
The sub and sts:RoleSessionName conditions bind the session to the authenticated user, and sts:RoleAuthorizedByIdp requires the token to be pinned to this role; see Tips for restricting access for what each does.
Managed policy
Attach an AWS-managed policy. Start with ReadOnlyAccess and broaden to exactly what your team needs – don’t reach for PowerUserAccess by default. See AWS’s job-function managed policies for options.
Resources:
VouchDeveloperRole:
Type: AWS::IAM::Role
Properties:
RoleName: VouchDeveloper
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:oidc-provider/us.vouch.sh"
Action:
- "sts:AssumeRoleWithWebIdentity"
- "sts:SetSourceIdentity"
- "sts:TagSession"
Condition:
StringEquals:
"us.vouch.sh:aud": "https://us.vouch.sh"
StringLike:
"us.vouch.sh:sub": "*@example.com"
"sts:RoleSessionName": "${us.vouch.sh:sub}"
Bool:
"sts:RoleAuthorizedByIdp": "true"
ManagedPolicyArns:
# Start safe. Attach the permissions your team needs.
- !Sub "arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess"
data "aws_caller_identity" "current" {}
data "aws_partition" "current" {}
locals {
aws_partition = data.aws_partition.current.partition
aws_account_id = data.aws_caller_identity.current.account_id
}
resource "aws_iam_role" "vouch_developer" {
name = "VouchDeveloper"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = "arn:${local.aws_partition}:iam::${local.aws_account_id}:oidc-provider/us.vouch.sh"
}
Action = [
"sts:AssumeRoleWithWebIdentity",
"sts:SetSourceIdentity",
"sts:TagSession",
]
Condition = {
StringEquals = {
"us.vouch.sh:aud" = "https://us.vouch.sh"
}
StringLike = {
"us.vouch.sh:sub" = "*@example.com"
"sts:RoleSessionName" = "${us.vouch.sh:sub}"
}
Bool = {
"sts:RoleAuthorizedByIdp" = "true"
}
}
}
]
})
# Start safe. Attach the permissions your team needs.
managed_policy_arns = ["arn:${local.aws_partition}:iam::aws:policy/ReadOnlyAccess"]
}
Explicit actions
Attach a custom inline policy listing only the actions your team needs. Use the same trust policy and role definition as the managed-policy example; replace the ManagedPolicyArns block with an inline policy. Example – read/write a specific S3 bucket and read CloudWatch logs:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-data",
"arn:aws:s3:::my-app-data/*"
]
},
{
"Effect": "Allow",
"Action": [
"logs:GetLogEvents",
"logs:FilterLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
],
"Resource": "*"
}
]
}
In CloudFormation, use Policies on the role; in Terraform, use aws_iam_role_policy.
You are done with role deployment when...
- The role uses the shared trust policy with your email domain in the
subcondition. - You attached a permissions policy your team is comfortable with (start with
ReadOnlyAccess). - You have the role ARN written down -- developers need it in Step 3.
Step 3 – Configure the Vouch CLI
Developer taskEach developer runs the wizard – it asks the same “How do you access AWS?” question and writes the AWS profile for you:
vouch setup aws
For single-account access you can skip the prompts by passing the role directly:
vouch setup aws --role arn:aws:iam::123456789012:role/VouchDeveloper
This command accepts the following flags:
--role– The ARN of the IAM role from Step 2. Omit all flags to launch the interactive wizard.--profile– The AWS profile name to write credentials to (default:vouch; additional profiles auto-name asvouch-2,vouch-3, etc.).
For multi-account setups, vouch setup aws also accepts --management-role, --identity-center-application, --region, and --discover – see Multi-Account AWS.
The command writes a credential_process entry into ~/.aws/config so that the AWS CLI and SDKs automatically call vouch credential aws whenever credentials are needed:
[profile vouch]
credential_process = vouch credential aws --role arn:aws:iam::123456789012:role/VouchDeveloper
Note: If you need a specific region for this profile, add a
regionline manually (e.g.,region = us-east-1).
Step 4 – Test
Developer taskVerify that everything is working:
# Make sure you are logged in
vouch login
# Check your identity
aws sts get-caller-identity --profile vouch
Expected output:
{
"UserId": "AROA...:alice@example.com",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/VouchDeveloper/alice@example.com"
}
Try running a command against a real AWS service:
aws s3 ls --profile vouch
You are done when...
aws sts get-caller-identity --profile vouchreturns an assumed-role ARN for the expected AWS account.- The role session name matches the authenticated Vouch user.
- A real AWS command succeeds without static credentials in
~/.aws/credentials.
Console access
Open the AWS Management Console directly from the CLI without entering credentials in a browser:
vouch aws console
This uses your active Vouch session to obtain temporary STS credentials, exchanges them for a federation sign-in token, and opens the console in your default browser. Pass --role to specify a role, or omit it to use the role from your configured AWS profile. For IAM Identity Center access, pass --account <id> --permission-set <name> (add --idc-application <arn> when more than one instance is configured); use --via <management-role-arn> to select a management role when multiple organizations are configured.
Tips for restricting access
Restrict by email address
Limit role assumption to specific users by adding an email condition to the trust policy:
"Condition": {
"StringEquals": {
"us.vouch.sh:aud": "https://us.vouch.sh",
"us.vouch.sh:sub": ["user@example.com"]
},
"StringLike": {
"sts:RoleSessionName": "${us.vouch.sh:sub}"
},
"Bool": {
"sts:RoleAuthorizedByIdp": "true"
}
}
Restrict by email domain
Allow any user from a specific domain:
"Condition": {
"StringEquals": {
"us.vouch.sh:aud": "https://us.vouch.sh"
},
"StringLike": {
"us.vouch.sh:sub": "*@example.com",
"sts:RoleSessionName": "${us.vouch.sh:sub}"
},
"Bool": {
"sts:RoleAuthorizedByIdp": "true"
}
}
Revoke access for a specific user
There are two complementary techniques for cutting off a user. Use both together for full offboarding.
1. Immediate revocation via an explicit Deny on the role’s permissions policy. Permissions policies are evaluated on every AWS API call, and explicit Deny always wins. Because Vouch sets the vouch:Email session tag on every assumed-role session (see Session tags), you can block an offboarded user on the next API call – including calls made with STS credentials that the Vouch agent has already cached:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyOffboardedUsers",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalTag/vouch:Email": [
"former-employee@example.com"
]
}
}
}
]
}
Attach this as an inline policy on each Vouch role, or apply it as a Service Control Policy in the management account to enforce it organization-wide. Because Vouch marks session tags as transitive, the vouch:Email tag propagates through role chains, so the same condition works in both the entry role and any spoke roles.
2. Block new role assumption via the trust policy. Add a StringNotEquals clause to the trust policy listing the emails to deny. The next AssumeRoleWithWebIdentity call from that user will fail:
"Condition": {
"StringEquals": {
"us.vouch.sh:aud": "https://us.vouch.sh"
},
"StringLike": {
"us.vouch.sh:sub": "*@example.com",
"sts:RoleSessionName": "${us.vouch.sh:sub}"
},
"StringNotEquals": {
"us.vouch.sh:sub": ["former-employee@example.com"]
},
"Bool": {
"sts:RoleAuthorizedByIdp": "true"
}
}
On its own, this only takes effect when the Vouch agent’s cached STS credentials expire (up to 1 hour later), because the trust policy is evaluated at AssumeRoleWithWebIdentity time, not on every API call. Combined with the deny statement above, it provides a durable record of who is offboarded and prevents the role from being re-assumed even after the deny statement is later removed.
For full offboarding, also deactivate the user in Vouch so they cannot start new sessions and existing non-AWS credentials (like SSH certificates) are cut off:
- With SCIM provisioning, deactivating the user in your identity provider automatically revokes their active Vouch session and blocks future logins – no manual step required.
- Without SCIM, an administrator can use the Deactivate and Revoke credentials actions in the admin console to do the same thing.
Note that revoking the Vouch session does not invalidate STS credentials already cached in the user’s local Vouch agent – the explicit Deny from step 1 is what blocks those on the AWS side. The Vouch-side action prevents new sessions and severs other credentials issued from the same session.
Prevent session name spoofing
The RoleSessionName is a client-provided STS API parameter. Without a trust policy condition, someone with a valid Vouch JWT could set it to another user’s email, making CloudTrail session ARNs misleading. The sts:RoleSessionName condition binds the session name to the authenticated sub claim from the validated JWT:
"StringLike": {
"sts:RoleSessionName": "${us.vouch.sh:sub}"
}
All trust policy examples in this guide include this condition. AWS rejects any AssumeRoleWithWebIdentity call where the session name does not match the OIDC subject.
Note: The immutable
SourceIdentityclaim (set to the user’s email) provides a second attribution anchor in CloudTrail that cannot be spoofed regardless of this condition.
Require role pinning
The Vouch CLI requests each OIDC token pinned to the role it is about to assume, and the Vouch server embeds that role ARN in the token’s https://aws.amazon.com/roles claim. AWS STS enforces the claim: a pinned token can only be exchanged for the exact role it was minted for, so a leaked token cannot assume any other role that trusts the Vouch issuer. This happens automatically – no configuration is required.
The trust policy makes pinning mandatory with the sts:RoleAuthorizedByIdp condition key:
"Condition": {
"Bool": {
"sts:RoleAuthorizedByIdp": "true"
}
}
With this in place, AWS rejects any AssumeRoleWithWebIdentity call whose token does not name this role in its roles claim. All trust policy examples in this guide include this condition. Two caveats:
- Roll the CLI out first. Older CLI versions do not request pinning, so their tokens carry no
rolesclaim and fail the condition. If part of your team is on an older CLI, leave the condition out until everyone has upgraded. - Web-identity trust statements only. The condition key is defined for
AssumeRoleWithWebIdentity. A role assumed by a plain SigV4sts:AssumeRolecall – such as a spoke role in a management-role chain – has no OIDC token in the request, so aBool-truecondition there can never match.
Matching is by exact role ARN; wildcards are not supported.
Session tags
Vouch sets the following session tags when assuming a role, which you can use in IAM policies for attribute-based access control (ABAC):
| Tag Key | Value | Example |
|---|---|---|
vouch:Email | The user’s verified email | alice@example.com |
vouch:Domain | The user’s organization domain (from the OIDC hd claim) | example.com |
vouch:AccessType | Set to ai when an AI coding agent is detected | ai |
vouch:Agent | The detected agent name (only present when an agent is detected) | claude-code |
You can reference these tags in IAM policy conditions using aws:PrincipalTag:
{
"Condition": {
"StringEquals": {
"aws:PrincipalTag/vouch:Domain": "example.com"
}
}
}
Because Vouch marks all tags as transitive, they automatically propagate through role chains. If a developer assumes a hub role via Vouch and then chains into a spoke role in another account, the spoke role’s trust policy can still evaluate aws:PrincipalTag/vouch:Email and aws:PrincipalTag/vouch:Domain conditions.
AI agent safety
When vouch credential aws runs inside an AI coding agent, Vouch automatically restricts the returned credentials to read-only access. No configuration is required – the CLI detects the agent environment and applies the restriction transparently.
Note: This read-only downscoping applies to the STS credential paths (
--role, including role chaining). On the IAM Identity Center path (--account/--permission-set), Vouch refuses to issue credentials to a detected agent rather than downscoping them – permission-set credentials cannot be constrained with a session policy, so there is no way to enforce read-only access. Agent workflows that need AWS access should use the STS role-chaining model.
How it works
The CLI checks for environment variables set by popular AI coding agents. When one is detected:
- The
ReadOnlyAccessAWS managed policy is attached as a session policy, which limits the effective permissions to the intersection of the role’s policies andReadOnlyAccess– regardless of what the role itself allows. - The
vouch:AccessType=aiandvouch:Agent=<name>session tags are added, where<name>is the verbatim value of the detected agent environment variable (for agents that setAI_AGENTorAGENT, the raw value is forwarded; for agents detected by a marker variable likeCLAUDE_CODEorCURSOR_TRACE_ID, the agent name is used). These tags appear on every CloudTrail event for the session, so you can attribute API calls to the specific agent that made them.
Supported agents
Vouch detects the following AI coding agents:
| Agent | Environment Variable |
|---|---|
| Claude Code | AI_AGENT or CLAUDE_CODE |
| Cursor | CURSOR_TRACE_ID |
| GitHub Copilot | COPILOT_MODEL |
| OpenAI Codex | CODEX_SANDBOX |
| Google Gemini | GEMINI_CLI |
| Augment | AUGMENT_AGENT |
| Cline | CLINE_ACTIVE |
| Amp | AGENT=amp |
| Goose | AGENT=goose |
If your agent is not listed, it will be detected if it sets the AGENT or AI_AGENT environment variable (an emerging convention).
Role chaining with agents
When using role chaining with an AI agent, Vouch applies an additional inline session policy to the management-account hop that restricts it to STS actions only (sts:AssumeRole, sts:TagSession, sts:SetSourceIdentity). The final role hop receives the ReadOnlyAccess session policy.
How it works
vouch login authenticates the developer with their YubiKey, and the Vouch server issues a short-lived OIDC ID token carrying their email in the sub claim and the target role ARN in the https://aws.amazon.com/roles claim. When the developer runs an AWS command, the CLI calls AWS STS AssumeRoleWithWebIdentity with that token; AWS validates it against the Vouch server and returns temporary credentials valid for up to 1 hour. Because the token is scoped to the authenticated user, pinned to the requested role, and short-lived, credentials cannot be shared, redirected to another role, or reused after expiry.
How Vouch compares to aws login and aws sso login
AWS’s built-in aws login and aws sso login cover AWS only. vouch login covers AWS and SSH, GitHub, Docker, Cargo, CodeCommit, CodeArtifact, and databases – from one phishing-resistant hardware-key session where every credential traces back to a physical key.
aws login | aws sso login | vouch login | |
|---|---|---|---|
| Authentication | Browser + console credentials | Browser + Identity Center | YubiKey tap (FIDO2) |
| Phishing-resistant | Depends on IdP | Depends on IdP | Yes (hardware-bound) |
| AWS credentials | Yes (up to 12h) | Yes | Yes (up to 1h) |
| SSH, GitHub, Docker, etc. | No | No | Yes |
| Identity in CloudTrail | IAM user or role | SSO user | Hardware-verified user |
| Requires AWS-managed service | No | IAM Identity Center | No |
If you already use IAM Identity Center, aws sso login may cover your AWS needs. Vouch fits when you want one authentication event to cover AWS and everything else your team uses.
Troubleshooting
“Not authorized to perform sts:AssumeRoleWithWebIdentity”
- Verify the OIDC provider URL in the IAM trust policy matches
https://us.vouch.shexactly (no trailing slash). - Confirm the
audcondition matches the client ID registered with the OIDC provider. - Ensure the trust policy
Actionincludes all three required actions:sts:AssumeRoleWithWebIdentity,sts:SetSourceIdentity, andsts:TagSession. - If the trust policy requires
sts:RoleAuthorizedByIdp, make sure the CLI is up to date – older CLI versions issue tokens without therolesclaim and fail the condition.
“Token is expired”
- Run
vouch loginagain to refresh your session. OIDC tokens are short-lived by design.
“Invalid identity token”
- Ensure the OIDC provider in AWS points to the correct Vouch server URL:
https://us.vouch.sh. - Verify that the Vouch server’s JWKS endpoint (
https://us.vouch.sh/oauth/jwks) is reachable from the internet (AWS must be able to fetch it).
Credentials not appearing in the expected profile
- Run
vouch setup awsagain and verify the profile name. - Check
~/.aws/configfor conflicting profile definitions.
Permission errors after assuming the role
- The trust policy controls who can assume the role; the permissions policy controls what they can do. Verify the correct permissions policies are attached to the IAM role.
Related guides
- Multi-Account AWS Strategy – Deploy Vouch across multiple AWS accounts with CloudFormation StackSets or Terraform modules.
- Amazon EKS – Use your Vouch-backed AWS credentials to authenticate to Kubernetes clusters.
- AWS Systems Manager – Connect to EC2 instances through Session Manager using Vouch credentials.
- Database Authentication – Connect to RDS, Aurora, and Redshift with IAM authentication.
- AWS CodeArtifact – Authenticate to package repositories using Vouch.
- Infrastructure as Code – Use CDK, Terraform, SAM, and other IaC tools with Vouch credentials.
- Claude & OpenAI APIs – Replace long-lived AI provider API keys with short-lived tokens via Workload Identity Federation.