DEV Community

Cover image for Stop Using IAM Access Keys: Secure Cross-Cloud Workloads with OIDC Federation
Jayesh Shinde
Jayesh Shinde

Posted on

Stop Using IAM Access Keys: Secure Cross-Cloud Workloads with OIDC Federation

As developers and DevOps engineers, we’ve all been there. You have an external service—maybe an Azure Dynamics 365 (D365) business application or a GitHub Actions CI/CD pipeline—that needs to upload a file to Amazon S3 or trigger an AWS Lambda function.

The easiest path? Create an AWS IAM User, generate a pair of static AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY credentials, dump them into your external service secrets, and call it a day.

Stop doing this. 🛑

According to the AWS Well-Architected Framework, long-lived access keys are one of the highest security risks to a cloud environment. If those keys are leaked, hardcoded by accident, or left unrotated, your entire AWS perimeter is compromised.

The solution? Workload Identity Federation via OpenID Connect (OIDC).

In this post, we’ll look at why you need to ditch IAM users and exactly how to connect external workloads like Azure D365 and GitHub Actions securely using short-lived, temporary tokens.


Why NOT IAM Users?

Let’s look at the numbers. Managing static keys manually vs. assuming dynamic roles:

Concern IAM User (Access Keys) IAM Role (OIDC / Assume Role)
Credential Rotation Manual, tedious, and error-prone Automatic (handled by AWS STS)
Leakage Risk High (long-lived keys last forever) Low (short-lived tokens expire in <1 hr)
Auditability Hard to trace back to specific sessions Clear session-based trails in CloudTrail
Scalability 1 user key per service to track 1 IAM role, multiple trusted identity claim mappings
AWS Status 🛑 Discouraged Preferred

The Core Concept: Workload Identity Federation

Instead of authenticating with a pre-shared password (an Access Key), AWS and your external identity provider establish a cryptographic trust.


[External Workload] ──(Requests OIDC JWT)──> [Identity Provider (Entra ID / GitHub)]
│                                                      │
│ (Presents JWT Token)                                 │
▼                                                      ▼
[AWS STS AssumeRoleWithWebIdentity] <──(Verifies Token)─────────┘
│
▼
[Temporary AWS Credentials Granted] ───> [Access AWS Resources (S3, Lambda, etc.)]

Enter fullscreen mode Exit fullscreen mode

AWS acts as the validation authority, inspecting the incoming JSON Web Token (JWT) from your external provider, matching it against rules you define, and granting temporary AWS IAM credentials valid for only a brief window.


Scenario 1: Azure D365 / Entra ID ➔ AWS

If you have a business workflow running in Microsoft Dynamics 365 or an Azure Function trying to authenticate to AWS, this is the gold-standard implementation.

1. Register Microsoft as an Identity Provider in AWS IAM

  1. Navigate to AWS IAMIdentity ProvidersAdd Provider.
  2. Select OpenID Connect.
  3. Provider URL: https://login.microsoftonline.com/<YOUR_AZURE_TENANT_ID>/v2.0
  4. Audience: Enter the Application (Client) ID of your Azure App Registration.

2. Configure the IAM Role & Trust Policy

When creating the IAM role that D365 will assume, the Trust Policy must enforce strict conditions. Do not just check the audience (aud); you must pin the specific subject (sub) to ensure other tenants or apps inside your Azure ecosystem can't hijack the role.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/[login.microsoftonline.com/](https://login.microsoftonline.com/)<AZURE_TENANT_ID>/v2.0"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "[login.microsoftonline.com/](https://login.microsoftonline.com/)<AZURE_TENANT_ID>/v2.0:aud": "<AZURE_APP_CLIENT_ID>",
          "[login.microsoftonline.com/](https://login.microsoftonline.com/)<AZURE_TENANT_ID>/v2.0:sub": "<AZURE_SERVICE_PRINCIPAL_OBJECT_ID>"
        }
      }
    }
  ]
}

Enter fullscreen mode Exit fullscreen mode

Scenario 2: GitHub Actions ➔ AWS

The exact same principles apply to your CI/CD pipelines. No more storing AWS keys in GitHub Secrets.

1. Register GitHub as an Identity Provider in AWS IAM

  1. Go to AWS IAMIdentity ProvidersAdd Provider.
  2. Provider URL: https://token.actions.githubusercontent.com
  3. Audience: sts.amazonaws.com

2. Configure the GitHub IAM Trust Policy

To keep things secure, your condition should restrict role-assumption to a specific GitHub Organization, Repository, or even a specific git branch.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:repo": "your-github-org/your-repo-name:*"
        }
      }
    }
  ]
}

Enter fullscreen mode Exit fullscreen mode

3. Use it in your GitHub Actions Workflow

In your .github/workflows/deploy.yml, make sure to grant the workflow id-token: write permissions so it can request the JWT token from GitHub's OIDC engine.

name: Deploy to AWS
on: [push]

permissions:
  id-token: write # Mandatory for OIDC federation
  contents: read

jobs:
  AWSLogin:
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::<AWS_ACCOUNT_ID>:role/YourGitHubOidcRole
          aws-region: us-east-1

      - name: Test AWS Connection
        run: aws s3 ls

Enter fullscreen mode Exit fullscreen mode

Pro-Tips for Production Implementations 💡

  • Infrastructure-as-Code (IaC) Thumbprints: If you are automating this setup with Terraform or CloudFormation, AWS requires a server certificate thumbprint for the OIDC provider. For Azure and GitHub, make sure your automated script dynamically fetches or references the correct root CA thumbprints to ensure authentication doesn't suddenly fail when Microsoft or GitHub updates their SSL certificates.
  • The "Multi-Tenant" Trap: In Azure, always make your App Registration Single-Tenant unless you have an explicit multi-organization architecture requirement. This is an excellent defense-in-depth practice.
  • What if I have an on-premises legacy workload? If you have legacy servers with no centralized OIDC identity provider, don't revert to IAM users right away! Look into AWS IAM Roles Anywhere. It allows local legacy infrastructure to use local X.509 certificates to securely request short-lived tokens from AWS STS.

Summary: Choose Your Strategy

Workload Scenario Recommended Authentication Mechanism
Azure D365 / Azure Functions OIDC Federation (Entra ID) + IAM Role
GitHub Actions / GitLab CI OIDC Federation (GitHub/GitLab Provider) + IAM Role
AWS Cross-Account Communication Native IAM Role Cross-Account Trust Policy
Legacy On-Premises Server (No IdP) AWS IAM Roles Anywhere (X.509 Certificates)

Migrating to Workload Identity Federation might take a few extra minutes of initial configuration compared to copying and pasting static keys, but the massive leap in cloud security makes it non-negotiable for modern systems.

Top comments (0)