0
votes

Here's my code to find Storage Containers:

var api = $"https://{storageAccountName}.blob.core.windows.net/?comp=list";
using (var client = new HttpClient())
{
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken); //token obtained from https://storage.azure.com/
    client.BaseAddress = new Uri($"https://{storageAccountName}.blob.core.windows.net/");
    using (var responseGet = client.GetAsync(api).Result)
    {
        if (responseGet.IsSuccessStatusCode)
        {
            var xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(responseGet.Content.ReadAsStringAsync().Result);
            foreach (XmlNode a in xmlDocument.DocumentElement.SelectNodes("Containers/Container"))
            {
                containerNameList.Add(a.SelectSingleNode("Name").FirstChild.Value);
            }
        }
    }
}

I got an error:

`StatusCode: 403, ReasonPhrase: 'Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.', Version: 1.1, Content:

System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers:
{
  Server: Windows-Azure-Blob/1.0
  Server: Microsoft-HTTPAPI/2.0
  x-ms-request-id: 9d70d7ff-901e-0096-4c5b-aec38d000000
  Date: Mon, 09 Dec 2019 06:38:16 GMT
  Content-Length: 438
  Content-Type: application/xml
}`

I obtained the access token from https://storage.azure.com/

And here's the code to remove the storage container:

var strApi = $"https://{storageAccountName}.blob.core.windows.net/{storageContainerName}?restype=container";
using (var client = new HttpClient())
{
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
    client.BaseAddress = new Uri(BaseManagementUri);
    using (var responseGet = client.DeleteAsync(strApi).Result)
    {
        if (responseGet.IsSuccessStatusCode)
        {
            log.LogInformation($"Deleted {storageAccountName}");
        }
        else
        {
            log.LogWarning($"Failed to deleted {storageAccountName}\n{responseGet.Content.ReadAsByteArrayAsync().Result}");
        }
    }
}

How to obtain the proper access token and what all headers required for the above operations ?

2
Why are you not using Storage SDK for .Net?Gaurav Mantri
I am creating an Azure Function and I would be trying to get the access token using MSI.Gour Gopal
@GourGopalg Do you have any other concerns?Jim Xu
The MSI method seems to be working! Thank you so much for your effort! Really helped me.Gour Gopal

2 Answers

1
votes

According to my research, we can use Azure Active Directory (AD) to authorize requests to Blob storage. For more details, please refer to the document

The detailed steps are as below.

  1. Create a service principal and assign Storage Blob Data Contributor role to the sp. You can refer to the article to know more details about how to do it.
az ad sp create-for-rbac --name "" --scope <"/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"> --role "Storage Blob Data Contributor"
  1. Get Azure AD access token
URL : https://login.microsoftonline.com/{tenant}/v2.0/token
Method : POST
Headers : Content-Type: application/x-www-form-urlencoded
Body :
       "grant_type" : "client_credentials"
       "scope" : "https://storage.azure.com/.default"
       "client_id" : "<your sp app id>"
       "client_secret" : "<your sp password>"

enter image description here

  1. Call Azure Blob rest api
    • list containers
URL: https://myaccount.blob.core.windows.net/?comp=list
Method: Get
Headers:
         x-ms-version : 2019-02-02
         Authorization: Bearer <access token>

enter image description here

  • delete container
URL: https://myaccount.blob.core.windows.net/mycontainer?restype=container  
Method : DELETE
Headers:
         x-ms-version : 2019-02-02
         Authorization: Bearer <access token>

enter image description here

Besides, if you want to do that with Azure MSI, please refer to the blog


Update

Regarding how to call Azure storage rest api with MSI in Azure function, please refer to the following steps. 1. Adding a system-assigned identity

  1. Assign the Storage Blob Data Contributor role to MSI enter image description here

  2. Code

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Xml.Linq;
using Microsoft.Azure.Services.AppAuthentication;
using RestSharp;
using System.Text;

namespace TestFunV2
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var tokenProvider = new AzureServiceTokenProvider();
            var accesstoken = await tokenProvider.GetAccessTokenAsync("https://storage.azure.com/");

            var client = new RestClient("https://hurystorage.blob.core.windows.net/?comp=list");
            var request = new RestRequest(Method.GET);

            request.AddHeader("Authorization", "Bearer " + accesstoken);
            request.AddHeader("x-ms-version", "2019-02-02");
            IRestResponse response = await client.ExecuteTaskAsync(request);

            if (response.IsSuccessful) {
                var xmlstring = response.Content;
                string _byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
                if (xmlstring.StartsWith(_byteOrderMarkUtf8))
                {
                    xmlstring = xmlstring.Remove(0, _byteOrderMarkUtf8.Length);
                }
                XElement x = XElement.Parse(xmlstring);
                foreach (XElement container in x.Element("Containers").Elements("Container"))
                {
                    log.LogInformation("Container name = {0}", container.Element("Name").Value);

                }
                return (ActionResult)new OkObjectResult("ok");
            }
            return new BadRequestObjectResult("failure");


        }
    }
}

enter image description here

-1
votes

Maybe this video helps you, it´s how can delete one or all containers, search with a prefix and delete, and you can download the code in the description.

 foreach (var container in blobClient.ListContainers("PREFIJO_A_COINCIDIR")) // Por cada contenedor en la lista con búsqueda "Prejifo_a_coincidir" hace lo siguiente
            {
                await Task.Delay(500);
                if (container.Properties.LeaseState == LeaseState.Leased)
                {
                    await container.BreakLeaseAsync(null);
                }
                await container.DeleteAsync();
                await Task.Delay(500);
               
            }

enter code here

You could put a texbox binding to the prefix and create special search.

https://www.youtube.com/watch?v=sUwLZ1FP2Qk

Link video