AWS Secrets Manager Integration with Bedrock AgentCore¶
This guide provides the steps to integrate AWS Secrets Manager with the Zscaler MCP Server on Amazon Bedrock AgentCore.
Important Discovery¶
After reviewing the AWS CLI API documentation for bedrock-agentcore-control create-agent-runtime, the following parameters are available:
{
"agentRuntimeName": "",
"description": "",
"agentRuntimeArtifact": { "containerConfiguration": {} },
"roleArn": "",
"networkConfiguration": {},
"protocolConfiguration": {},
"environmentVariables": {},
"authorizerConfiguration": {}
}
Key Finding: There is NO identity-configuration or secretsManagerConfiguration parameter in the current AgentCore API.
This means:
AgentCore does NOT have built-in Secrets Manager integration at the container configuration level
No native “token vault” parameter for automatic secret injection
You must use one of the practical approaches below
Available Approaches¶
Approach |
Container Changes |
Complexity |
Security |
Recommended For |
|---|---|---|---|---|
1. Pre-Deployment Retrieval |
None |
Low |
Good |
Most users |
2. Container Runtime Retrieval |
Required |
Medium |
Better |
Enterprise |
3. Lambda Proxy |
None |
Medium |
Good |
Automated pipelines |
Approach 1: Pre-Deployment Secret Retrieval (Recommended)¶
Retrieve secrets from Secrets Manager before creating the agent runtime and pass them as environment variables.
Advantages¶
No container modifications
Simple to implement
Works with existing image
Easy to automate
Considerations¶
Credentials visible in AWS console (in agent runtime configuration)
Requires re-deployment for rotation
Step 1: Create Secret in Secrets Manager¶
aws secretsmanager create-secret \
--region us-east-1 \
--name zscaler/mcp/credentials \
--description "Zscaler MCP Server API Credentials" \
--secret-string '{
"ZSCALER_CLIENT_ID": "your_client_id",
"ZSCALER_CLIENT_SECRET": "your_client_secret",
"ZSCALER_VANITY_DOMAIN": "your_domain",
"ZSCALER_CUSTOMER_ID": "your_customer_id",
"ZSCALER_CLOUD": "production",
"ZSCALER_MCP_WRITE_ENABLED": "true",
"ZSCALER_MCP_WRITE_TOOLS": "zpa_*,zia_*"
}'
Verify the secret:
aws secretsmanager get-secret-value \
--region us-east-1 \
--secret-id zscaler/mcp/credentials \
--query SecretString \
--output text | jq
Step 2: Grant Deployment User/Role Secrets Manager Access¶
Your deployment user or role (not the AgentCore execution role) needs permission to read secrets:
cat > deployment-secrets-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadZscalerSecrets",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:*:secret:zscaler/mcp/*"
]
}
]
}
EOF
# Attach to your deployment user
aws iam put-user-policy \
--user-name your-deployment-user \
--policy-name ZscalerSecretsDeploymentAccess \
--policy-document file://deployment-secrets-policy.json
# OR attach to your deployment role
aws iam put-role-policy \
--role-name your-deployment-role \
--policy-name ZscalerSecretsDeploymentAccess \
--policy-document file://deployment-secrets-policy.json
Step 3: Retrieve Secrets and Build Environment Variables¶
# Retrieve the secret
SECRET_JSON=$(aws secretsmanager get-secret-value \
--region us-east-1 \
--secret-id zscaler/mcp/credentials \
--query SecretString \
--output text)
# Parse the JSON values into shell variables
ZSCALER_CLIENT_ID=$(echo $SECRET_JSON | jq -r '.ZSCALER_CLIENT_ID')
ZSCALER_CLIENT_SECRET=$(echo $SECRET_JSON | jq -r '.ZSCALER_CLIENT_SECRET')
ZSCALER_VANITY_DOMAIN=$(echo $SECRET_JSON | jq -r '.ZSCALER_VANITY_DOMAIN')
ZSCALER_CUSTOMER_ID=$(echo $SECRET_JSON | jq -r '.ZSCALER_CUSTOMER_ID')
Step 4: Create AgentCore Runtime with Retrieved Secrets¶
aws bedrock-agentcore-control create-agent-runtime \
--agent-runtime-name zscaler-mcp-server \
--description "Zscaler MCP Server with Secrets Manager" \
--role-arn arn:aws:iam::ACCOUNT_ID:role/zscaler-mcp-execution-role \
--network-configuration '{"networkMode":"PUBLIC"}' \
--protocol-configuration '{"serverProtocol":"MCP"}' \
--environment-variables "{
\"ZSCALER_CLIENT_ID\":\"$ZSCALER_CLIENT_ID\",
\"ZSCALER_CLIENT_SECRET\":\"$ZSCALER_CLIENT_SECRET\",
\"ZSCALER_VANITY_DOMAIN\":\"$ZSCALER_VANITY_DOMAIN\",
\"ZSCALER_CUSTOMER_ID\":\"$ZSCALER_CUSTOMER_ID\"
}" \
--agent-runtime-artifact "containerConfiguration={
containerUri=ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/zscaler/zscaler-mcp-server:latest
}" \
--region us-east-1
Approach 2: Container Runtime Retrieval¶
The container retrieves secrets from Secrets Manager at startup using boto3, so secrets are never visible in the AgentCore configuration.
Advantages¶
Secrets NEVER appear in AgentCore configuration
Secrets NEVER appear in CloudFormation/CDK templates
Automatic rotation support (re-fetch on restart)
Strongest security posture
Considerations¶
Requires container code changes (already implemented in
zscaler_mcp/config.py)AgentCore execution role needs Secrets Manager access
Slight startup delay (~100ms for secret retrieval)
How It Works¶
The Zscaler MCP Server’s container image already includes zscaler_mcp/config.py, a side-effect module that runs at process boot via aws_entrypoint.py:
The deploy script writes the credential JSON to a Secrets Manager entry (e.g.
zscaler-mcp/credentials).The AgentCore runtime task definition gets only
ZSCALER_SECRET_NAME=<that-name>— never the actual credential values.The execution role gets a scoped two-statement inline policy:
secretsmanager:GetSecretValueon the secret ARN +kms:Decryptfiltered bykms:ViaService=secretsmanager.<region>.At container boot,
config.pycallsGetSecretValuevia boto3, parses the JSON, andos.environ-injects each key. The SDK then initialises exactly as if the keys had been passed as env vars.
Required IAM Policy for the Execution Role¶
The AgentCore execution role (the role passed to create-agent-runtime --role-arn) needs the following inline policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadZscalerCredentialsSecret",
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": [
"arn:aws:secretsmanager:us-east-1:ACCOUNT_ID:secret:zscaler/mcp/credentials-*"
]
},
{
"Sid": "DecryptZscalerCredentialsSecret",
"Effect": "Allow",
"Action": ["kms:Decrypt"],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
}
}
}
]
}
The -* ARN wildcard handles the random 6-char suffix Secrets Manager appends to secret ARNs.
Deploying with Container Runtime Retrieval¶
After creating the secret (same as Approach 1, Step 1) and granting the execution role the policy above:
aws bedrock-agentcore-control create-agent-runtime \
--agent-runtime-name zscaler-mcp-server \
--description "Zscaler MCP Server with container-side secret retrieval" \
--role-arn arn:aws:iam::ACCOUNT_ID:role/zscaler-mcp-execution-role \
--network-configuration '{"networkMode":"PUBLIC"}' \
--protocol-configuration '{"serverProtocol":"MCP"}' \
--environment-variables '{
"ZSCALER_SECRET_NAME": "zscaler/mcp/credentials",
"AWS_REGION": "us-east-1"
}' \
--agent-runtime-artifact "containerConfiguration={
containerUri=ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/zscaler/zscaler-mcp-server:latest
}" \
--region us-east-1
Notice the environment variables now contain only ZSCALER_SECRET_NAME and AWS_REGION — the actual Zscaler credentials never leave Secrets Manager.
Approach 3: Lambda Proxy¶
A Lambda function acts as a proxy: it fetches the secret from Secrets Manager and creates the AgentCore runtime with the retrieved values, all within an automated pipeline.
Best for: CI/CD pipelines, GitOps deployments, multi-environment automation.
The flow is:
CI/CD triggers a Lambda function
Lambda retrieves the secret from Secrets Manager
Lambda calls
bedrock-agentcore-control:CreateAgentRuntimewith the retrieved values as env varsLambda destroys the temporary credential strings from memory
This pattern is essentially Approach 1 wrapped in a Lambda — same security model, but the secret-retrieval step never runs on a developer workstation.
Secret rotation¶
For Approach 1 (Pre-Deployment Retrieval), rotation requires re-deploying the AgentCore runtime with the new credentials.
For Approach 2 (Container Runtime Retrieval), rotation works automatically because the container re-fetches the secret on every cold start. To force a refresh:
# Rotate the secret
aws secretsmanager put-secret-value \
--region us-east-1 \
--secret-id zscaler/mcp/credentials \
--secret-string '{"ZSCALER_CLIENT_SECRET":"new_secret",...}'
# Force the AgentCore runtime to cycle (creates a new task with fresh env)
aws bedrock-agentcore-control update-agent-runtime \
--agent-runtime-name zscaler-mcp-server \
--region us-east-1 \
...
Security comparison summary¶
Property |
Approach 1 |
Approach 2 |
Approach 3 |
|---|---|---|---|
Container changes needed |
No |
Yes |
No |
Secrets in AgentCore config |
Yes |
No |
Yes |
Secrets in CloudTrail (CreateAgentRuntime call) |
Yes |
No |
Yes (Lambda call only) |
Rotation requires redeploy |
Yes |
No |
Yes |
Suitable for production |
With caveats |
Yes |
Yes |
Suitable for compliance regimes (SOC2, ISO27001, PCI-DSS) |
Limited |
Yes |
Yes |
Use Approach 2 whenever you can — the Zscaler MCP Server container image already supports it.
See also¶
Amazon Bedrock AgentCore Deployment — full AgentCore Runtime deployment walkthrough.
AWS Harness — AgentCore Harness deployment — AgentCore Harness preview, which uses Approach 2 by default.
Strands Agent client for AgentCore Runtime — local Strands client for testing a deployed runtime.