Reputation: 3631
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 turned on the System Assigned Managed Identity for this function app;
I have assigned to my Function app the needed roles on the resource myappbackendfiles
; see the below screenshot. I believe I have done quite some overkill in this regard:
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:
And I have added these IP addresses to the "white list":
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":
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
Reputation: 3649
Firstly, I uploaded a blob in my storage account container at Azure Portal like below,
Assigned Storage Blob Data Contributor role to my function app,
Then, I changed the Networking access to Enabled from selected virtual networks and IP addresses in Azure Storage as shown below,
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,
With the above URL, the blob downloaded successfully in the browser like below,
Then, I deployed this code to my function app and it deployed successfully as below,
I have set the storage account connection string in Configuration section in the function app,
I run this function in function app at Azure portal and it runs successfully as below,
Upvotes: 0