Kid_Learning_C
Kid_Learning_C

Reputation: 3631

Azure function gets AuthorizationFailure when trying to GET a file in Azure Blob Storage that is not public

In my Azure function, I am trying to download a file from Blob Storage named myappbackendfiles.

Code (utils/Azure/blobServiceClient.ts) that initiates the BlobServiceClient:

import { BlobServiceClient } from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";

const account = "myappbackendfiles";
export const blobServiceClient = new BlobServiceClient(
  `https://${account}.blob.core.windows.net`,
  new DefaultAzureCredential()
);

Code that uses the BlobServiceClient

import { blobServiceClient } from "../utils/Azure/blobServiceClient";

...

    // Create BlobServiceClient
    const containerClient = blobServiceClient.getContainerClient(containerName);
    const blockBlobClient = containerClient.getBlockBlobClient(blobName);

    // Stream the blob to a local file
    const downloadBlockBlobResponse = await blockBlobClient.download(0);
    const blobReadableStream = downloadBlockBlobResponse.readableStreamBody;

    if (blobReadableStream) {
      const writableStream = fs.createWriteStream(localFilePath);
      blobReadableStream.pipe(writableStream);
    }

However, when I test the function in azure function app, I got this error; and as you can see, it is trying to GET the file https://myappbackendfiles.blob.core.windows.net/issues/src-A/dst-B/2023-08-15-01-52/c1diouasdfhia1231/testFile.zip

{
   "name": "RestError",
   "code": "AuthorizationFailure",
   "statusCode": 403,
   "request": {
      "streamResponseStatusCodes": {},
      "url": "https://myappbackendfiles.blob.core.windows.net/issues/src-A/dst-B/2023-08-15-01-52/c1diouasdfhia1231/testFile.zip",
      "method": "GET",
      "headers": {
         "_headersMap": {
            "x-ms-version": "REDACTED",
            "accept": "application/xml",
            "user-agent": "azsdk-js-storageblob/12.15.0 (NODE-VERSION v18.16.1; Linux 5.10.177.1-1.cm1)",
            "x-ms-client-request-id": "cca1e0cc-b8f3-49f7-8d50-5de520714f96",
            "x-ms-date": "REDACTED",
            "authorization": "REDACTED"
         }
      },
      "withCredentials": false,
      "timeout": 0,
      "keepAlive": true,
      "decompressResponse": false,
      "requestId": "cca1e0cc-b8f3-49f7-8d50-5de520714f96"
   },
   "details": {
      "errorCode": "AuthorizationFailure",
      "access-control-allow-origin": "*",
      "access-control-expose-headers": "x-ms-request-id,x-ms-client-request-id,x-ms-error-code,Content-Length,Date,Transfer-Encoding",
      "content-length": "246",
      "content-type": "application/xml",
      "date": "Wed, 16 Aug 2023 08:18:07 GMT",
      "server": "Microsoft-HTTPAPI/2.0",
      "x-ms-client-request-id": "cca1e0cc-b8f3-49f7-8d50-5de520714f96",
      "x-ms-request-id": "11d56133-501e-001b-0d1a-d0c60f000000",
      "message": "This request is not authorized to perform this operation.\nRequestId:11d56133-501e-001b-0d1a-d0c60f000000\nTime:2023-08-16T08:18:08.0305733Z",
      "code": "AuthorizationFailure"
   },
   "message": "This request is not authorized to perform this operation.\nRequestId:11d56133-501e-001b-0d1a-d0c60f000000\nTime:2023-08-16T08:18:08.0305733Z"
}

I have done steps that have been suggested by people:

I have set the storage account networks to "Enabled from selected virtual networks and IP addresses". I do not want to enable from all networks since the data is private.

Below are the outbouding IP addresses of the function app: enter image description here

And I have added these IP addresses to the "white list": enter image description here

However, I am getting the error above.

Now I found out that as soon as I change the Public network access to "Enabled from all networks": enter image description here

The error is fixed! There is no "AuthorizationFailure" anymore.

However, obviously I cannot keep it as "Enabled from all networks". The private data will leak...

What can I do ? I must be missing something very basic.

Any suggestions?

Upvotes: 1

Views: 2083

Answers (1)

Dasari Kamali
Dasari Kamali

Reputation: 3649

Firstly, I uploaded a blob in my storage account container at Azure Portal like below,

enter image description here

Assigned Storage Blob Data Contributor role to my function app,

enter image description here

Then, I changed the Networking access to Enabled from selected virtual networks and IP addresses in Azure Storage as shown below,

enter image description here

I tried below typescript code to download a blob from my storage account container.

Code:

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { BlobServiceClient } from "@azure/storage-blob";

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    const containerName = "<container_name>"; 
    const blobName = "<blob_name>"; 

    try {
        const connectionString = process.env["AZURE_STORAGE_CONNECTION_STRING"];
        if (!connectionString) {
            throw Error("Azure Storage connection string not found in configuration");
        }

        const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString);

        const containerClient = blobServiceClient.getContainerClient(containerName);
        const blockBlobClient = containerClient.getBlockBlobClient(blobName);

        const blobDownloadResponse = await blockBlobClient.download(0);
        const blobReadableStream = blobDownloadResponse.readableStreamBody;

        const headers = {
            "Content-Type": "text/plain", 
            "Content-Disposition": `attachment; filename="${blobName}"`,
        };

        context.res = {
            status: 200, 
            body: "Blob downloaded successfully!", 
            headers: headers,
        };
    } catch (error) {
        context.log.error("An error occurred:", error);
        context.res = {
            status: 500,
            body: "Internal Server Error",
        };
    }
};

export default httpTrigger;

.env :

I added the storage account connection string to the .env file like below,

AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=<account_name>;AccountKey=<account_key>;EndpointSuffix=core.windows.net"

Output:

It runs successfully as below,

enter image description here

With the above URL, the blob downloaded successfully in the browser like below,

enter image description here

Then, I deployed this code to my function app and it deployed successfully as below,

enter image description here

I have set the storage account connection string in Configuration section in the function app,

enter image description here

I run this function in function app at Azure portal and it runs successfully as below,

enter image description here

Upvotes: 0

Related Questions