简体   繁体   中英

Authentication errors using Azure blob storage and Azure CDN

I'm having intermittent 403 errors trying to access a blob storage, via Azure CDN, with the symmetric access key. It seems that sometimes there's a header added for "Range", in the format of "bytes=xxx". The full error message is below:

{'Date': 'Mon, 12 Dec 2022 13:07:40 GMT', 'Content-Type': 'application/xml', 'Content-Length': '697', 'Connection': 'keep-alive', 'x-ms-request-id': '3f89c2c1-e01e-0050-132a-0eeb42000000', 'x-ms-error-code': 'AuthenticationFailed', 'x-azure-ref': '20221212T130740Z-6rfkrgx8qt0shbtz3x46rwnhrn0000000630000000002ayd', 'X-Cache': 'TCP_MISS'}
<?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:3f89c2c1-e01e-0050-132a-0eeb42000000
Time:2022-12-12T13:07:40.7638741Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'xxxxxx=' is not the same as any computed signature. Server used following string to sign: 'GET












bytes=0-8388607
x-ms-date:Mon, 12 Dec 2022 13:07:36 GMT
x-ms-version:2020-04-08
/deviceimage2zgjscikl7kny/images/data-prod-1.1.packer'.</AuthenticationErrorDetail></Error>

I was able to reproduce the error by generating the MAC signature in Python, but I saw it originally using the Go SDK and az CLI.

We added a rule at the CDN to Bypass caching, and it seems to have improved the situation (problem happens less frequently), but we are still seeing it on occasion.

Has anyone else experienced this? And is there a workaround?

Trying to access a blob storage with an access key, via Azure CDN

I tried in my environment and got below results:

Initially, I got a same when I tried to access blob storage with CDN using Postman.

Postman:

在此处输入图像描述

The above error states that signature and date is incorrect. So, we can't pass directly storage access key. You need to create a signature string that represents the given request, sign the string with the HMAC-SHA256 algorithm (using your storage key to sign), and encode the result in base 64 .

For creating signature, I used below .NET code:

using System.Globalization;
using System.Net;
using System.Security.Cryptography;

class Program
{
    static void Main(string[] args)
    {
        ListBlobs();
        Console.WriteLine("done");
        Console.ReadLine();
    }

    static void ListBlobs()
    {
        string Account = "venkat123";
        string Key = "<Storage account key>";
        string Container = "test";
        string apiversion = "2021-06-08";

        DateTime dt = DateTime.UtcNow;
        string StringToSign = String.Format("GET\n"
            + "\n" // content encoding
            + "\n" // content language
            + "\n" // content length
            + "\n" // content md5
            + "\n" // content type
            + "\n" // date
            + "\n" // if modified since
            + "\n" // if match
            + "\n" // if none match
            + "\n" // if unmodified since
            + "\n" // range
            + "x-ms-date:" + dt.ToString("R") + "\nx-ms-version:" + apiversion + "\n" // headers
            + "/{0}/{1}\ncomp:list\nrestype:container", Account, Container);

        string auth = SignThis(StringToSign, Key, Account);

        Console.WriteLine($"the date is: {dt.ToString("R")}");
        Console.WriteLine($"the auth token is: {auth}");
        Console.WriteLine("*********");
        string method = "GET";
        string urlPath = string.Format("https://{0}.blob.core.windows.net/{1}?restype=container&comp=list", Account, Container);
        Uri uri = new Uri(urlPath);
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.Method = method;
        request.Headers.Add("x-ms-date", dt.ToString("R"));
        request.Headers.Add("x-ms-version", apiversion);
        request.Headers.Add("Authorization", auth);

        Console.WriteLine("***list all the blobs in the specified container, in xml format***");
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {

            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                Console.WriteLine(reader.ReadToEnd());
            }
        }
    }


    private static String SignThis(String StringToSign, string Key, string Account)
    {
        String signature = string.Empty;
        byte[] unicodeKey = Convert.FromBase64String(Key);
        using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
        {
            Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
            signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
        }

        String authorizationHeader = String.Format(
              CultureInfo.InvariantCulture,
              "{0} {1}:{2}",
              "SharedKey",
              Account,
              signature);

        return authorizationHeader;
    }
}

Console:

在此处输入图像描述

Above executed code, date and signature which I copied and used in postman, and it worked successfully.

Postman: 在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM