使用 iam-role-anywhere 在中国区访问 global 区域 secret manager
Cross-partition access: AWS China to AWS Commercial via IAM Roles Anywhere¶
Reference: https://aws.amazon.com/blogs/security/transfer-data-across-aws-partitions-with-iam-roles-anywhere/
Why IAM Roles Anywhere?¶
普通 cross-account: Account A ──AssumeRole──▶ Account B
同一个 IAM 平面,直接信任即可
跨分区 (cn ↔ aws): aws-cn 的 IAM ≠ aws 的 IAM
两套独立的身份系统
trust policy 写对方分区的 principal → 直接报错
所以需要一个「分区外」的身份凭据 → X.509 证书
IAM Roles Anywhere 就是把 X.509 证书翻译成 STS 临时凭证的桥梁
一句话:IAM Roles Anywhere = X.509 证书 → STS 临时凭证的翻译器。让任何能持有证书的地方(另一个分区、on-prem、IoT 设备)都能像 EC2 instance profile 一样免 AK/SK 地调 AWS API。
Architecture¶
cn-north-1 (aws-cn, <CN_ACCOUNT_ID>) us-west-2 (aws, <COM_ACCOUNT_ID>)
┌─────────────────────────────────┐ ┌──────────────────────────────────────┐
│ VPC 10.x.0.0/16 │ │ IAM Roles Anywhere │
│ └─ public subnet + IGW │ ① client cert │ Trust Anchor ← Root CA (self-sign) │
│ └─ EC2 │ (X.509 over TLS) │ Profile → <ROLE_NAME> │
│ Ubuntu 24.04 │──────────────────▶ │ │
│ /etc/ira/client.crt │ │ IAM Role │
│ /etc/ira/client.key │ ② temp creds │ trust: rolesanywhere.amazonaws.com │
│ aws_signing_helper │◀────────────────── │ allow: secretsmanager:Get/Describe │
│ │ │ │
│ aws --profile commercial \ │ ③ GetSecretValue │ Secrets Manager │
│ secretsmanager │──────────────────▶ │ <SECRET_NAME> │
│ get-secret-value │ │ │
└─────────────────────────────────┘ └──────────────────────────────────────┘
How it works - 一次性准备(建立信任链)¶
管理员
│
├─➊ 建一个 Root CA(自签名或 AWS Private CA)
│ 产出: root-ca.crt, root-ca.key
│
├─➋ 用 Root CA 签发 client cert 给工作负载
│ 产出: client.crt, client.key
│
└─➌ 在目标 AWS 账号 (us-west-2) 做三件事:
│
├─ Trust Anchor: 上传 root-ca.crt
│ → "我信任这个 CA 签发的所有证书"
│
├─ IAM Role: 创建角色,trust policy 写
│ Principal: rolesanywhere.amazonaws.com
│ → "IAM Roles Anywhere 服务可以 AssumeRole"
│
└─ Profile: 绑定 Role + 设置 session 时长
→ "用这个 Profile 来的请求,给它这个 Role"
建完之后的信任链:
root-ca.crt ──签发──▶ client.crt
│ │
▼ ▼
Trust Anchor EC2 上的工作负载
(us-west-2 持有 client.crt + client.key
"我认识这个CA")
How it works - 运行时(每次需要凭证时)¶
这是 aws_signing_helper credential-process 每次被调用时干的事:
EC2 (cn-north-1) IAM Roles Anywhere (us-west-2)
│ │
│ ➊ 用 client.key 对请求做数字签名 │
│ 把 client.crt 附在请求里 │
│──── CreateSession (HTTPS) ──────────────────────────▶ │
│ │
│ ➋ 收到请求,做两件事:
│ a) 从 client.crt 提取 issuer
│ 去 Trust Anchor 里找对应 CA
│ 用 root-ca.crt 验签 client.crt
│ → 证书链合法? ✓
│ b) 验证数字签名
│ → 请求方确实持有 private key? ✓
│ │
│ ➌ 两项都通过 → 调用 STS AssumeRole
│ 用 Profile 绑定的 Role
│ 生成临时凭证 (AK/SK/Token, 1h TTL)
│ │
│◀──── 返回临时凭证 ────────────────────────────────────│
│ │
│ ➍ 拿到凭证,注入到 AWS CLI / SDK 的请求中 │
│ 正常调 AWS API(如 secretsmanager:GetSecretValue) │
│ │
关键:整个过程没有任何长期 AK/SK 参与。client.key 从不离开 EC2,也不发给 AWS。AWS 只看到 client.crt(公钥)和用 private key 做的签名。
Flow summary:
- EC2 上的
aws_signing_helper用 X.509 client cert 向 Commercial 区 IAM Roles Anywhere 发起认证 - IAM Roles Anywhere 用 Trust Anchor 中注册的 CA 验证证书,签发临时 STS 凭证 (1h TTL)
- EC2 用临时凭证调用 us-west-2 Secrets Manager API
Prerequisites¶
- Two AWS CLI profiles: one for cn-north-1 (China partition), one for us-west-2 (Commercial partition)
- OpenSSL (生成自签名 CA)
- 本地工作目录用于存放 PKI 文件和脚本
Step 1 - Generate Root CA and client certificate¶
CA cert 必须带 basicConstraints=critical,CA:TRUE 扩展,否则 CreateTrustAnchor 会报 Incorrect basic constraints for CA certificate。
# Root CA key + cert (10 year)
openssl genrsa -out root-ca.key 4096
cat > root-ca.cnf <<'EOF'
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[ req_distinguished_name ]
C = CN
O = IRA-Test
OU = PKI
CN = IRA-Test-RootCA
[ v3_ca ]
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign, digitalSignature
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
EOF
openssl req -x509 -new -nodes -key root-ca.key -sha256 -days 3650 \
-config root-ca.cnf -out root-ca.crt
# Client key + cert (1 year, signed by Root CA)
openssl genrsa -out client.key 2048
openssl req -new -key client.key \
-subj "/C=CN/O=IRA-Test/OU=Workloads/CN=cn-ec2-workload" \
-out client.csr
cat > client.ext <<'EOF'
basicConstraints=CA:FALSE
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=clientAuth
EOF
openssl x509 -req -in client.csr -CA root-ca.crt -CAkey root-ca.key \
-CAcreateserial -out client.crt -days 365 -sha256 -extfile client.ext
openssl verify -CAfile root-ca.crt client.crt
Step 2 - Commercial partition setup (us-west-2)¶
AWS="aws --profile <COM_PROFILE> --region us-west-2"
# 2.1 Secret
${AWS} secretsmanager create-secret \
--name "<SECRET_NAME>" \
--secret-string "hello-from-us-west-2"
# 2.2 IAM Role (trust IAM Roles Anywhere)
cat > trust-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "rolesanywhere.amazonaws.com" },
"Action": [ "sts:AssumeRole", "sts:TagSession", "sts:SetSourceIdentity" ]
}]
}
EOF
${AWS} iam create-role \
--role-name ira-xpart-test-role \
--assume-role-policy-document file://trust-policy.json
# 2.3 Inline policy - read secret
cat > secret-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [ "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret" ],
"Resource": "<SECRET_ARN>"
}]
}
EOF
${AWS} iam put-role-policy \
--role-name ira-xpart-test-role \
--policy-name ira-xpart-test-policy \
--policy-document file://secret-policy.json
# 2.4 Trust Anchor (upload Root CA cert)
${AWS} rolesanywhere create-trust-anchor \
--name ira-xpart-test-trust-anchor \
--source "sourceType=CERTIFICATE_BUNDLE,sourceData={x509CertificateData=\"$(cat root-ca.crt)\"}" \
--enabled
# 2.5 Profile
${AWS} rolesanywhere create-profile \
--name ira-xpart-test-profile \
--role-arns "<ROLE_ARN>" \
--duration-seconds 3600 \
--enabled
Step 3 - China partition setup (cn-north-1)¶
Launch an EC2 (m5.large, Ubuntu 24.04 ami-062d2c5b771a4b959) in a public subnet with SSH access.
Step 4 - EC2 bootstrap¶
# Upload certs
scp client.crt client.key root-ca.crt ubuntu@<EC2_IP>:/tmp/
ssh ubuntu@<EC2_IP>
# On EC2:
sudo mkdir -p /etc/ira
sudo mv /tmp/client.crt /tmp/client.key /tmp/root-ca.crt /etc/ira/
sudo chown ubuntu:ubuntu /etc/ira/* # credential_process runs as ubuntu
sudo chmod 600 /etc/ira/client.key
# Install AWS CLI v2
curl -sS "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
cd /tmp && unzip -q awscliv2.zip && sudo ./aws/install
# Install aws_signing_helper (v1.8.1)
sudo curl -sSL -o /usr/local/bin/aws_signing_helper \
https://rolesanywhere.amazonaws.com/releases/1.8.1/X86_64/Linux/Amzn2023/aws_signing_helper
sudo chmod +x /usr/local/bin/aws_signing_helper
# Configure AWS CLI profile
cat > ~/.aws/config <<'CFG'
[profile commercial]
region = us-west-2
credential_process = /usr/local/bin/aws_signing_helper credential-process \
--certificate /etc/ira/client.crt \
--private-key /etc/ira/client.key \
--trust-anchor-arn <TRUST_ANCHOR_ARN> \
--profile-arn <PROFILE_ARN> \
--role-arn <ROLE_ARN>
CFG
Step 5 - Verify¶
# STS identity — should show assumed-role in your Commercial account
aws --profile commercial sts get-caller-identity
# Read secret from us-west-2
aws --profile commercial secretsmanager get-secret-value \
--secret-id <SECRET_NAME>
Python SDK example¶
boto3 原生支持 credential_process,配好 ~/.aws/config 后无需额外凭证代码:
#!/usr/bin/env python3
import boto3
session = boto3.Session(profile_name="commercial")
# who am I?
sts = session.client("sts")
identity = sts.get_caller_identity()
print(f"Account: {identity['Account']}")
print(f"Arn: {identity['Arn']}")
# read the secret
sm = session.client("secretsmanager", region_name="us-west-2")
resp = sm.get_secret_value(SecretId="<SECRET_NAME>")
print(f"Secret: {resp['SecretString']}")
Resource reference (replace with your own values)¶
| Item | Placeholder |
|---|---|
| CN Account ID | <CN_ACCOUNT_ID> |
| Commercial Account ID | <COM_ACCOUNT_ID> |
| Secret ARN | arn:aws:secretsmanager:us-west-2:<COM_ACCOUNT_ID>:secret:<SECRET_NAME> |
| IAM Role ARN | arn:aws:iam::<COM_ACCOUNT_ID>:role/<ROLE_NAME> |
| Trust Anchor ARN | arn:aws:rolesanywhere:us-west-2:<COM_ACCOUNT_ID>:trust-anchor/<TA_ID> |
| Profile ARN | arn:aws:rolesanywhere:us-west-2:<COM_ACCOUNT_ID>:profile/<PROFILE_ID> |
| EC2 Instance | cn-north-1, Ubuntu 24.04 with public IP |
Troubleshooting / gotchas¶
-
CreateTrustAnchor
Incorrect basic constraints for CA certificate– Root CA cert 必须包含basicConstraints=critical,CA:TRUE扩展。openssl req -x509 -subj ...默认不加这个扩展,必须用 config 文件指定v3_casection。 -
aws_signing_helper 下载 URL – 当前正确路径是
releases/1.8.1/X86_64/Linux/Amzn2023/aws_signing_helper。旧版本路径或随意拼的路径会返回 S3 AccessDenied XML。 -
unable to parse private key–credential_process以当前用户 (ubuntu) 运行。如果/etc/ira/client.keyowner 是 root:root mode 600,ubuntu 读不到就报这个错。需要chown ubuntu:ubuntu。