DEV Community

mgbec for AWS Community Builders

Posted on Originally published at Medium on

The Secret Ingredient is A2A

In my last article, I wrote about https://dev.to/aws-builders/lets-talk-a2a-dual-idp-a2a-on-aws-one-agent-two-identity-providers-zero-rewrites-1c5f. I set up a compliance agent in Bedrock Agentcore and planned the API Gateway routes to have it authenticate using both AWS Cognito and Microsoft Entra authentication.

Now it is time to wire it up to a Microsoft Foundry agent using Agent2Agent. A2A protocol can take the humans out of the communication process, but we still need to watch what those agents are doing and make sure they are playing by the rules all of the annoying humans have set up for them.

A2A Authentication in Foundry

Microsoft has a number of ways to set up A2A authentication: https://learn.microsoft.com/en-us/azure/foundry/agents/concepts/agent-to-agent-authentication.

In this scenario, we are having the agents talk to one another, without human intervention. I am using a project managed identity, not an agent managed identity. It’s a little bit simpler in this case, but not right for every situation. The project managed identity uses one identity for the whole Foundry project. Agent managed identity (AgenticIdentityToken) involves a dedicated identity per deployed/hosted agent. It’s finer-grained. You could grant Agent.Invoke to one specific agent and not others, but it only exists once an agent is deployed as a Hosted agent, and you’d assign the role to that per-agent principal instead. So for project managed identity, our Terraform looks like this:

In a2a_connection.tf:

authType = “ProjectManagedIdentity”
useWorkspaceManagedIdentity = true
principal_object_id =
azurerm_cognitive_account.account.identity[0].principal_id

In main.tf

identity {
type = “SystemAssigned”
}

Tying it together

To get this all wired together, I needed to:

1) Register the AgentCore SCF Agent in Entra as an App Registration. Inside of the SCF API App Registration, I am defining an App role that applications are allowed to hold.

Entra models an app registration as two objects:

  • the application object (the global definition/blueprint, where roles are declared), and
  • the service principal object (the tenant-local instance, where assignments are recorded).

In Terraform-

resource “azuread_application_app_role” “scf_agent_invoke” {
count = var.scf_agent_app_client_id != “” &&
var.manage_scf_app_role ? 1 : 0
application_id = “/applications/${var.scf_agent_app_object_id}”
role_id = “your role id here”
allowed_member_types = [“Application”]
display_name = “Agent.Invoke”
value = “Agent.Invoke”
}

2) Now we need to grab that app role id and assign it to the project managed user.

resource “azuread_app_role_assignment”
“foundry_mi_scf_invoke” {
count = var.scf_agent_app_client_id != “” ? 1 : 0
app_role_id = “add your app role id here”
principal_object_id =
azurerm_cognitive_account.account.identity[0].principal_id
resource_object_id =
data.azuread_service_principal.scf_agent_api[0].object_id

}

This means “grant app_role_id on resource_object_id to principal_object_id”:

  • app_role_id — the same GUID as the role above; says which role.
  • principal_object_id — who gets it: azurerm_cognitive_account.account.identity[0].principal_id. That’s the Foundry account’s system-assigned MI. Terraform reads it straight off the account resource, so it always tracks the real identity even if the account is recreated.
  • resource_object_id — on which resource: the service principal object ID of the SCF app. Defining a role happens on the application object; assigning it happens against the app’s service principal. That’s why the file has a data “azuread_service_principal” lookup — to resolve the SP object ID from the client ID. If you want to look up the Service Principal’s object ID for yourself, in Enterprise applications you can look for your application id. Click on it to look at the properties. The service principal object is called the “object id”.

3. The actual connection needs to be wired up on both the AWS and Azure/Entra side.

a.) Part of the connection is an Azure-side object. Creating the azapi_resource.aws_agent_a2a_connection via terraform apply writes a persistent project connection resource into your Foundry project. You can see it under your Foundry project’s connection. It stores, persistently in Azure:

  • target (the AWS /entra/rpc URL to call)
  • authType = ProjectManagedIdentity + useWorkspaceManagedIdentity = true (how to authenticate)
  • audience (what resource to request a token for)
  • category = RemoteA2A (what kind of connection it is)

When the agent runs and decides to call the tool, Foundry’s Agent Service reads the connection, uses the account’s Managed Identity to create a fresh Entra token for the connection’s audience, resolves the agent card, and sends “message/send” with that bearer token.

b.) The other piece of the connection we need to be concerned about is the AWS side of the connection. AWS has to be prepared to receive and authenticate our particular application that lives in Azure. In this case, I own the AWS agent repo, so I can put this in terraform tf.vars and do a terraform apply.

-entra_tenant_id = “”
-entra_audience = “raw url of audience”
-entra_issuer_override = “https://sts.windows.net//” # if the MI token is v1.0

If you want to set it up in the AWS Gateway console view, your settings will look like this for the authorizer:

One thing to note- although the audience for this connection is listed as api:// on the Entra side, you will need to enter it without the preface of “api://” on the AWS API gateway side, or in Terraform.

The integration for both the Entra and Cognito authorizers in the AWS API Gateway is the scf-agent-a2a-bridge Lambda.

4. The last step takes place at the AWS API Gateway. Does the Gateway accept the token that the Foundry Managed Identity has generated? We can look in CloudWatch for troubleshooting any issues.

So the full chain, top to bottom:

  1. Role defined on the SCF app
  2. Role assigned to the Foundry MI
  3. Connection tells the MI to get a token for that audience
  4. AWS API Gateway validates the token, and agent responds.

Testing it out

Test it: agent/a2a_collaborator.py creates a small collaborator agent with the A2A tool attached, then delegates your question to the SCF agent over A2A (tool_choice=”required” forces the delegation so the round trip is actually exercised). Three ways to run it:

-python agent/a2a_collaborator.py # built-in smoke test
-python agent/a2a_collaborator.py -m “Look up SCF control IAC-15” # one-off question
-python agent/a2a_collaborator.py — interactive # chat loop, reuses one agent

A successful run shows POST /entra/rpc and will return answers from the SCF AgentCore Agent:

Next steps- observability and more threat modeling

I’ve started to make sure we have a nice level of observability, both in Azure and AWS. Threat modeling on the A2A protocol has been performed with references to https://cloudsecurityalliance.org/blog/2025/04/30/threat-modeling-google-s-a2a-protocol-with-the-maestro-framework. Stay tuned for more on that. Thanks for reading!

Top comments (0)