'trouble with aws, powershell and the Signature
i want to play with the Amazon Selling Partner API. From Postman everything works fine. From Powershell not.
I tried to derive my powershell script from the documentation https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html and the python example.
I try it all the day, but i do not find the solution.
What i have done:
- Test functionality from Postman -> Works
- Read about Signing AWS requests with Signature Version 4 -> OK
- Understanding signing key functionality with the test input from https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html -> Works
- Try to translate the Python example to Powershell: https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html -> does not work
- Use Google to find a solution from examples and found this: http://www.laurierhodes.info/?q=node/114 -> does not work - maybe because it is for aws lambda
Whatever i do, i receive error Message Sender SignatureDoesNotMatch
I attached a screenshot from Postman, it shows the response from this endpoint. I know it is "Access denied", it is just really near on the example from amazon. Later on i need to make a sts request to receive temp credentials on each call and i also need to sign every call to the amazon selling partner API.
Maybe someone can help me, please? I'm going nuts :D
Here is my Powershell code from the python example: https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
I tried both get variants,
- Using GET with an authorization header (Python)
- Using GET with authentication information in the Query string (Python)
This code is from the 2nd -> Using GET with authentication information in the Query string
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
[cultureinfo]::CurrentCulture = 'de-DE'
#powershell variant with example test input from #https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html
<#
.Synopsis
HMACSHA256 signing function used in the construction of a "Signature 4 " request
#>
# translated function from Deriving a signing key using .NET (C#)
function hmacSHA256(
[string]$data,
[byte[]]$key)
{
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = $key
$signature = $hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($data))
return $signature
}
<#
.Synopsis
The AWS Signature version 4 creation routine
#>
function getSignatureKey(
[String]$AWSAccessKey,
[String]$dateStamp,
[String]$regionName,
[String]$serviceName)
{
[Byte[]]$kSecret = [System.Text.Encoding]::UTF8.GetBytes("AWS4" + $AWSAccessKey)
$kDate = hmacSHA256 -data $dateStamp -key $kSecret
$kRegion = hmacSHA256 -data $regionName -key $kDate
$kService = hmacSHA256 -data $serviceName -key $kRegion
$kSigningKey = hmacSHA256 -data "aws4_request" -key $kService
return $kSigningKey
}
<#
.Synopsis
Retrieves an SHA hash of a string as required by AWS Signature 4
#>
function hash($request) {
$sha256 = new-object -TypeName System.Security.Cryptography.SHA256Managed
$utf8 = new-object -TypeName System.Text.UTF8Encoding
$hash = [System.BitConverter]::ToString($sha256.ComputeHash($utf8.GetBytes($request)))
return $hash.replace('-','').toLower()
}
# ************* REQUEST VALUES *************
$method = 'GET'
$service = 'iam'
$host1 = 'iam.amazonaws.com'
$region = 'us-east-1'
$endpoint = 'https://iam.amazonaws.com'
$access_key = 'AKIA4KA7FVL7SN2EXAMPLE'
$secret_key = 'EXPL[enter image description here][1]Y59hS5KWKAnfOSnWLjNsiKaK/EXAMPLE'
$now = [DateTime]::UtcNow
$amz_date = $now.ToString('yyyyMMddTHHmmssZ')
$datestamp = $now.ToString('yyyyMMdd')
# ************* TASK 1: CREATE A CANONICAL REQUEST *************
# http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
# Step 2: Create canonical URI--the part of the URI from domain to query
# string (use '/' if no path)
$canonical_uri = '/'
# Step 3: Create the canonical headers and signed headers. Header names
# must be trimmed and lowercase, and sorted in code point order from
# low to high. Note trailing \n in canonical_headers.
# signed_headers is the list of headers that are being included
# as part of the signing process. For requests that use query strings,
# only "host" is included in the signed headers.
$canonical_headers = "host:" + $host1 + "`n"
$signed_headers = "host"
# Match the algorithm to the hashing algorithm you use, either SHA-1 or
# SHA-256 (recommended)
$algorithm = 'AWS4-HMAC-SHA256'
$credential_scope = $datestamp + '/' + $region + '/' + $service + '/' + 'aws4_request'
# Step 4: Create the canonical query string. In this example, request
# parameters are in the query string. Query string values must
# be URL-encoded (space=%20). The parameters must be sorted by name.
$canonical_querystring = "Action=CreateUser&UserName=NewUser&Version=2010-05-08"
$canonical_querystring += "&X-Amz-Algorithm=AWS4-HMAC-SHA256 `n"
$canonical_querystring += "&X-Amz-Credential=" + [uri]::EscapeDataString(($access_key + "/" + $credential_scope))
$canonical_querystring += "&X-Amz-Date=" + $amz_date
$canonical_querystring += "&X-Amz-Expires=30"
$canonical_querystring += "&X-Amz-SignedHeaders=" + $signed_headers
# Step 5: Create payload hash. For GET requests, the payload is an
# empty string ("").
$payload_hash = hash ''
# Step 6: Combine elements to create canonical request
$canonical_request = $method + "`n" +
$canonical_uri + "`n" +
$canonical_querystring + "`n" +
$canonical_headers + "`n" +
$signed_headers + "`n" +
$payload_hash
#$canonical_request_hash = hash -request $canonical_request
#write-host $canonical_request_hash
# *************************************************************#
# ************* TASK 2: CREATE THE STRING TO SIGN *************#
$string_to_sign = $algorithm + "`n" +
$amz_date + "`n" +
$credential_scope + "`n" +
$canonical_request_hash
# *************************************************************#
# ************* TASK 3: CALCULATE THE SIGNATURE ***************#
# Create the signing key
$signing_key = getSignatureKey($secret_key, $datestamp, $region, $service)
#write-host "signing-key: $($signing_key)"
# Sign the string_to_sign using the signing_key
$signature = HmacSHA256 -data $string_to_sign -key $signing_key
$signature = [System.BitConverter]::ToString($signature).Replace('-','').ToLower()
# ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
# The auth information can be either in a query string
# value or in a header named Authorization. This code shows how to put
# everything into a query string.
$canonical_querystring += '&X-Amz-Signature=' + $signature
# ************* SEND THE REQUEST *************
# The 'host' header is added automatically by the Python 'request' lib. But it
# must exist as a header in the request.
###
#I am not sure how to work with headers, because i used the Get Variant with authentication information in the Query string
####
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("authorization", "AWS4-HMAC-SHA256 Credential=$($AWSAccessID)/$($shortdate)/$($AWSRegion)/$($AWSService)/aws4_request, SignedHeaders=$($SignedHeadersList), Signature=$($signature)")
$request_url = $endpoint + "/?" + $canonical_querystring
Invoke-RestMethod $request_url -Method 'GET' -Headers $headers
Best regards and many many thanks Patrick
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
