使用Curl上传数据至AWS S3出错,求解决方法及示例代码
解决Curl上传AWS S3的签名及加密问题
核心问题分析
你的脚本使用的是AWS Signature Version 2(SigV2),但目前AWS S3绝大多数区域已不再支持SigV2,强制要求使用Signature Version 4(SigV4),这是请求失败的主要原因。另外如果你的S3桶启用了KMS默认加密,还需要在请求中添加对应的加密头。
修正方案及示例代码
以下是适配SigV4且支持KMS加密的完整Shell脚本:
#!/usr/bin/env bash set -eo pipefail # 配置参数 file_to_upload="/home/sraj/Hello10.txt" bucket="mybucket" # S3对象键:仅填桶内路径/文件名,不要带桶名或本地绝对路径 object_key="Hello10.txt" # 若桶启用KMS默认加密,填写KMS密钥ARN/别名;无需加密则注释此行 kms_key_id="arn:aws:kms:us-east-1:123456789012:key/xxxxxx" content_type="application/x-compressed-tar" region="us-east-1" # 替换为你的桶所在AWS区域 # 生成SigV4要求的UTC时间格式 date_now=$(date -u +"%Y%m%d") datetime_now=$(date -u +"%Y%m%dT%H%M%SZ") # 构建规范请求(SigV4核心步骤) canonical_request="PUT /${object_key} content-type:${content_type} host:${bucket}.s3.${region}.amazonaws.com x-amz-date:${datetime_now} x-amz-server-side-encryption:aws:kms x-amz-server-side-encryption-aws-kms-key-id:${kms_key_id} content-type;host;x-amz-date;x-amz-server-side-encryption;x-amz-server-side-encryption-aws-kms-key-id $(openssl dgst -sha256 -binary "${file_to_upload}" | base64)" # 构建待签字符串 string_to_sign="AWS4-HMAC-SHA256 ${datetime_now} ${date_now}/${region}/s3/aws4_request $(echo -n "${canonical_request}" | openssl dgst -sha256 -hex | awk '{print $2}')" # 生成SigV4签名密钥 signing_key=$(echo -n "AWS4${s3_secret_key}" | openssl dgst -sha256 -hmac "${date_now}" -binary | openssl dgst -sha256 -hmac "${region}" -binary | openssl dgst -sha256 -hmac "s3" -binary | openssl dgst -sha256 -hmac "aws4_request" -binary) signature=$(echo -n "${string_to_sign}" | openssl dgst -sha256 -hmac "${signing_key}" -binary | base64) # 执行Curl上传请求 curl -X PUT -T "${file_to_upload}" \ -H "Content-Type: ${content_type}" \ -H "Host: ${bucket}.s3.${region}.amazonaws.com" \ -H "X-Amz-Date: ${datetime_now}" \ -H "X-Amz-Server-Side-Encryption: aws:kms" \ -H "X-Amz-Server-Side-Encryption-AWS-KMS-Key-Id: ${kms_key_id}" \ -H "Authorization: AWS4-HMAC-SHA256 Credential=${s3_access_key}/${date_now}/${region}/s3/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-server-side-encryption;x-amz-server-side-encryption-aws-kms-key-id, Signature=${signature}" \ "https://${bucket}.s3.${region}.amazonaws.com/${object_key}"
关键修正点说明
- 切换至SigV4签名:完全重写了签名生成逻辑,符合AWS当前唯一支持的SigV4规范,解决了旧版本签名的兼容性问题。
- KMS加密适配:若桶启用SSE-KMS默认加密,必须添加
X-Amz-Server-Side-Encryption系列头;无需加密则直接删除相关代码块。 - 路径修正:原脚本错误地将本地绝对路径作为S3对象键,修正为仅包含桶内的目标路径/文件名。
- 区域指定:SigV4要求明确指定桶所在的AWS区域,需替换为你的实际区域(如
us-west-2、eu-central-1)。 - 时间格式:使用UTC标准时间格式,避免时区差异导致的签名验证失败。
额外注意事项
- 确保IAM用户拥有
s3:PutObject权限;若使用KMS,还需拥有对应密钥的kms:GenerateDataKey和kms:Decrypt权限。 - 不要硬编码密钥到脚本中,建议通过环境变量传递(如
export AWS_ACCESS_KEY_ID=xxx、export AWS_SECRET_ACCESS_KEY=yyy)。 - 若无需服务器端加密,删除所有与KMS相关的头和变量即可。
内容的提问来源于stack exchange,提问作者Sundar Raj
相关产品推荐
相关产品推荐

