amazon-web-services - 如何在不安装 AWS SDK 的情况下通过 Powershell 从 S3 下载文件?
问题描述
我想使用 Windows Powershell 从我的 AWS S3 存储桶下载文件。我无法安装任何 AWS 软件,需要创建 API 才能访问 AWS S3 中的文件。我使用 Postman 测试该文件是否可访问并且成功。
鉴于这一成功,我尝试遵循 AWS 的指南,该指南说我需要创建以下内容:
- 创建规范请求。
- 使用规范请求和其他元数据创建用于签名的字符串。
- 从您的 AWS 秘密访问密钥派生签名密钥。然后使用签名密钥和上一步中的字符串来创建签名。
- 将生成的签名添加到标头中的 HTTP 请求或作为查询字符串参数。
我见过的最接近的是 Abhaya 的https://forums.aws.amazon.com/thread.jspa?threadID=251722中的这个例子,但它也没有解决。(此示例中的有效负载哈希是空白的有效负载哈希)。我已经阅读了几个 AWS 指南,但是在尝试将它们应用于 powershell 时,这些指南非常令人困惑。https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
下面代码的 url 生成一个看起来正确的 url:http://SAMPLEBUCKETNAME HERE.s3-ap-southeast-1.amazonaws.com/test.xlsx?&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential =%2F20190907%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20190907T1644136560000Z&X-Amz-E0&X-Amz-SignedHeaders=host&X-Amz-Signature=HASH HERE
$method = 'GET'
$service = 's3'
$host1 = 'SAMPLES3BUCKETNAME.s3-ap-southeast-1.amazonaws.com'
$region = 'ap-southeast-1'
$endpoint = 'http://SAMPLES3BUCKETNAME.s3-ap-southeast-1.amazonaws.com/test.xlsx'
function HmacSHA256($message, $secret){
<#$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::UTF8.GetBytes($secret)
#$hmacsha.key = $secret
$signature = $hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
#>
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.Key = @($secret -split '(?<=\G..)(?=.)'|ForEach-Object {[byte]::Parse($_,'HexNumber')})
$sign = [BitConverter]::ToString($hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($message))).Replace('-','').ToLower()
return $sign
}
function getSignatureKey($key, $dateStamp, $regionName, $serviceName)
{
$kSecret = [Text.Encoding]::UTF8.GetBytes(("AWS4" + $key).toCharArray())
$kDate = HmacSHA256 $dateStamp $kSecret;
$kRegion = HmacSHA256 $regionName $kDate ;
$kService = HmacSHA256 $serviceName $kRegion ;
$kSigning = HmacSHA256 "aws4_request" $kService ;
return $kSigning;
}
$access_key = 'SAMPLEACCESSKEY'
$secret_key = 'SAMPLESECRETKEY'
$amz_date = [DateTime]::UtcNow.ToString('yyyyMMddTHHmmssfffffffZ')
$datestamp = [DateTime]::UtcNow.ToString('yyyyMMdd')
$canonical_uri = '/'
$canonical_headers = 'host:' + $host1 + "`n"
$signed_headers = 'host'
$algorithm = 'AWS4-HMAC-SHA256'
$credential_scope = $datestamp + '/' + $region + '/' + $service + '/' + 'aws4_request'
$canonical_querystring = ''
$canonical_querystring += '&X-Amz-Algorithm=AWS4-HMAC-SHA256'
$canonical_querystring += '&X-Amz-Credential=' + [uri]::EscapeDataString(($access_key + '/' + $credential_scope))
$canonical_querystring += '&X-Amz-Date=' + $amz_date
$canonical_querystring += '&X-Amz-Expires=86400'
$canonical_querystring += '&X-Amz-SignedHeaders=' + $signed_headers
$payload_hash = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
$canonical_request1 = $method + "`n" +$canonical_uri + "`n" + $canonical_querystring + "`n" + $canonical_headers + "`n" + $signed_headers + "`n" + $payload_hash
Write-Host $canonical_request1
function hash($request) {
$hasher = [System.Security.Cryptography.SHA256]::Create()
$content = [Text.Encoding]::UTF8.GetBytes($request)
$hash = [System.Convert]::ToBase64String($hasher.ComputeHash($content))
return $hash
}
$canonical_request = hash -request $canonical_request1
$string_to_sign = $algorithm + "`n" + $amz_date + "`n" + $credential_scope + "`n" + $canonical_request
$signing_key = getSignatureKey $secret_key $datestamp $region $service
$signature = HmacSHA256 -secret $signing_key -message $string_to_sign
$canonical_querystring += '&X-Amz-Signature=' + $signature
$request_url = $endpoint + "?" + $canonical_querystring
$request_url
解决方案
有一些错误,特别是您如何计算签名、构建时间戳,而您看到的错误是因为参数没有正确传递。
这是纠正这些问题的版本:
$method = 'GET'
$service = 's3'
$bucket = "SAMPLES3BUCKETNAME"
$key = 'test.xlsx'
$region = 'ap-southeast-1'
$host1 = $bucket + '.s3-' + $region + '.amazonaws.com'
$access_key = 'SAMPLEACCESSKEY'
$secret_key = 'SAMPLESECRETKEY'
function HmacSHA256($message, $secret)
{
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = $secret
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
return $signature
}
function getSignatureKey($key, $dateStamp, $regionName, $serviceName)
{
$kSecret = [Text.Encoding]::UTF8.GetBytes(("AWS4" + $key).toCharArray())
$kDate = HmacSHA256 $dateStamp $kSecret;
$kRegion = HmacSHA256 $regionName $kDate;
$kService = HmacSHA256 $serviceName $kRegion;
$kSigning = HmacSHA256 "aws4_request" $kService;
return $kSigning
}
function hash($request)
{
$hasher = [System.Security.Cryptography.SHA256]::Create()
$content = [Text.Encoding]::UTF8.GetBytes($request)
$bytes = $hasher.ComputeHash($content)
return ($bytes|ForEach-Object ToString x2) -join ''
}
$now = [DateTime]::UtcNow
$amz_date = $now.ToString('yyyyMMddTHHmmssZ')
$datestamp = $now.ToString('yyyyMMdd')
$signed_headers = 'host'
$credential_scope = $datestamp + '/' + $region + '/' + $service + '/' + 'aws4_request'
$canonical_querystring = 'X-Amz-Algorithm=AWS4-HMAC-SHA256'
$canonical_querystring += '&X-Amz-Credential=' + [uri]::EscapeDataString(($access_key + '/' + $credential_scope))
$canonical_querystring += '&X-Amz-Date=' + $amz_date
$canonical_querystring += '&X-Amz-Expires=86400'
$canonical_querystring += '&X-Amz-SignedHeaders=' + $signed_headers
$canonical_headers = 'host:' + $host1 + "`n"
$canonical_request = $method + "`n"
$canonical_request += "/" + $key + "`n"
$canonical_request += $canonical_querystring + "`n"
$canonical_request += $canonical_headers + "`n"
$canonical_request += $signed_headers + "`n"
$canonical_request += "UNSIGNED-PAYLOAD"
$algorithm = 'AWS4-HMAC-SHA256'
$canonical_request_hash = hash -request $canonical_request
$string_to_sign = $algorithm + "`n"
$string_to_sign += $amz_date + "`n"
$string_to_sign += $credential_scope + "`n"
$string_to_sign += $canonical_request_hash
$signing_key = getSignatureKey $secret_key $datestamp $region $service
$signature = HmacSHA256 -secret $signing_key -message $string_to_sign
$signature = ($signature|ForEach-Object ToString x2) -join ''
$canonical_querystring += '&X-Amz-Signature=' + $signature
$request_url = "http://" + $host1 + "/" + $key + "?" + $canonical_querystring
Write-Host $request_url
推荐阅读
- php - 运行两个 mySql 查询以获取数据
- laravel - 基本 URL 是非 www 导致路由非 www
- python - 具有 Selenoid 设置所需功能的机器人框架
- sql - 基于每个组 [base1.col1, base2.col2] 的 table1 的 SQL 最新条目
- r - 使用索引数据为分面 geom_point 图定义 X 和 y 数据
- flutter - 未处理的异常:NoSuchMethodError:在 null 上调用了方法“调用”
- python - 如何在追加和读取模式下循环文件行时插入文本
- swift - 如何在 NSTextTable 中获取选定的文本块
- c# - 获取每个实体的最大值的简单查询
- amazon-web-services - CDK 部署失败并拒绝访问