← Back to list

How to Connect Azure DevOps to AWS Using OIDC Federation (No Static Keys Required)

** A step-by-step guide to securely authenticating Azure Pipelines with AWS using OpenID Connect, without static keys. **

Umar Khan in Towards Dev · 2026-04-09 19:35 · 0 claps · 5.5 min read paywalled
#aws #azure-devops #devsecops #azure #yaml
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

How to Connect Azure DevOps to AWS Using OIDC Federation (No Static Keys Required)

A step-by-step guide to securely authenticating Azure Pipelines with AWS using OpenID Connect, without static keys.

If you’ve ever stored AWS access keys as Azure DevOps pipeline variables, you already know the problem. Rotating them is painful, they can be leaked in logs, and they violate the principle of least privilege. There’s a better way.

OpenID Connect (OIDC) federation lets your Azure DevOps pipelines authenticate with AWS using short-lived, automatically rotated credentials, with zero static keys stored anywhere. This guide walks you through the complete setup, including the exact trust policy JSON you need, common errors, and how to make it work across multiple projects.

How It Works

Before diving into the steps, it helps to understand the flow:

  1. Your Azure DevOps pipeline starts and requests an OIDC token from Azure DevOps.
  2. Azure DevOps issues a signed JWT containing claims about who is running the pipeline (org, project, service connection).
  3. The pipeline presents this token to AWS Security Token Service (STS).
  4. AWS STS validates the token against the registered OIDC identity provider.
  5. If the trust policy conditions match, AWS issues temporary credentials (valid for up to 12 hours).
  6. The pipeline uses those temporary credentials to call AWS APIs.

No secrets stored. No rotation required. No risk of credentials leaking in logs.

Prerequisites

  • An Azure DevOps organization with a project
  • An AWS account with permissions to create IAM roles and identity providers
  • AWS Toolkit for Azure DevOps v1.15.0 or higher installed in your Azure DevOps organization (install from the marketplace)

Step 1: Find Your Azure DevOps Organization GUID

AWS needs a unique identifier for your Azure DevOps organization to configure the OIDC trust. This is not your org name. It is a GUID.

While logged into Azure DevOps in your browser, navigate to:

https://dev.azure.com/{YOUR_ORG_NAME}/_apis/connectionData?api-version=5.0-preview.1

In the JSON response, find the instanceId field:

{
  "instanceId": "457fdbd6-7115-4eda-a575-8c00de7a1a80",
  ...
}

That GUID is your Organization ID. Save it. You will use it throughout the rest of this guide.

Your OIDC issuer URL will be:

https://vstoken.dev.azure.com/{YOUR_ORG_GUID}

Step 2: Register the OIDC Identity Provider in AWS

AWS needs to know to trust tokens issued by Azure DevOps.

  1. Go to AWS Console → IAM → Identity providers
  2. Click Add provider
  3. Choose OpenID Connect
  4. Set the Provider URL to: https://vstoken.dev.azure.com/{YOUR_ORG_GUID}
  5. Click Get thumbprint (AWS fetches the certificate fingerprint automatically)
  6. Set the Audience to: api://AzureADTokenExchange
  7. Click Add provider

Step 3: Create the IAM Role

This is the role your pipeline will assume. The trust policy is the critical part. It controls exactly who can assume the role.

Navigate to IAM Roles

  1. Go to AWS Console → IAM → Roles → Create role
  2. For Trusted entity type, select Web identity
  3. For Identity provider, select the provider you just created (vstoken.dev.azure.com/{YOUR_ORG_GUID})
  4. For Audience, select api://AzureADTokenExchange
  5. Click Next

Attach a Permission Policy

For a Packer AMI build pipeline, attach a policy with the minimum EC2 permissions needed:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeImages",
        "ec2:DescribeInstances",
        "ec2:RunInstances",
        "ec2:StopInstances",
        "ec2:TerminateInstances",
        "ec2:CreateImage",
        "ec2:RegisterImage",
        "ec2:DeregisterImage",
        "ec2:CreateSnapshot",
        "ec2:DeleteSnapshot",
        "ec2:DescribeSnapshots",
        "ec2:CreateTags",
        "ec2:DescribeSubnets",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeKeyPairs",
        "ec2:DescribeRegions",
        "ec2:DescribeVolumes",
        "iam:GetInstanceProfile",
        "iam:PassRole"
      ],
      "Resource": "*"
    }
  ]
}

Tip: Scope the iam:PassRole resource to a specific instance profile ARN rather than `` if your Packer template uses an instance profile.*

Give the role a name (for example, AzureDevOpsRole) and create it.

Step 4: Configure the Trust Policy

After creating the role, update its trust policy to lock it down to your specific Azure DevOps service connection. This prevents other pipelines, even within your org, from assuming the role unless you explicitly allow it.

Option A: Single Project (Most Restrictive)

Use StringEquals and specify the exact service connection subject:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::{YOUR_AWS_ACCOUNT_ID}:oidc-provider/vstoken.dev.azure.com/{YOUR_ORG_GUID}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "vstoken.dev.azure.com/{YOUR_ORG_GUID}:sub": "sc://{OrgName}/{ProjectName}/{ServiceConnectionName}",
          "vstoken.dev.azure.com/{YOUR_ORG_GUID}:aud": "api://AzureADTokenExchange"
        }
      }
    }
  ]
}

