AWS MCP with IAM Roles Anywhere¶
This guide connects a Sympozium Agent to the AWS MCP Server using temporary
AWS credentials from IAM Roles Anywhere. It uses an X.509 certificate and the
AWS aws_signing_helper credential process, so no long-lived AWS access key
or secret key is stored in Kubernetes.
The certificate's private key remains sensitive. Store it in a Kubernetes
Secret and mount it read-only into the MCP container. Do not put it in
MCPServer.spec.deployment.secretRefs: Sympozium injects those Secret values
as environment variables.
How authentication works¶
Agent → mcp-bridge → AWS MCP proxy → AWS SDK credential process
→ aws_signing_helper + X.509 certificate
→ IAM Roles Anywhere → temporary STS credentials
→ SigV4-signed AWS MCP requests
The proxy and credential helper run in the MCP server container. The AWS SDK
uses the configured credential_process when it needs credentials and runs it
again to refresh credentials as they expire. Credentials stay in the container
and are used to sign requests; they are not passed to the Agent or model.
The IAM role's permissions policy is one authorization control for the AWS
actions the session can perform. Effective permissions also depend on
applicable session policies, permissions boundaries, service control policies
(SCPs), and explicit denies. MCP tool filters and toolsPrefix only affect
which tools are registered with the Agent; they do not enforce AWS
authorization.
Prerequisites¶
- A Sympozium cluster with the
MCPServerCRD. - An AWS account and permission to create IAM Roles Anywhere resources, an IAM role, and a least-privilege permissions policy.
- A certificate authority (CA) and an end-entity certificate issued by that CA for this workload. The CA private key must remain outside the cluster.
- A container registry reachable by the cluster.
- A Linux container image for your node architecture containing the AWS MCP
proxy,
aws_signing_helper, and a stdio entrypoint. The reference implementation includes a Dockerfile, entrypoint, and matching Sympozium manifest. Review and build it in your own supply chain; pin the proxy version and verify the helper checksum rather than using a floatinglatestimage. - The AWS MCP Server endpoint in a supported Region. See the AWS MCP Server endpoints.
The example below assumes an endpoint of the form
https://aws-mcp.<region>.api.aws/mcp. Keep the Roles Anywhere resources,
credential-helper region, and endpoint signing region aligned as required by
your deployment.
1. Issue the workload certificate¶
Use your organization's CA to issue a client certificate for the MCP workload.
The certificate must chain to the CA certificate you register with IAM Roles
Anywhere. Give it a workload-unique Subject Alternative Name (SAN) URI, such as
spiffe://example.com/sympozium/aws-mcp, and make sure the CA does not issue
that identity to another workload. The profile's attribute mapping must include
x509SAN/URI for the trust policy condition to work; AWS maps SAN URI values by
default. The
reference implementation's provisioning notebook
demonstrates a disposable EasyRSA CA and client certificate for a lab. Do not
use its local CA for production; keep the CA private key outside the cluster.
2. Create the trust anchor, role, and profile¶
IAM Roles Anywhere exchanges a certificate chain trusted by a configured trust
anchor for temporary role credentials. Create a role whose trust policy is
restricted to this anchor and the workload certificate subject, then attach a
permissions policy for the AWS actions the Agent needs. This lab example
attaches the AWS managed ViewOnlyAccess policy; it is broad, so replace it
with a narrower custom policy for production.
In the AWS console, create an IAM Roles Anywhere trust anchor with your CA certificate as its certificate bundle and enable it. Use the resulting trust anchor ARN in the trust policy below. Create the trust anchor in the Region where you will create the profile and request credentials.
The role trust policy must trust the IAM Roles Anywhere service principal and should scope assumptions to the expected trust anchor and certificate identity. For example, adapt the condition values to your CA and the unique SAN URI in your certificate:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "rolesanywhere.amazonaws.com" },
"Action": ["sts:AssumeRole", "sts:SetSourceIdentity", "sts:TagSession"],
"Condition": {
"ArnEquals": {
"aws:SourceArn": "TRUST_ANCHOR_ARN"
},
"StringEquals": {
"aws:PrincipalTag/x509SAN/URI": "spiffe://example.com/sympozium/aws-mcp"
}
}
}]
}
Create the role and attach the lab policy (replace the placeholders):
aws iam create-role \
--role-name sympozium-aws-mcp \
--assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy \
--role-name sympozium-aws-mcp \
--policy-arn arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
Create a Roles Anywhere profile that permits this role, then record both ARNs. The credential helper uses the trust anchor, profile, and role ARNs to request temporary credentials:
aws rolesanywhere create-profile \
--name sympozium-aws-mcp \
--role-arns arn:aws:iam::123456789012:role/sympozium-aws-mcp \
--enabled \
--region us-east-1
For details, see the AWS Roles Anywhere trust model, credential helper, and create-profile command.
3. Build and publish the MCP container¶
Build an image for the architecture of the cluster nodes. Include a pinned
version of the AWS MCP proxy and aws_signing_helper. The entrypoint should
run the proxy in stdio mode, keeping stdout reserved for MCP messages and
writing diagnostics to stderr. The reference implementation linked above
shows one way to package these components; Sympozium does not publish or
maintain that image.
Push the image to a registry available to your cluster and use an immutable
version tag in the MCPServer below. Configure an image pull Secret on the
MCP server ServiceAccount if the registry is private.
4. Create the certificate Secret¶
Create a Secret containing the end-entity certificate and its private key. The key is sensitive material: do not commit it, print it in command output, or put it in a ConfigMap or environment variable. Use your certificate issuer's filenames or rename them to match this example:
kubectl create secret generic aws-mcp-certificate \
--namespace sympozium-system \
--from-file=tls.crt=./work/client.crt \
--from-file=tls.key=./work/client.key
Kubernetes mounts Secret volumes read-only in the pod specification below.
Enable encryption at rest for Kubernetes Secrets or use an external secret
provider, and tightly restrict RBAC access to the Secret in
sympozium-system. The example sets the projected files to mode 0400; ensure
the helper process runs as a UID that can read them. Rotate the certificate
before it expires. Replacing the certificate Secret does not reissue the
certificate; follow your CA's issuance and rotation process.
5. Configure the AWS profile and MCPServer¶
Create a ConfigMap with an AWS shared config profile. The credential helper uses the mounted certificate and key to obtain temporary credentials from IAM Roles Anywhere. Replace the ARN placeholders and region with your values:
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-mcp-config
namespace: sympozium-system
data:
config: |
[profile sympozium-mcp]
region = us-east-1
credential_process = /usr/local/bin/aws_signing_helper credential-process --certificate /certs/tls.crt --private-key /certs/tls.key --trust-anchor-arn arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/TA_ID --profile-arn arn:aws:rolesanywhere:us-east-1:123456789012:profile/PROFILE_ID --role-arn arn:aws:iam::123456789012:role/sympozium-aws-mcp
Apply the ConfigMap, then create the MCPServer. Set image to the image you
built and pushed. Its entrypoint path and environment variables must match
that image's proxy configuration.
apiVersion: sympozium.ai/v1alpha1
kind: MCPServer
metadata:
name: aws-mcp
namespace: sympozium-system
spec:
transportType: stdio
toolsPrefix: aws
timeout: 180
deployment:
image: registry.example.com/aws-mcp-roles-anywhere:1.0.0
cmd: /app/entrypoint.sh
env:
AWS_CONFIG_FILE: /config/config
AWS_PROFILE: sympozium-mcp
AWS_REGION: us-east-1
MCP_ENDPOINT: https://aws-mcp.us-east-1.api.aws/mcp
volumes:
- name: aws-config
configMap:
name: aws-mcp-config
- name: aws-certificate
secret:
secretName: aws-mcp-certificate
defaultMode: 0400
volumeMounts:
- name: aws-config
mountPath: /config
readOnly: true
- name: aws-certificate
mountPath: /certs
readOnly: true
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 512Mi
Apply both resources and wait for the MCPServer deployment to become ready:
kubectl apply -f aws-mcp-config.yaml
kubectl apply -f aws-mcp-server.yaml
kubectl get mcpserver aws-mcp -n sympozium-system
The proxy image must not contain static AWS access keys. Do not add
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, or AWS_SESSION_TOKEN to the
deployment; configure only the profile and certificate-based credential
process.
6. Attach the MCP server to an Agent¶
Reference the MCPServer by name in the Agent. The prefix namespaces the MCP
tools to avoid name collisions; it does not grant IAM permissions.
apiVersion: sympozium.ai/v1alpha1
kind: Agent
metadata:
name: aws-inventory
namespace: default
spec:
agents:
default:
model: gpt-4o
mcpServers:
- name: aws-mcp
toolsPrefix: aws
Apply the Agent and test a read-only operation against a non-sensitive resource. Confirm the IAM role denies an action outside its effective permissions. A tool allowlist can reduce which tools the Agent sees, but AWS IAM policies and applicable organization controls determine the permissions for every signed request.
Troubleshooting¶
- Credential process fails: Check that the mounted certificate matches the private key, the certificate chains to the trust anchor, the role trust policy permits the trust anchor and certificate identity, and the profile includes the role.
- Access denied: Check the role's permissions policy and the requested resource. Tool filtering does not change role permissions.
- MCP server cannot connect: Confirm the AWS MCP endpoint is available in the selected Region and that the pod can reach it over HTTPS.
- Pod cannot start: Check the image architecture, image pull access, and that the configured helper and entrypoint paths exist in the image.