azurepowershellazure-storageazure-powershellsas-token

Generating SAS account token in powershell


"I generated a token using Azure and it’s working, but I need to create a correct script in PowerShell using the key. The stringToSign I generated is different from the one provided by Azure, and azcopy gives me a 403 Server failed to authenticate the request error. The base for the script is: https://learn.microsoft.com/en-us/rest/api/storageservices/create-account-sas https://learn.microsoft.com/en-us/rest/api/eventhub/generate-sas-token

# Azure Storage Account Details
$storageAccountName = "name"
$storageAccountKey = "key"
$baseUrl = "https://$storageAccountName.blob.core.windows.net"

# SAS Token parameters
$permissions = "rwdlacup"  # Read, write, delete, list, add, create, update, process
$serviceVersion = "2022-11-02"  # API version
$expiryDate = "2024-12-13T22:41:13Z"  # Token expiry
$startDate = "2024-12-13T14:41:13Z"   # Start time
$signedServices = "bqtf"  # Blob, Queue, Table, File
$signedResourceTypes = "sco"  # Service, Container, Object
$signedIP = ""             # No specific IP restriction
$signedProtocol = "https"  # Only HTTPS

# Create the string-to-sign
$stringToSign = "$storageAccountName\n$permissions\n$signedServices\n$signedResourceTypes\n$startDate\n$expiryDate\n$signedIP\n$signedProtocol\n$signedversion"

# Compute HMAC SHA-256
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Convert]::FromBase64String($storageAccountKey)
$sig = [Convert]::ToBase64String($hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($stringToSign)))

# Construct SAS token
$sasToken = "?sv=$serviceVersion&ss=$signedServices&srt=$signedResourceTypes&sp=$permissions&se=$expiryDate&st=$startDate&spr=https&sig=$sig"

# Full URL with SAS token
$fullUrl = "$baseUrl/$sasToken"

I tried different types of stringToSign, but the SAS token is still different and results in the same error. The SAS token generation is not matching, and I receive the 403 Server failed to authenticate the request error. I have tried using various stringToSign formats, but none have worked as expected.


Solution

  • Generating SAS account token in powershell

    If you are using 2022-11-02 REST API version your stringToSign should be constructed using the following logic:

    StringToSign = accountname + "\n" +  
        signedpermissions + "\n" +  
        signedservice + "\n" +  
        signedresourcetype + "\n" +  
        signedstart + "\n" +  
        signedexpiry + "\n" +  
        signedIP + "\n" +  
        signedProtocol + "\n" +  
        signedversion + "\n" +
        signedEncryptionScope + "\n"
    

    You can use the below script to generate account sas token using Powershell.

    Script:

    # Parameters
    $xMsDate = [System.DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
    $expiryInSeconds = 7200 # 2 hours validity
    
    $accountName = "xxx"
    $signedPermissions = "rwdlaciytfx"
    $signedService = "b"
    $signedResourceType = "sco"
    $signedStart = $xMsDate
    $signedExpiry = [System.DateTime]::UtcNow.AddSeconds($expiryInSeconds).ToString("yyyy-MM-ddTHH:mm:ssZ")
    $signedIP = "" # Optional
    $signedProtocol = "https"
    $signedVersion = "2022-11-02"
    $signedEncryptionScope = ""
    
    # Storage Account Key (Replace with your actual key)
    $accessKey = "xxxx"
    
    # Construct String-to-Sign
    $StringToSign = "{0}`n{1}`n{2}`n{3}`n{4}`n{5}`n{6}`n{7}`n{8}`n{9}`n" -f `
        $accountName, $signedPermissions, $signedService, $signedResourceType, `
        $signedStart, $signedExpiry, $signedIP, $signedProtocol, $signedVersion, $signedEncryptionScope
    
    # Decode the storage account key
    $keyBytes = [Convert]::FromBase64String($accessKey)
    
    # Convert String-to-Sign to bytes
    $SignatureBytes = [System.Text.Encoding]::UTF8.GetBytes($StringToSign)
    
    # Generate HMAC-SHA256 signature
    $hasher = New-Object System.Security.Cryptography.HMACSHA256
    $hasher.Key = $keyBytes
    $Signature = [Convert]::ToBase64String($hasher.ComputeHash($SignatureBytes))
    
    # Generate SAS Token
    $sasToken = "sv=$signedVersion&ss=$signedService&srt=$signedResourceType&sp=$signedPermissions&se=$signedExpiry&st=$signedStart&spr=$signedProtocol&sig=$([System.Web.HttpUtility]::UrlEncode($Signature))"
    
    # Output the SAS Token
    Write-Output $sasToken
    

    Output:

    sv=2022-11-02&ss=b&srt=sco&sp=rwdlaciytfx&se=2024-12-14T11:27:45Z&st=2024-12-14T09:27:45Z&spr=https&sig=redacted
    

    enter image description here

    Now, I verified the SAS token with blob URL to fetch the image from the Azure blob storage.

    API request:

    enter image description here

    Reference:

    Create an account SAS - Azure Storage | Microsoft Learn