I have following pwsh7 script and have no other idea, why the Azure Blob REST API refuse to authenticate. I know there is an Entra ID Oauth2 or SAS scheme but I need to make a prove that an integrated third party software that supports only keys will be able to authenticate.
I checked the value of $StringToSign and returned xml error
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:9300092d-b01e-0070-71fb-0f5492000000
Time:2024-09-26T10:01:29.7869247Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request '72Lz/EdHuzzi57gC4JAKW1oFWz8SnU1JW4lq5+LLajA=' is not the same as any computed signature. Server used following string to sign: 'GET
x-ms-date:Thu, 26 Sep 2024 09:56:58 GMT
x-ms-version:2020-10-02
/presofalogs/pre-sofa-logs
comp:list
restype:container'.</AuthenticationErrorDetail
The script I checked againts the docs [https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key] and didn't find any discrepancies.
# Variables
$StorageAccountName = "mysa"
$StorageAccountKey = "mykey"
$ContainerName = "mycontainer"
$StorageUrl = "https://${StorageAccountName}.blob.core.windows.net/${ContainerName}?restype=container&comp=list"
$DateUtc = (Get-Date).ToUniversalTime().ToString("R")
$Verb = "GET"
$Version = "2020-10-02"
#$OpenSSLPath = "c:\Program Files\OpenSSL-Win64\bin"
$OpenSSLPath = "c:\Program Files\OpenSSL-Win64-1.1\bin"
$env:PATH = "$OpenSSLPath;$env:PATH"
# Build the String-to-Sign with LF (`\n`) line endings explicitly
# https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key
$StringToSign = $Verb + "`n" +
"`n" + # Content-Encoding (empty)
"`n" + # Content-Language (empty)
"`n" + # Content-Length (empty)
"`n" + # Content-MD5 (empty)
"`n" + # Content-Type (empty)
"`n" + # Date (empty, because we're using x-ms-date)
"`n" + # If-Modified-Since (empty)
"`n" + # If-Match (empty)
"`n" + # If-None-Match (empty)
"`n" + # If-Unmodified-Since (empty)
"`n" + # Range (empty)
"x-ms-date:$DateUtc`n" + # Custom header
"x-ms-version:$Version`n" + # Custom header
"/$StorageAccountName/$ContainerName`n" + # Canonicalized resource
"comp:list`n" + # Query parameter in alphabetical order
"restype:container" # Query parameter in alphabetical order
$StringToSign | Out-File -FilePath sts.txt -NoNewline
# Create a temporary file for the binary storage account key
$TempKeyFile = [System.IO.Path]::GetTempFileName()
# Decode the base64-encoded storage account key and save it as binary to the temporary file
[IO.File]::WriteAllBytes($TempKeyFile, [Convert]::FromBase64String($StorageAccountKey))
# Create the HMAC signature using OpenSSL with the binary key stored in the temporary file
# Use a here-string to pass $StringToSign as input via stdin to openssl
$StringToSignBytes = [System.Text.Encoding]::UTF8.GetBytes($StringToSign)
$Signature = $StringToSignBytes | & openssl dgst -sha256 -binary -mac HMAC -macopt "key:file:$TempKeyFile" | base64
# Remove the temporary file securely
Remove-Item $TempKeyFile
# Output the signature for debugging
Write-Host "Signature: $Signature"
# Prepare the curl request
$Headers = [Ordered]@{
"x-ms-date" = $DateUtc
"x-ms-version" = $Version
"Authorization" = "SharedKey ${StorageAccountName}:${Signature}"
}
# Execute the request to list the blobs in the container
# Used -Proxy 'http://localhost:8888' for inspecting via a Fiddler
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
Invoke-RestMethod -Method $Verb -Uri $StorageUrl -Headers $Headers -Proxy 'http://localhost:8888'
Fiddler showed other request headers that shouldn't break the signature.
GET https://mysa.blob.core.windows.net/mycontainer?restype=container&comp=list HTTP/1.1
Host: mysa.blob.core.windows.net
x-ms-date: Thu, 26 Sep 2024 09:56:58 GMT
x-ms-version: 2020-10-02
Authorization: SharedKey mysa:72Lz/EdHuzzi57gC4JAKW1oFWz8SnU1JW4lq5+LLajA=
User-Agent: Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.19045; cs-CZ) PowerShell/7.4.5
Accept-Encoding: gzip, deflate, br