How to connect Azure Table Storage using Managed Identity? - azure

string userAssignedClientId = "abcderfgh-1234-1234-b17b-12345678900";
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = userAssignedClientId });
var blobClient = new CloudTableClient(new Uri("https://myaccount.blob.core.windows.net/mycontainer/myblob"), Microsoft.Azure.Cosmos.Table.StorageCredentials(credential));
Error: Argument 2: cannot convert from 'Azure.Identity.ManagedIdentityCredential' to 'Microsoft.Azure.Cosmos.Table.StorageCredentials'

Related

Copy file from Azure Storage blob (Containers) to Azure File shares using Nodejs

Is there a way to copy files from Azure Containers (blobs) to Azure File shares?
I was able to copy files from one container to another - see below.
But I wanted to copy files from Blob to File Shares
const {
BlobServiceClient,
StorageSharedKeyCredential
} = require("#azure/storage-blob");
async function copy() {
const account = "<account-name>";
const accountKey = "<account-key>";
const cert = new StorageSharedKeyCredential(account, accountKey)
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
cert
);
const sourceContainer = blobServiceClient.getContainerClient("documents")
const desContainer = blobServiceClient.getContainerClient("copy")
//if the desContainer does not exist, please run the following code
// await desContainer.create()
//copy blob
const sourceBlob = sourceContainer.getBlobClient("file1.png");
console.log(sourceBlob, sourceBlob.name)
const desBlob = desContainer.getBlobClient(sourceBlob.name)
const response = await desBlob.beginCopyFromURL(sourceBlob.url);
const result = (await response.pollUntilDone())
console.log(result._response.status)
console.log(result.copyStatus)
}
copy()
I have tested in my environment.
To copy a file from Azure File Share to Azure Blob Storage, you can use the below code:
const {
BlobServiceClient,
StorageSharedKeyCredential,
} = require("#azure/storage-blob");
const {
ShareServiceClient
} = require("#azure/storage-file-share")
async function copy() {
const account = "<account-name>";
const accountKey = "<account-key>";
const cert = new StorageSharedKeyCredential(account, accountKey)
const accountSas = "<account-sas>"
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
cert
);
const serviceClient = new ShareServiceClient(`https://${account}.file.core.windows.net${accountSas}`,cert)
const sourceContainer = blobServiceClient.getContainerClient("containerName")
const shareClient = serviceClient.getShareClient("fileShareName")
const directoryClient = shareClient.getDirectoryClient("directoryName");
var fileClient = directoryClient.getFileClient("fileName");
//if the desContainer does not exist, please run the following code
// await desContainer.create()
//copy blob
const sourceBlob = sourceContainer.getBlobClient("blobFileName");
const response = await sourceBlob.beginCopyFromURL(fileClient.url);
}
copy()
To copy the files from Azure Blob Storage to Azure File Share, we can download the blob file to local first and then upload the local file to Azure File Share.
You can use below code to download the blob file to local:
const {
BlobServiceClient,
StorageSharedKeyCredential,
} = require("#azure/storage-blob");
const account = "<account-name>";
const accountKey = "<account-key>";
const cert = new StorageSharedKeyCredential(account, accountKey)
const accountSas = "<account-sas>"
function download() {
const account = "<account-name>";
const accountKey = "<account-key>";
const cert = new StorageSharedKeyCredential(account, accountKey)
const accountSas = "<account-sas>"
const container = "containerName"
const blobFileName = "blobFileName"
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
cert
);
const sourceContainer = blobServiceClient.getContainerClient(container)
const sourceBlob = sourceContainer.getBlobClient(blobFileName);
sourceBlob.downloadToFile(blobFileName);
}
download()
You can use the below code to upload the file from local to Azure File Share:
const {
ShareServiceClient
} = require("#azure/storage-file-share");
function upload() {
const account = "<account-name>";
const accountKey = "<account-key>";
const cert = new StorageSharedKeyCredential(account, accountKey)
const accountSas = "<account-sas>"
const serviceClient = new ShareServiceClient(`https://${account}.file.core.windows.net${accountSas}`,cert)
const shareClient = serviceClient.getShareClient("fileShareName")
const directoryClient = shareClient.getDirectoryClient("directoryName");
var fileClient = directoryClient.getFileClient("FileName");
fileClient.uploadFile("localFilePath");
}
upload()

