AWS IAM Setup with OIDC Federation
This guide walks through configuring an IAM role that USDN can assume in your AWS account using OIDC Workload Identity Federation — no AWS access keys, no shared ExternalId, and no long-lived secrets stored on the USDN platform. Once configured, you can use the Cloud Accounts page in the USDN portal to validate credentials, discover VPC resources, browse Marketplace AMIs, and launch AdWanOS devices with one click.
sts:AssumeRoleUSDN previously used cross-account sts:AssumeRole with a shared ExternalId. The platform now federates against AWS IAM as an OIDC Identity Provider, which is the AWS-recommended pattern for third-party integrations. If you still have a legacy role with an ExternalId-gated trust policy, follow this guide to recreate the role with a federated trust policy and the platform will pick it up automatically.
How It Works
USDN mints a short-lived JSON Web Token (JWT) signed by the USDN OIDC issuer and exchanges it for AWS temporary credentials via sts:AssumeRoleWithWebIdentity. AWS verifies the JWT against the OIDC Identity Provider you registered in your account, then issues credentials scoped to the IAM role you trusted.
The key invariant: USDN never stores an AWS access key or shared secret. The trust anchor is the public JWKS endpoint that AWS IAM pulls from our OIDC issuer.
Prerequisites
- An AWS account with permissions to create IAM Identity Providers, policies, and roles
- The USDN OIDC issuer URL:
<USDN_OIDC_ISSUER>(provided during onboarding, e.g.https://api.usdn.example.com) - Your USDN organization ID (visible in the portal Cloud Accounts wizard, used in the trust policy
subcondition) - Access to the USDN portal with an active organization
The USDN portal's Link Cloud Account wizard generates a trust policy JSON tailored to your AWS account ID and organization ID — you can copy it directly into AWS instead of editing the templates below by hand. The CLI snippets in this guide are useful for IaC pipelines and unattended setups.
Step 1: Register USDN as an OIDC Identity Provider
This step tells AWS IAM to trust JWTs minted by the USDN platform.
Using the AWS Console
- Open the IAM Console and navigate to Identity providers > Add provider.
- Choose OpenID Connect as the provider type.
- Enter the following values:
| Field | Value |
|---|---|
| Provider URL | <USDN_OIDC_ISSUER> (no trailing slash) |
| Audience | cloud-federation |
- Click Get thumbprint — AWS will fetch the issuer's TLS certificate and compute a thumbprint. Verify the thumbprint matches what the USDN portal shows in the Link Cloud Account wizard.
- Click Add provider. Record the resulting provider ARN — it has the form
arn:aws:iam::<your-account-id>:oidc-provider/<host>where<host>is the issuer hostname (nohttps://).
Using the AWS CLI
USDN_ISSUER="https://api.usdn.example.com" # Provided during onboarding
USDN_HOST="${USDN_ISSUER#https://}"
# AWS computes the thumbprint server-side when you create the provider via
# the console, but the CLI requires you to supply it. Fetch it from the
# issuer's TLS certificate:
THUMBPRINT=$(echo | openssl s_client -servername "${USDN_HOST}" \
-showcerts -connect "${USDN_HOST}:443" 2>/dev/null \
| openssl x509 -fingerprint -sha1 -noout \
| sed 's/://g' | cut -d= -f2 | tr 'A-Z' 'a-z')
aws iam create-open-id-connect-provider \
--url "${USDN_ISSUER}" \
--client-id-list "cloud-federation" \
--thumbprint-list "${THUMBPRINT}"
The command prints the OIDC provider ARN. Save it — you will reference it in the trust policy in Step 3.
AWS caches the thumbprint locally and does not re-fetch it. If USDN rotates the TLS certificate on the OIDC issuer, you will need to update the thumbprint with aws iam update-open-id-connect-provider-thumbprint. We will give you advance notice before any planned rotation.
Step 2: Create the IAM Policy
Create a policy that grants the minimum permissions USDN needs to deploy and manage instances.
Using the AWS Console
- In the IAM Console, navigate to Policies > Create policy.
- Select the JSON tab and paste the policy below.
- Name the policy
USDNCloudDeployPolicy.
Using the AWS CLI
cat > usdn-deploy-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "USDNInstanceLifecycle",
"Effect": "Allow",
"Action": [
"ec2:RunInstances",
"ec2:TerminateInstances",
"ec2:DescribeInstances",
"ec2:DescribeInstanceStatus"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": [
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
"eu-west-1",
"eu-central-1",
"ap-northeast-1",
"ap-southeast-1",
"ap-southeast-2"
]
}
}
},
{
"Sid": "USDNResourceDiscovery",
"Effect": "Allow",
"Action": [
"ec2:DescribeVpcs",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeImages",
"ec2:DescribeAvailabilityZones",
"ec2:DescribeKeyPairs"
],
"Resource": "*"
},
{
"Sid": "USDNTagging",
"Effect": "Allow",
"Action": [
"ec2:CreateTags"
],
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringEquals": {
"ec2:CreateAction": "RunInstances"
}
}
},
{
"Sid": "USDNValidation",
"Effect": "Allow",
"Action": [
"sts:GetCallerIdentity"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name USDNCloudDeployPolicy \
--policy-document file://usdn-deploy-policy.json
The policy above uses "Resource": "*" for EC2 actions. For tighter control you can scope resources to specific VPCs or subnets using resource ARNs and condition keys like ec2:Vpc and ec2:Subnet. See the AWS EC2 condition keys reference for details.
Permission Summary
| Permission | Purpose |
|---|---|
ec2:RunInstances | Launch AdWanOS instances |
ec2:TerminateInstances | Tear down instances from the portal |
ec2:DescribeInstances | Poll instance status after launch |
ec2:DescribeInstanceStatus | Check instance health during provisioning |
ec2:DescribeVpcs | Discover VPCs for the deploy wizard |
ec2:DescribeSubnets | Discover subnets for placement selection |
ec2:DescribeSecurityGroups | List security groups for instance assignment |
ec2:DescribeImages | List Marketplace + private AMIs in the deploy wizard |
ec2:DescribeAvailabilityZones | Resolve regions to availability zones |
ec2:DescribeKeyPairs | Optional — list available key pairs |
ec2:CreateTags | Tag instances with USDN metadata |
sts:GetCallerIdentity | Credential validation from the portal |
Step 3: Create the IAM Role with a Federated Trust Policy
Create a role that trusts JWTs from the OIDC Identity Provider you registered in Step 1, and attach the policy from Step 2.
Using the AWS Console
- In the IAM Console, go to Roles > Create role.
- Select Web identity as the trusted entity type.
- For Identity provider, choose the USDN OIDC provider you created in Step 1.
- For Audience, select
cloud-federation. - Click Add condition and configure:
- Condition key:
<issuer-host>:sub(the console fills in the host automatically) - Operator:
StringEquals - Value:
usdn-deploy-<your-organization-id>(the portal wizard shows your org ID)
- Condition key:
- Click Next, search for and attach the
USDNCloudDeployPolicypolicy. - Name the role
USDNCloudDeployRoleand create it. - Copy the Role ARN from the role summary page (e.g.
arn:aws:iam::222222222222:role/USDNCloudDeployRole).
Using the AWS CLI
# Replace these values
YOUR_ACCOUNT_ID="222222222222" # Your AWS account ID
USDN_HOST="api.usdn.example.com" # The host portion of the USDN issuer
USDN_ORG_ID="42" # Your USDN organization ID
# Create the federated trust policy
cat > usdn-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${YOUR_ACCOUNT_ID}:oidc-provider/${USDN_HOST}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${USDN_HOST}:aud": "cloud-federation",
"${USDN_HOST}:sub": "usdn-deploy-${USDN_ORG_ID}"
}
}
}
]
}
EOF
# Create the role
aws iam create-role \
--role-name USDNCloudDeployRole \
--assume-role-policy-document file://usdn-trust-policy.json \
--description "OIDC-federated role for USDN cloud deployments"
# Attach the deploy policy
POLICY_ARN="arn:aws:iam::${YOUR_ACCOUNT_ID}:policy/USDNCloudDeployPolicy"
aws iam attach-role-policy \
--role-name USDNCloudDeployRole \
--policy-arn "${POLICY_ARN}"
Trust Policy Explained
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<YOUR_ACCOUNT_ID>:oidc-provider/<USDN_HOST>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"<USDN_HOST>:aud": "cloud-federation",
"<USDN_HOST>:sub": "usdn-deploy-<YOUR_ORG_ID>"
}
}
}
]
}
| Field | Description |
|---|---|
Principal.Federated | The OIDC provider ARN from Step 1. AWS uses this to know which OIDC issuer to verify the JWT against. |
Action | sts:AssumeRoleWithWebIdentity is the only API call USDN makes against this role. |
<host>:aud condition | Pins the JWT audience claim. USDN always mints JWTs with aud=cloud-federation. |
<host>:sub condition | Pins the JWT subject claim to your specific organization (usdn-deploy-<org_id>). This is what scopes the role to your org and prevents another USDN customer from assuming your role. |
sub Condition Is CriticalWithout the sub condition, any USDN organization could assume your role. Always include the sub claim with your organization ID, exactly as shown in the portal wizard. The trust policy USDN auto-generates always includes it.
Step 4: Link the Account in USDN
- Log in to the USDN portal and navigate to Cloud Accounts (under Infrastructure).
- Click Link Cloud Account.
- Select Amazon Web Services as the provider.
- Fill in the required fields:
| Field | Value | Example |
|---|---|---|
| Account Name | A friendly label | Production AWS |
| AWS Account ID | Your 12-digit account ID | 222222222222 |
| IAM Role ARN | The role ARN from Step 3 | arn:aws:iam::222222222222:role/USDNCloudDeployRole |
| Default Region | Preferred deployment region | us-east-1 |
The portal does not prompt for an external ID. The OIDC trust policy you configured in Step 3 is the only thing that grants USDN access — no shared secrets are ever stored on the platform side.
-
Click Save. USDN will validate the credentials by calling
sts:AssumeRoleWithWebIdentityfollowed bysts:GetCallerIdentityto confirm the assumed identity matches the expected account. -
If validation succeeds, the account status will change to Connected. You can now use the Deploy button to launch devices into this account.
Step 5: Deploy a Device
Once your cloud account shows Connected status:
- Click Deploy next to the linked account, or use the Deployments tab.
- The deploy wizard walks through three steps:
- Site & Region — Select the USDN site and AWS region
- Instance Configuration — Choose AMI (from Marketplace or your private images), instance type, VPC, subnet, and security group (auto-discovered from your account)
- Launch & Monitor — Watch real-time deployment progress
Troubleshooting
Validation Fails with "Couldn't retrieve verification key from your identity provider"
AWS IAM could not fetch or verify the JWKS from the USDN OIDC issuer.
- Confirm the OIDC provider was created in Step 1 with the exact issuer URL the portal shows (case-sensitive, no trailing slash).
- Confirm the audience on the OIDC provider includes
cloud-federation. - Try
curl -fsSL <USDN_OIDC_ISSUER>/.well-known/openid-configurationfrom any host — it should return JSON with a validjwks_uri. - If we recently rotated the issuer's TLS certificate, refresh the provider thumbprint with
aws iam update-open-id-connect-provider-thumbprint.
Validation Fails with "Not authorized to perform sts:AssumeRoleWithWebIdentity"
The JWT verified successfully, but the trust policy on the IAM role rejected it.
- Confirm the trust policy
Principal.Federatedmatches the OIDC provider ARN from Step 1 exactly. - Confirm the
<host>:audcondition value iscloud-federation. - Confirm the
<host>:subcondition value isusdn-deploy-<org_id>and that<org_id>matches the organization ID shown in the portal wizard. Mismatched org IDs are the most common cause of this error.
Validation Fails with "Role Not Found"
- Double-check the Role ARN for typos. The format should be
arn:aws:iam::<account-id>:role/<role-name>. - Ensure the role was created in the same partition (e.g.
awsvsaws-cn).
Deploy Fails with "Instance Limit Exceeded"
- Check your EC2 service quotas for the target region.
- Request a limit increase if needed.
Deploy Fails with "VPC/Subnet Not Found"
- Ensure the selected VPC and subnet exist in the target region.
- Verify the IAM role has
ec2:DescribeVpcsandec2:DescribeSubnetspermissions.
AMI List Is Empty in the Deploy Wizard
- Confirm the IAM role has
ec2:DescribeImages. - Marketplace AMIs require a one-time subscription on the AWS account that owns the role — visit the AdWanOS listing in AWS Marketplace and click Continue to Subscribe before retrying.
Device Fails to Register (Timeout)
- Verify the instance has outbound internet access (check route tables, NACLs, and security group egress rules).
- The security group must allow outbound HTTPS (port 443) to the USDN controller.
- Check the instance system log in the EC2 console for bootstrap errors:
aws ec2 get-console-output --instance-id i-0123456789abcdef0
Security Best Practices
- No long-lived secrets — OIDC federation is inherently more secure than static access keys or
ExternalId-gated roles. Never re-introduce an IAM user with access keys for this integration. - Pin the
subcondition — Always include<host>:subin the trust policy. Without it, any USDN organization could assume the role. - Scope to regions — The policy in Step 2 restricts EC2 actions to a documented region list. Trim that list to only the regions you actually use.
- Enable CloudTrail — Monitor all
sts:AssumeRoleWithWebIdentitycalls and the API actions that follow. The session name (usdn-deploy-<account-id>) makes USDN sessions easy to filter on. - Review periodically — Audit the role's permissions and trust policy quarterly.
- Use SCPs for guardrails — If using AWS Organizations, apply Service Control Policies to limit what the role can do.
- Watch the OIDC provider list — Only USDN-issued JWTs should match the OIDC provider you registered. Remove the provider entirely if you stop using USDN.
Revoking Access
To immediately revoke USDN's access to your AWS account, you have several options ordered from least to most disruptive:
# Option 1: Remove just the role's trust policy (USDN can no longer assume,
# the role and policy stay for forensic review)
aws iam update-assume-role-policy \
--role-name USDNCloudDeployRole \
--policy-document '{"Version":"2012-10-17","Statement":[]}'
# Option 2: Detach and delete the role + policy
aws iam detach-role-policy \
--role-name USDNCloudDeployRole \
--policy-arn "arn:aws:iam::<YOUR_ACCOUNT_ID>:policy/USDNCloudDeployPolicy"
aws iam delete-role --role-name USDNCloudDeployRole
# Option 3: Delete the OIDC Identity Provider (severs trust for *any* role
# that referenced this provider — use only if removing USDN entirely)
aws iam delete-open-id-connect-provider \
--open-id-connect-provider-arn "arn:aws:iam::<YOUR_ACCOUNT_ID>:oidc-provider/<USDN_HOST>"
After revoking, the linked account in the USDN portal will show an Error status on the next validation attempt. Existing running instances are not affected — they continue to run independently in your account.