An agent running on or against AWS should never hold a long-lived credential. Not an IAM user, not an access key in a secrets manager, not a shared "agents" service account. Every serious authentication path AWS offers, instance profiles, IRSA, EKS Pod Identity, OIDC federation, IAM Roles Anywhere, AgentCore Identity, exists to do the same thing: exchange a verifiable proof of identity for temporary credentials that expire on their own. If your agent platform starts from that rule, most of the hard questions answer themselves.

Yesterday I wrote about the protocol layer of this problem on the sister site: SEP-1046 giving MCP agents a real client credentials story, with signed JWT assertions replacing shared secrets. This post is the layer underneath: when the agent's target is AWS itself, or the agent runs on AWS and needs to reach everything else, what does its identity actually look like? The answer, in almost every case, is the same shape SEP-1046 chose: a short-lived signed token in, short-lived credentials out. AWS has been running this pattern at scale for years. You just have to stop fighting it with static keys.

One pattern under everything: OIDC federation

Strip the product names away and AWS agent auth is one mechanism. An identity provider signs a JWT about a workload. You register that provider's issuer URL in IAM as an OIDC identity provider; IAM fetches the public keys from the provider's jwks_uri via the /.well-known/openid-configuration discovery document. The workload presents its token to sts:AssumeRoleWithWebIdentity and gets role credentials that expire within the hour. The role's trust policy pins who gets in with conditions on the token's aud and sub claims.

The version of this every platform team already knows is GitHub Actions: the runner gets an OIDC token whose sub claim encodes repo and branch, the role trust policy matches repo:my-org/my-repo:ref:refs/heads/main, and no access key ever lives in repository secrets. That is not a CI trick. It is the template for every unattended workload, agents included. A signed, audience-bound, minutes-lived assertion replacing a stored secret is exactly what private_key_jwt does at the MCP layer; the industry converged on one answer from two directions, which is usually the sign the answer is right.

Where the agent runs decides the mechanism

You rarely build the federation yourself. You pick the packaging that matches the runtime:

  • On EC2 or ECS: instance profile or task role. The SDK credential chain picks it up, nothing to configure in the agent. If your agent framework asks for an access key here, that is a framework smell, not an AWS requirement.
  • On EKS: two options. IRSA (IAM Roles for Service Accounts) is the older one: the cluster exposes an OIDC issuer, you register it in IAM and annotate a ServiceAccount with a role ARN. EKS Pod Identity is the newer one: no per-cluster OIDC provider registration, an agent add-on on the node exchanges credentials, and the role trust policy targets pods.eks.amazonaws.com once instead of per-cluster issuer URLs. For a fleet of clusters, Pod Identity removes real toil; for a single cluster either is fine. Both end at the same place: one IAM role per agent workload, no keys in the pod.
  • Outside AWS, with an IdP: plain OIDC federation as above. Your datacenter workload, your other cloud, your SaaS runner authenticates to its own identity provider and federates in. This is the GitHub Actions pattern generalized.
  • Outside AWS, without an IdP: IAM Roles Anywhere. Your workload presents an X.509 certificate from a CA you registered as a trust anchor (AWS Private CA or your own PKI) and exchanges it for temporary role credentials via a profile. The honest caveat: you inherit certificate lifecycle management, issuance, rotation, revocation. If you do not already run PKI, standing up an identity provider is usually less operational weight than adopting one.

AgentCore Identity: the agent-shaped layer on top

IAM answers "how does this workload call AWS". Agents have two more problems: who is allowed to call the agent, and how the agent reaches non-AWS services, Slack, GitHub, Google, on a user's behalf. That is the slice Amazon Bedrock AgentCore Identity covers, and it is worth understanding even if you never run AgentCore, because it is AWS writing down what agent identity needs beyond a role.

  • Workload identities for agents. Each agent gets its own directory entry, not a shared principal. The same one-identity-per-workload rule as IAM roles, applied one level up.
  • Inbound auth. Callers reach the agent either with plain SigV4 (IAM as usual) or through a JWT authorizer: you configure a discovery URL and allowed audiences, and Cognito, Okta, or Entra ID tokens gate the agent. AgentCore Gateway exposes the same CUSTOM_JWT authorizer for tool endpoints, which is how an MCP-ish gateway on AWS validates the tokens the previous post was about minting.
  • Outbound auth. A token vault holds OAuth grants for third-party services, two-legged for service-to-service, three-legged where a user consented once and the agent acts on that consent later. This is the acting-on-behalf-of pattern with the consent stored server side instead of a refresh token pasted into an environment variable.
  • Pricing footnote. Through AgentCore Runtime or Gateway it costs nothing extra; standalone use bills per successful OAuth token or API key request. Cheap either way; the expensive part was always the incident you avoid.

The protocol layer above all of this keeps moving too. The MCP spec repo's auth queue holds proposals your gateway will meet within the year: securitySchemes in tool metadata for mixed-auth servers (SEP-1488), standardized tool errors that trigger an OAuth flow mid-session (SEP-1489), and declared authentication methods for remote servers (SEP-2742). If you operate an MCP gateway on AWS, watch that label the way you watch the EKS release notes.

Attribution is the part audits actually ask about

Temporary credentials solve theft; they do not by themselves solve "which agent did this". Three habits close that gap. One role per agent, so CloudTrail's role session already names the workload. sts:SourceIdentity set at assumption time, so the human or system that triggered the agent survives into every downstream log line even across role chaining. And session policies to scope a broad role down to the task at hand, so the blast radius of a prompt-injected or simply wrong agent is the task's permissions, not the role's. Keep the standing permissions read-only and gate every mutating action; I have made that argument enough times that regular readers can recite it.

What to do on Monday

  • Run aws iam list-users and treat every IAM user with active access keys that belongs to an automation as a finding. Agents are automations.
  • Map each agent to its runtime and adopt the matching mechanism: instance/task roles, IRSA or Pod Identity, OIDC federation, Roles Anywhere. In that order of preference.
  • Pin every OIDC trust policy on aud and the narrowest sub pattern you can write. A trust policy without a sub condition is an open door with a nice sign.
  • Set sts:SourceIdentity in every agent's assume-role call and make your CloudTrail queries use it. Retrofitting attribution after an incident does not work.
  • If you are on AgentCore, front agents with the JWT authorizer and move third-party OAuth grants into the token vault. If you are not, copy the shape: per-agent identity, validated inbound tokens, server-side consent storage.

The through line with the MCP piece is hard to miss. Protocol by protocol, platform by platform, agent identity is converging on signed short-lived assertions, audience binding, and per-workload principals, and the pieces now exist at both layers. The teams still copying access keys into agent configs are not early adopters of anything. They are running 2015 security posture against 2026 workloads.

Read this next

Agent Toolkit for AWS: The Docs Have a New Reader covers what those authenticated agents actually do with AWS access. On the sister site, Enterprise MCP Auth: Agents Finally Get Service Accounts is the protocol-layer half of this post, and ercanermis.com maps everything else I write.

References