AWS IAM CreatePolicy API请求签名不匹配问题排查求助
AWS IAM CreatePolicy API 签名不匹配问题(含URL编码策略文档时)
问题背景
调用AWS IAM的CreatePolicy API创建策略时:
- 直接将JSON格式的PolicyDocument作为查询字符串参数传递,返回400 Bad Request错误。
- 在Postman中对PolicyDocument进行URL编码后,无论是放在查询参数还是
application/x-www-form-urlencoded格式的请求体中,均能正常调用;但自定义HTTP客户端采用同样方式时,返回签名不匹配错误:"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details"
- 自定义客户端对其他IAM GET类API均能正常工作,仅在传递编码后的PolicyDocument时失败。
核心原因
AWS签名版本4的计算要求请求的所有组件(查询参数、请求体等)的编码状态与签名计算时的内容完全一致,自定义客户端通常在编码处理或签名计算环节出现以下问题:
- 编码规则不符合AWS要求(误用
application/x-www-form-urlencoded规则而非RFC 3986标准); - 存在双重编码(手动编码后客户端自动再次编码);
- 签名计算时未使用最终发送的编码后内容(比如查询参数或请求体的内容与签名计算时的不一致)。
解决方案
1. 严格遵循RFC 3986编码规则处理PolicyDocument
AWS要求对PolicyDocument采用RFC 3986标准编码,而非application/x-www-form-urlencoded的规则:
- 保留字符(如
:、/、=)和非保留字符外的所有字符都需编码; - 空格需编码为
%20而非+; - 示例:原始JSON
编码后应为:{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::my-bucket" }] }%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%22s3%3AListBucket%22%2C%22Resource%22%3A%22arn%3Aaws%3As3%3A%3A%3Amy-bucket%22%7D%5D%7D
2. 避免双重编码
关闭自定义HTTP客户端的自动编码功能,确保仅手动编码一次PolicyDocument后直接传递:
- 如果是查询参数:手动编码后直接拼接在URL中,禁止客户端再次编码;
- 如果是请求体:将编码后的字符串作为
application/x-www-form-urlencoded的内容(格式为PolicyDocument=编码后的内容),确保请求体内容无额外修改。
3. 确保签名计算与实际请求内容一致
按照AWS签名版本4的流程,验证以下环节:
- 规范请求构建:确保HTTP方法(POST)、URI(
/)、查询字符串(编码后的完整参数)、请求头(包括Content-Type)、请求体哈希均与实际发送的内容完全一致; - 签名密钥生成:使用正确的Secret Access Key、请求日期、区域(如
us-east-1)、服务名称(iam)生成签名密钥; - 签名计算:确保签名时使用的查询参数或请求体内容,与最终发送到AWS的内容完全相同。
4. 优先使用请求体传递(推荐)
相较于查询参数,将编码后的PolicyDocument放在application/x-www-form-urlencoded格式的请求体中,更易避免URL长度限制和编码冲突,需注意:
- 请求头必须设置
Content-Type: application/x-www-form-urlencoded; - 请求体内容为
PolicyDocument=编码后的JSON字符串,无多余空格或换行; - 签名计算时需将请求体内容纳入签名范围(AWS签名版本4对POST请求的请求体哈希计算要求)。
内容的提问来源于stack exchange,提问作者Sumit Patil
相关产品推荐
相关产品推荐