The sub format is always:

sc://{OrgName}/{ProjectName}/{ServiceConnectionName}

Option B: Multiple Projects (Shared Service Connection)

If you have multiple Azure DevOps projects sharing the same service connection, use StringLike with a wildcard, or use an array of allowed subjects.

  • Wildcard approach (all projects in org):
"Condition": {
  "StringLike": {
    "vstoken.dev.azure.com/{YOUR_ORG_GUID}:sub": "sc://{OrgName}/*",
    "vstoken.dev.azure.com/{YOUR_ORG_GUID}:aud": "api://AzureADTokenExchange"
  }
}
  • Array approach (specific projects only, recommended):
"Condition": {
  "StringEquals": {
    "vstoken.dev.azure.com/{YOUR_ORG_GUID}:sub": [
      "sc://{OrgName}/ProjectA/{ServiceConnectionName}",
      "sc://{OrgName}/ProjectB/{ServiceConnectionName}"
    ],
    "vstoken.dev.azure.com/{YOUR_ORG_GUID}:aud": "api://AzureADTokenExchange"
  }
}

Note: JSON objects cannot have duplicate keys. If you need multiple subjects, use an array value, not duplicate key entries.

To apply the trust policy: go to your IAM role → Trust relationshipsEdit trust policy → paste and save.

Step 5: Create the Azure DevOps Service Connection

  1. In Azure DevOps, go to Project Settings → Service connections → New service connection
  2. Select AWS
  3. Set the Authentication scheme to Workload Identity Federation
  4. Fill in:
  • Role to Assume ARN: arn:aws:iam::{YOUR_AWS_ACCOUNT_ID}:role/azdo-packer-role
  • Default Region: your AWS region (for example, us-east-1)
  • Service Connection Name: your chosen name (for example, aws-oidc)
  • Leave Access Key ID, Secret Access Key, and Session Token completely empty
  • Click Save

Common mistake: If you enable OIDC but leave any static key fields populated, the toolkit will fall back to key-based authentication and OIDC will be silently ignored. All key fields must be empty.

Step 6: Write the Pipeline

trigger:
- main

pool:
  vmImage: ubuntu-latest
variables:
  aws.rolecredential.maxduration: "3600"  # Session duration in seconds (900-43200)
steps:
# Verify the OIDC connection is working
- task: AWSCLI@1
  displayName: "Verify AWS identity"
  inputs:
    awsCredentials: "aws-oidc"
    regionName: "us-east-1"
    awsCommand: "sts"
    awsSubCommand: "get-caller-identity"

Verifying It Works

When OIDC is working correctly, your pipeline logs will show something like:

Skipping Instance profile, we have OIDC enabled
Getting OIDC Token...
OIDC Token generated: issuer: {<https://vstoken.dev.azure.com/>...} sub: {sc://your-org/your-project/aws-oidc}, aud: {api://AzureADTokenExchange}
Assuming role via OIDC Token...

If you see endpoint defines standard access/secret key credentials instead, the service connection still has static keys populated. Go back and clear them.

Troubleshooting Common Errors

Unable to locate credentials

The service connection is using basic auth instead of OIDC. Check that the service connection has no static keys and is set to Workload Identity Federation.

AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity

The OIDC token is being generated but the trust policy is rejecting it. Check that:

  • The sub value in the condition exactly matches your actual service connection path (sc://org/project/connection-name)
  • The aud value is api://AzureADTokenExchange
  • The OIDC provider ARN in Principal.Federated is correct
  • You do not have duplicate keys in the StringEquals block

To find your exact sub value, check the pipeline log line that starts with OIDC Token generated. It prints the actual issuer, sub, and aud values.

NoCredentialProviders

The role ARN in the service connection may be missing or malformed. Ensure it follows the format arn:aws:iam::{account-id}:role/{role-name}.

Security Best Practices

  • Least privilege IAM policy: only grant the specific actions your pipeline needs.
  • Pin the sub condition: prefer StringEquals with a specific subject over broad wildcards.
  • Enable CloudTrail: every AssumeRoleWithWebIdentity call is logged in AWS CloudTrail.
  • Set session duration appropriately: use aws.rolecredential.maxduration to control credential lifetime.
  • Restrict pipeline edit access: limit who can modify pipeline YAML and the service connection.

Summary

OIDC federation is now the industry standard for connecting CI/CD systems to cloud providers without storing secrets. Once set up, it removes an entire category of credential management burden and significantly improves pipeline security.

  • Have questions or ran into a different error? Leave a comment below.

메타데이터
post_id
bab741c4e134
slug
how-to-connect-azure-devops-to-aws-using-oidc-federation-no-static-keys-required-bab741c4e134
url
https://towardsdev.com/how-to-connect-azure-devops-to-aws-using-oidc-federation-no-static-keys-required-bab741c4e134
canonical_url
https://towardsdev.com/how-to-connect-azure-devops-to-aws-using-oidc-federation-no-static-keys-required-bab741c4e134
author_url
https://medium.com/@ukhan262
status
ok
fetched_at
2026-07-13 06:23:13