Is it possible to use service principal to access blob storage?

I am now trying to use Service Principal to access azure blob storage in nodes, instead of using connection string.
What I did (and succeeded) is using connection string as follows:
// connect via connection string
const AZURE_STORAGE_CONNECTION_STRING = process.env.AZURE_STORAGE_CONNECTION_STRING;
const blobServiceClient = BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
Now I want to use Service Principal instead of connection string, but I can't seem to make it work. I can see some examples using some token credentials, e.g.
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
defaultAzureCredential
);
Is it possible to use service principal credentials this way, or are there other ways to do this?
Try this :
const { BlobServiceClient } = require("#azure/storage-blob");
const { ClientSecretCredential } = require("#azure/identity");
const account = '<your accounr name>'
//Using Service Principal
const appID = ""
const appSec = ""
const tenantID = ""
const clientCred = new ClientSecretCredential(tenantID,appID,appSec)
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
clientCred
);
//try to list all containers in stroage account to check if success
blobServiceClient.listContainers().byPage().next().then(result =>{
result.value.containerItems.forEach(element => {
console.log(element.name);
});
})
Result:
Note:
Before you run this demo, pls make sure that you have granted the required permissions to your Service Principal, details see this official doc.

How to generate an azure blob url with SAS signature in nodejs sdk v12?

