Related:aws-devops-agent-slack-bridge — Slack 通知 + chatbot,在 PetSite 上跑 AWS DevOps Agent 的主线集成。本仓是其中中国区桥接部分拆出来的独立项目。
让 Global 分区 的 AWS DevOps Agent(仅在 us-east-1/us-west-2 等可用,不支持 aws-cn)能只读访问中国区(cn-northwest-1 / cn-north-1)资源。如需写权限,部署时传 ManagedPolicyArn=...PowerUserAccess 或 ...AdministratorAccess 显式 opt-in。
本模板从 workshop 项目
operating-china-region-using-devops-agent提炼而来,去除 Workshop Studio 强依赖(不再从 assets bucket 拉 cert),改成 SSM Parameter Store 输入;ALB SG 接 CloudFront origin-facing prefix list;IAM Role 默认ReadOnlyAccess;MCP server 默认@latest。
当前是 只读模式(默认):
- 中国 IAM Role 默认挂
ReadOnlyAccess(只能列出 / 描述资源,不能创建 / 修改 / 删除) - MCP server 未设
READ_OPERATIONS_ONLY(这是 profile namechina-readonly+ IAM 只读 policy 双重限制) - 任何拿到 X-API-Key + CloudFront 域名 的人只能读中国账号信息(包括资源拓扑、IAM 配置、实例信息等)
如果你主动 opt-in 扩大权限(ManagedPolicyArn=...AdministratorAccess):
- 中国 IAM Role 能干账号内任何事(创建 / 删除 / 修改)
- 拿到 X-API-Key + CloudFront 域名 的人 = 中国账号完全控制权
无论哪种模式,请确保:
- SecretsManager 里的 API Key 只发给必要的人,泄漏后立即 update-stack 旋转
- client.crt/key 在本地 + SSM SecureString 严妥保管,泄漏后立即删 Trust Anchor 重建
- CloudWatch / CloudTrail 开启中国账号审计,跟踪
devops-agent-cn-admin-role的所有调用
DevOps Agent (Global, e.g. us-east-1)
│ HTTPS + X-API-Key
▼
CloudFront ──► ALB(:80) ──► EC2
├─ :8000 aws-api-mcp-server (path: /mcp)
└─ :8001 mcp-proxy (path: /servers/<name>/mcp)
├─ spawns awslabs.cloudwatch-mcp-server (stdio)
├─ spawns awslabs.eks-mcp-server (stdio)
└─ spawns awslabs.cost-explorer-mcp-server (stdio)
│
▼ credential_process (共享)
aws_signing_helper ──► IAM Roles Anywhere
(X.509 client cert) (cn-northwest-1)
│ 1h 临时凭证 (ReadOnly default)
▼
aws-cn API
| 文件 | 部署位置 | 作用 |
|---|---|---|
01-cn-roles-anywhere.yaml |
中国账号 / cn-northwest-1 | Trust Anchor + Profile + Read-Only IAM Role(可 opt-in 到 Admin) |
02-global-mcp-bridge.yaml |
Global 账号 / us-east-1 | VPC + ALB(prefix list) + CloudFront + EC2 跑 aws-api-mcp-server (:8000) 和 mcp-proxy (:8001,多 MCP server 网关) |
mkdir -p ~/devops-agent-cn-bridge-certs && cd ~/devops-agent-cn-bridge-certs
# CA(10 年)
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
-out ca.crt -subj "/CN=devops-agent-cn-bridge-ca"
# Client cert(1 年;到期需重发)
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
-subj "/CN=devops-agent-cn-bridge-client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt -days 365 -sha256
chmod 600 ca.key client.keyaws cloudformation deploy \
--region cn-northwest-1 \
--profile <your-china-profile> \
--stack-name devops-agent-cn-bridge \
--template-file 01-cn-roles-anywhere.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
CACertificateBody="$(cat ~/devops-agent-cn-bridge-certs/ca.crt)"记下 outputs:
aws cloudformation describe-stacks \
--region cn-northwest-1 --profile <your-china-profile> \
--stack-name devops-agent-cn-bridge \
--query 'Stacks[0].Outputs'会拿到 TrustAnchorArn / ProfileArn / RoleArn。
想收紧权限?默认已是
ReadOnlyAccess,无需额外参数。需要写权限才传--parameter-overrides ManagedPolicyArn=arn:aws-cn:iam::aws:policy/PowerUserAccess(或 AdministratorAccess / 你自己的 managed policy ARN)。
GLOBAL_REGION=us-east-1
aws ssm put-parameter \
--region $GLOBAL_REGION \
--name /devops-agent-cn-bridge/client-cert \
--type SecureString \
--value "$(cat ~/devops-agent-cn-bridge-certs/client.crt)" \
--overwrite
aws ssm put-parameter \
--region $GLOBAL_REGION \
--name /devops-agent-cn-bridge/client-key \
--type SecureString \
--value "$(cat ~/devops-agent-cn-bridge-certs/client.key)" \
--overwriteaws cloudformation deploy \
--region us-east-1 \
--stack-name devops-agent-cn-bridge \
--template-file 02-global-mcp-bridge.yaml \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
TrustAnchorArn="arn:aws-cn:rolesanywhere:cn-northwest-1:..." \
ProfileArn="arn:aws-cn:rolesanywhere:cn-northwest-1:..." \
CnRoleArn="arn:aws-cn:iam::...:role/devops-agent-cn-admin-role" \
CnRegion=cn-northwest-1部署完成后取出端点和 API Key:
aws cloudformation describe-stacks \
--region us-east-1 --stack-name devops-agent-cn-bridge \
--query 'Stacks[0].Outputs'
# API Key 明文
aws secretsmanager get-secret-value \
--region us-east-1 \
--secret-id devops-agent-cn-bridge/alb-api-key \
--query SecretString --output textENDPOINT="<McpEndpointHttps from outputs>"
API_KEY="<from secretsmanager>"
aws bedrock-agent register-service \
--region us-east-1 \
--service-name devops-agent-cn-bridge \
--service-type mcpserver \
--service-config "{\"endpoint\":\"$ENDPOINT\",\"apiKey\":\"$API_KEY\"}"
# 然后到 Bedrock Agent Space 把 call_aws / suggest_aws_commands 关联到你的 AgentENDPOINT="<McpEndpointHttps>"
API_KEY="<from secretsmanager>"
# MCP initialize
curl -sS "$ENDPOINT" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'02-global-mcp-bridge.yaml 在 stack 内置一个小 Lambda custom resource,部署时调用 ec2:DescribeManagedPrefixLists 查找当前 region 的 com.amazonaws.global.cloudfront.origin-facing 这条 AWS managed prefix list(每个 region 的 pl-xxx ID 不同,且没有公共 SSM 参数路径),把 ID 注入到 ALB SG 的 ingress rule。
这样:
- 只有 CloudFront 的回源 IP 段能直连 ALB :80
- 即使有人扫到 ALB DNS,也访问不通(403 / connection refused)
- AWS 维护这个 prefix list,IP 范围变更不需要你管
需要再加管理员/测试 IP 直连?传 AllowedAdminCidrs=1.2.3.4/32,5.6.7.8/32(最多 2 个)。
McpServerVersion=latest(默认)。EC2 重启或重建时拉最新版。
风险:上游 awslabs.aws-api-mcp-server 出 breaking change 会让桥服务挂掉。
出问题时把参数改成具体版本(例如 0.2.5)做 update-stack 即可回退。
除了 aws-api-mcp-server,其他 awslabs MCP server (cloudwatch / eks / cost-explorer / ...) 都是原生 stdio(看 mcp.run() 源码,FastMCP 不从环境变量读 transport)。在同一 EC2 跑一个 mcp-proxy(sparfenyuk/mcp-proxy)进程,用 Named Servers 模式多实例存放,每个 server 映射到 /servers/<name>/mcp path。
漟加/减只需改 CFN McpProxyServers 参数(逗号分隔字符串,默认 cloudwatch,eks,cost-explorer) → update-stack,EC2 UserData 重生成 /opt/mcp-bridge/mcp-proxy-servers.json + restart,不需动 ALB / TG。
# 示例:只启 cloudwatch 和 eks
ManagedPolicyArn=...ReadOnlyAccess
McpProxyServers='cloudwatch,eks'
# 完全关闭 mcp-proxy、只保留 aws-api-mcp-server
EnableMcpProxy=false
注册到 DevOps Agent 时,每个 server 一个 endpoint URL:
ENDPOINT_BASE="https://${CFN_DOMAIN}"
aws bedrock-agent register-service --service-name agent-cn-aws-api \
--service-config "{\"endpoint\":\"$ENDPOINT_BASE/mcp\",\"apiKey\":\"$API_KEY\"}"
for srv in cloudwatch eks cost-explorer; do
aws bedrock-agent register-service --service-name agent-cn-$srv \
--service-config "{\"endpoint\":\"$ENDPOINT_BASE/servers/$srv/mcp\",\"apiKey\":\"$API_KEY\"}"
done健康检查:curl -H 'X-API-Key: ...' $ENDPOINT_BASE/status — mcp-proxy 自带的状态端点。返回 200 + JSON 表示哪些 named server 启用。
注意:mcp-proxy 是社区项目,默认 釘版本 0.10.2(不跳 latest,避免 breaking change)。需要升级手动改 McpProxyVersion 参数。
ALB ListenerRule 用 {{resolve:secretsmanager:...}} 引用 API Key,是 CFN 模板期 解析的静态值。SecretsManager 自动旋转后 ALB 规则不会跟着变,必须 update-stack 才生效。
解决思路(未实现):
- 用 Lambda@Edge / CloudFront Function 在边缘做 header 校验,从 SecretsManager 读最新值
- 或换成 ALB + Cognito / OIDC 真正的 auth 层
单 AZ、单 instance、public subnet。Demo 够用,生产建议:
- ASG 起 2 台跨 AZ
- TargetGroup 多 target
- 移到 private subnet + NAT GW
| 项 | Workshop 原版 | 本模板 |
|---|---|---|
| cert/params 来源 | S3 assets bucket | SSM Parameter Store SecureString |
| MCP server 版本 | awslabs...@latest |
参数化(默认 latest,可钉版) |
AWS_API_MCP_ALLOWED_HOSTS |
* |
ALB DNS(防 Host header 攻击) |
READ_OPERATIONS_ONLY |
true |
不设置(依赖 IAM ReadOnlyAccess 限制) |
| ALB SG ingress | DevOps Agent IP/32 + 0.0.0.0/0 |
CloudFront origin-facing prefix list + 可选 admin CIDR |
| China Role policy | ReadOnlyAccess |
ReadOnlyAccess(默认;可参数覆盖为 PowerUser / Admin) |
| CloudFront | 必选 | 可选(EnableCloudFront) |
| Roles Anywhere session | 固定 3600s | 参数化 |
| 中国 sample resources | 模板内含 | 不包含 |
# Global
aws cloudformation delete-stack --region us-east-1 --stack-name devops-agent-cn-bridge
# China
aws cloudformation delete-stack --region cn-northwest-1 --profile <china> \
--stack-name devops-agent-cn-bridge
# SSM
aws ssm delete-parameter --region us-east-1 --name /devops-agent-cn-bridge/client-cert
aws ssm delete-parameter --region us-east-1 --name /devops-agent-cn-bridge/client-key