previously (in older sdk like v2) you can generate a sas url (a signed shareable url for a blob) like following :
var azure = require('azure-storage');
var blobService = azure.createBlobService();
var startDate = new Date();
var expiryDate = new Date(startDate);
expiryDate.setMinutes(startDate.getMinutes() + 100);
startDate.setMinutes(startDate.getMinutes() - 100);
var sharedAccessPolicy = {
AccessPolicy: {
Permissions: azure.BlobUtilities.SharedAccessPermissions.READ,
Start: startDate,
Expiry: expiryDate
}
};
var token = blobService.generateSharedAccessSignature(containerName, blobName, sharedAccessPolicy);
var sasUrl = blobService.getUrl(containerName, blobName, token);
I'm wondering how we can generate that url in sdk v12?
I could not find any documentation for Sas URL in v12.
BlobUtilities and getUrl() methods also not available in v12 (in v12 there are separate packages for every module , in my case I'm using require("#azure/storage-blob");)
Thanks.
Regarding the issue, please refer to the following code
var storage = require("#azure/storage-blob")
const accountname ="blobstorage0516";
const key = "";
const cerds = new storage.StorageSharedKeyCredential(accountname,key);
const blobServiceClient = new storage.BlobServiceClient(`https://${accountname}.blob.core.windows.net`,cerds);
const containerName="test";
const client =blobServiceClient.getContainerClient(containerName)
const blobName="help.txt";
const blobClient = client.getBlobClient(blobName);
const blobSAS = storage.generateBlobSASQueryParameters({
containerName,
blobName,
permissions: storage.BlobSASPermissions.parse("racwd"),
startsOn: new Date(),
expiresOn: new Date(new Date().valueOf() + 86400)
},
cerds
).toString();
const sasUrl= blobClient.url+"?"+blobSAS;
console.log(sasUrl);
You can do so by using generateBlobSASQueryParameters. For example, see the code below:
const AZURE_STORAGE_ACCOUNT = 'account-name';
const AZURE_STORAGE_ACCESS_KEY = 'account-key';
const { StorageSharedKeyCredential, BlobServiceClient, generateBlobSASQueryParameters, BlobSASPermissions } = require("#azure/storage-blob");
const sharedKeyCredential = new StorageSharedKeyCredential(AZURE_STORAGE_ACCOUNT, AZURE_STORAGE_ACCESS_KEY);
const blobServiceClient = new BlobServiceClient(
`https://${AZURE_STORAGE_ACCOUNT}.blob.core.windows.net`,
sharedKeyCredential
);
const containerName = 'container-name';
const blobName = 'blob-name';
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
// const credentials = new StorageSharedKeyCredential()
const sasToken = generateBlobSASQueryParameters({
containerName: containerName,
blobName: blobName,
expiresOn: new Date(new Date().valueOf() + 86400),
permissions: BlobSASPermissions.parse("racwd")
}, sharedKeyCredential);
const sasUrl = `${blockBlobClient.url}?${sasToken}`;
console.log(sasUrl);

How to use Azure storage emulator blob endpoint to get a blob?

The following code, when pointed to a real Azure storage account will successfully return the blob content:
var path = $"{container}/{blob}";
var rfcDate = DateTime.UtcNow.ToString("R");
var headers = "GET\n\n\n\n\n\n\n\n\n\n\n\n" +
"x-ms-blob-type:Block\n" +
$"x-ms-date:{rfcDate}\n" +
$"x-ms-version:{ServiceVersion}\n" +
$"/{AccountName}/{path}";
var uri = new Uri(BlobEndpoint + path);
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("x-ms-blob-type", "Block");
request.Headers.Add("x-ms-date", rfcDate);
request.Headers.Add("x-ms-version", ServiceVersion);
string signature = "";
using (var sha = new HMACSHA256(System.Convert.FromBase64String(AccountKey)))
{
var data = Encoding.UTF8.GetBytes(headers);
signature = System.Convert.ToBase64String(sha.ComputeHash(data));
}
var authHeader = $"SharedKey {AccountName}:{signature}";
request.Headers.Add("Authorization", authHeader);
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
However, if I configure it to use the Azure emulator where:
AccountName = devstoreaccount1
AccountKey = Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
BlobEndpoint = http://127.0.0.1:10000/
ServiceVersion = 2009-09-19
I always get 404. I'm using Azure Storage Emulator v4.6. Is the code or config incorrect or is this not supported with the emulator?
There are two issues with your code:
Blob Service in Storage Emulator listens at http://127.0.0.1:1000 however the base URI is http://127.0.0.1:1000/devstoreaccount1.
In computation of Signature String (header variable in your code), account name must appear twice. This is because the account name is part of your resource's URI path (URL for the blob would be http://127.0.0.1:1000/devstoreaccount1/container-name/blob-name).
Based on these, please try the following code:
static async Task<string> ReadBlobFromDevStorage()
{
var container = "temp";
var blob = "test.txt";
var ServiceVersion = "2009-09-19";
var AccountName = "devstoreaccount1";
var BlobEndpoint = "http://127.0.0.1:10000/devstoreaccount1";
var path = $"{container}/{blob}";
var AccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
var rfcDate = DateTime.UtcNow.ToString("R");
var headers = "GET\n\n\n\n\n\n\n\n\n\n\n\n" +
"x-ms-blob-type:Block\n" +
$"x-ms-date:{rfcDate}\n" +
$"x-ms-version:{ServiceVersion}\n" +
$"/{AccountName}/{AccountName}/{path}";
var uri = new Uri(BlobEndpoint + "/" + path);
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("x-ms-blob-type", "Block");
request.Headers.Add("x-ms-date", rfcDate);
request.Headers.Add("x-ms-version", ServiceVersion);
string signature = "";
using (var sha = new HMACSHA256(System.Convert.FromBase64String(AccountKey)))
{
var data = Encoding.UTF8.GetBytes(headers);
signature = System.Convert.ToBase64String(sha.ComputeHash(data));
}
var authHeader = $"SharedKey {AccountName}:{signature}";
request.Headers.Add("Authorization", authHeader);
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
return content;
}
}

Azure forbidden exception trying to connect programmatically

I have the following code:
var authority = "https://login.microsoftonline.com/XXX-XXXX-XXXXX-XXXXXX/oauth2/authorize";
var clientId = "YYY-YYYY-YYYYY-YYYYYY";
var appKey = "xxxxxxxxxxxxx";
var resource = "https://management.core.windows.net/";
var authContext = new AuthenticationContext(authority, true);
var clientCredential = new ClientCredential(clientId, appKey);
var result = authContext.AcquireToken(resource, clientCredential);
var token = result.AccessToken;
var creds = new TokenCloudCredentials("ZZZ-ZZZZ-ZZZZZ-ZZZZZZ", token);
var client = new WebSiteManagementClient(creds);
var data = client.WebSites.Get("eastuswebspace", "some-site", new WebSiteGetParameters());
I am getting this error on the client.WebSites.Get() call:
The server failed to authenticate the request. Verify that the
certificate is valid and is associated with this subscription
But I am not using a certificate, I am using AuthenticationContext.
What am I doing wrong?

Resources