Is it possible to use service principal to access blob storage? - node.js

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.

Related

Azure Default Credential with Managed Identity not working (node)

I was trying to use a user-assigned managed identity with the DefaultAzureCredential, but am getting the 403 permissions mismatch error. I'm following the code example found in MS docs and it still fails. However, replacing the DefaultAzureCredential with the explicit ManagedIdentityCredential works just fine.
This is my code:
const { BlobServiceClient } = require('#azure/storage-blob');
const { DefaultAzureCredential } = require('#azure/identity');
const {url, clientId} = require('./config');
const cred = new DefaultAzureCredential({managedIdentityClientId: clientId});
const containerClient = new BlobServiceClient(url, cred).getContainerClient('container-name');
(async () => {
const exists = await containerClient.exists();
console.log({exists});
})();
This looks like it should work, but it does not. Any thoughts?
versions:
"#azure/identity": "^1.1.0",
"#azure/storage-blob": "^12.12.0",
node v16.18.1
I tried in my environment and got below results:
I tried to reproduce same code in my environment, and it successfully executed with container exist or not.
Code:
const { BlobServiceClient } = require('#azure/storage-blob');
const { DefaultAzureCredential } = require('#azure/identity');
const url="https://venkat123.blob.core.windows.net";
const clientId="<client-id>";
const cred = new DefaultAzureCredential({managedIdentityClientId: clientId});
const Client = new BlobServiceClient(url, cred);
const containerClient=Client.getContainerClient("test");
(async () => {
const exists = await containerClient.exists();
console.log({exists});
})();
Console:
403, This request is not authorized to perform this operation using this permission.
If you are accessing storage account with identity, you need a role like Storage-blob-contributor or storage-blob-owner.
Go to portal -> your storage account -> Access Control (IAM) ->Add -> Add role assignments -> storage-blob-contributor or storage-blob-owner->Add your user managed identity id.
Also, I tried with user-assigned managed identity with the DefaultAzureCredential it worked perfectly.
Code:
const { BlobServiceClient } = require('#azure/storage-blob');
const { DefaultAzureCredential } = require('#azure/identity');
const url="https://venkat123.blob.core.windows.net";
const cred = new DefaultAzureCredential();
const Client = new BlobServiceClient(url, cred);
const containerClient=Client.getContainerClient("test");
(async () => {
const exists = await containerClient.exists();
console.log({exists});
})();
Console:

Cannot upload file to Azure Blob Node.js

Trying to upload a file to azure blob storage using #azure/storage-blob sdk in nodejs:
module.exports.createBlob = (blobName, containerName, blobContent) => {
return new Promise(async (resolve, reject) => {
try {
const sharedKeyCredential = await this.createSharedAccessToken(blobName, 'c')
const blobServiceClient = new BlobServiceClient(
`https://${process.env.AZURE_BLOB_ACCOUNT}.blob.core.windows.net`,
sharedKeyCredential
)
const containerClient = blobServiceClient.getContainerClient(containerName)
const blockBlobClient = containerClient.getBlockBlobClient(blobName)
const blob = await blockBlobClient.upload(blobContent, blobContent.length) // implement later
resolve(blob)
} catch (err) {
console.log(err)
reject(err)
}
})
}
module.exports.createSharedAccessToken = (blobName, permission) => {
return new Promise(async (resolve, reject) => {
const sharedKeyCredential = new StorageSharedKeyCredential(process.env.AZURE_BLOB_ACCOUNT, process.env.AZURE_BLOB_KEY)
const containerName = process.env.AZURE_CONTAINER_NAME
const startsOn = new Date()
expiresOn.setMinutes(expiresOn.getMinutes() + parseInt(autoLogoutDuration.KeyValue))
const blobSAS = generateBlobSASQueryParameters({
containerName, // Required
blobName, // Required
permissions: BlobSASPermissions.parse(permission), // Required
startsOn: startsOn, // Required
},
sharedKeyCredential // StorageSharedKeyCredential - `new StorageSharedKeyCredential(account, accountKey)`
).toString()
resolve(decodeURI(blobSAS))
})
}
It keeps throwing a "NoAuthenticationInformation" error. The same creds work for downloading an existing blob but uploading is not working no matter what I try. Any help would be appreciated.
Followed by this MS DOC , I tried to reproduce your issue ,but able to upload files into my azure blob container using Node.js without any authentication error.
As you are using shared key credential we need to have all those permissions in our portal as shown below:
Also i am using #azure/storage-blob sdk in nodejs in my package.json .
Also added #azure/storage-blob sdk in my testupload.js file
And added the below code into my testupload.js file as i have already created container i just commented the above screenshot code .
const account="testa";
const sharedKeyCredential = new StorageSharedKeyCredential("yourstorageaccountname", "your storage key connection string");
const blobServiceClient1 = new BlobServiceClient(
// When using AnonymousCredential, following url should include a valid SAS or support public access
`https://${account}.blob.core.windows.net`,
sharedKeyCredential
);
const blobnewname="example2.txt"
blobContent="hi hello";
const containerClient1 = blobServiceClient.getContainerClient("test")
const blockBlobClient1= containerClient.getBlockBlobClient(blobnewname)
const blob = blockBlobClient1.upload(blobContent, blobContent.length)
Then i can able to test and upload my files to Azure blob container
Here are screenshot for reference:
For more information please refer this MS DOC : Azure Storage samples using v12 JavaScript client libraries
UPDATE:-
As suggested by #Setanjan Roy
Alternate way:-
To get rid of this we can use new BlobServiceClient( https://${process.env.AZURE_BLOB_ACCOUNT}.blob.core.windows.net${sharedKeyCredential} )

Azure Rest Api Community for developer

I am a developer and trying to disassociate NSG from subnets using rest API but could not find any good answer please tell me community for Azure Rest API so that I can ask my question there.
If you want to disassociate NSG from subnets, please refer to the following steps
Create a service principal and assign contributor role to the sp
az login
# it will create a service principal and assign a contributor rolen to the sp
az ad sp create-for-rbac -n "MyApp" --sdk-auth
code
var msRestNodeAuth = require("#azure/ms-rest-nodeauth");
var { NetworkManagementClient } = require("#azure/arm-network");
const clientId = "sp clientId";
const secret = "sp clientSecret";
const domain = "hanxia.onmicrosoft.com";
const subscriptionId = "e5b0fcfa-e****e5fe29f4c68";
async function main() {
try {
const creds = await msRestNodeAuth.loginWithServicePrincipalSecret(
clientId,
secret,
domain,
);
const client = new NetworkManagementClient(creds, subscriptionId);
const resourceGroupName = "testvnet";
const virtualNetworkName = "test";
const subnetName = "default";
//get the subnet
const subnetrespose = await client.subnets.get(
resourceGroupName,
virtualNetworkName,
subnetName,
);
const subnet = subnetrespose._response.parsedBody;
console.log(subnet);
console.log("----------update-----------");
subnet.networkSecurityGroup = null;
const res = await client.subnets.createOrUpdate(
resourceGroupName,
virtualNetworkName,
subnetName,
subnet,
);
console.log(res._response.parsedBody);
} catch (error) {
console.log(error);
}
}
main();

Unable to regenerate storage key with Azure Management API

I can't use /regenerateKey [1] to regenerate keys for a Storage Account with the Azure Management API.
I'm using the following code in JavaScript (the resource has the subscription removed)
const { ClientSecretCredential } = require('#azure/identity');
const { SecretClient } = require('#azure/keyvault-secrets');
const MSRestAzure = require('ms-rest-azure');
const keyVaultName = process.env.KEY_VAULT_NAME;
const KVUri = `https://${keyVaultName}.vault.azure.net`;
const credential = new ClientSecretCredential(
process.env.AZURE_TENANT_ID,
process.env.AZURE_CLIENT_ID,
process.env.AZURE_CLIENT_SECRET,
);
const vault = new SecretClient(KVUri, credential);
function getCreds() {
return new Promise((res, rej) => {
MSRestAzure.loginWithServicePrincipalSecret(
process.env.AZURE_CLIENT_ID,
process.env.AZURE_CLIENT_SECRET,
process.env.AZURE_TENANT_ID,
(err, creds) => {
if (err) {
rej(err);
return;
}
res(creds);
},
);
});
}
const getResourceUrl = (resource, action) => `https://management.azure.com${resource}/${action}?api-version=2019-04-01`;
const resource = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Storage/storageAccounts/MyStore
const creds = await getCreds();
const client = new MSRestAzure.AzureServiceClient(creds);
const regenUrl = getResourceUrl(resource, 'regenerateKey');
await client.sendRequest({ method: 'POST', url: regenUrl }).then(console.log);
I'm getting an UnexpectedException response -
{
"error": {
"code": "UnexpectedException",
"message": "The server was unable to complete your request."
}
}
The Client ID/Secret belongs to an app registration that has access to the storage account, as well as Contributor and Storage Account Key Operator over that subscription.
I'm lead to think that I've not formed the request properly.
I am able to reproduce the error if I don't specify the request body.
Please provide the request body in the following format:
{
keyName: "key1 or key2 (basically which key you want to regenerate)"
}

how to upload a file to Azure storage blob Container after getting sasQueryParameter in SDK v10 using nodejs?

I would like to have some help with uploading a file to Azure blob storage.
I actually want to be able to get SAS token from the backend for the container and want to be able to upload a file to that container using react web app.
I used this for reference, but couldn't get going.
use generateBlobSASQueryParameters function from #azure/storage-blob package.
the way I used generateBlobSASQueryParameters is :
const {
BlobSASPermissions,
SharedKeyCredential,
generateBlobSASQueryParameters,
} = require("#azure/storage-blob");
const {
STORAGE_ACCOUNT_KEY,
STORAGE_ACCOUNT_NAME,
CONTAINERS,
} = require("./Constants/blobStorage"); // get these from azure storage account
const generateSasQueryToken = () => {
const sharedKeyCredential = new SharedKeyCredential(STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY);
const permissions = BlobSASPermissions.parse("racwd");
const startDate = new Date();
const expiryDate = new Date(startDate);
expiryDate.setMinutes(startDate.getMinutes() + 100);
startDate.setMinutes(startDate.getMinutes() - 100);
const queryParams = generateBlobSASQueryParameters(
{
containerName: CONTAINERS.IMAGE,
permissions: permissions.toString(),
startTime: startDate,
expiryTime: expiryDate,
},
sharedKeyCredential,
);
return {
SAS_STRING: queryParams.toString(),
CONTAINER_NAME: CONTAINERS.IMAGE,
URL: `https://${STORAGE_ACCOUNT_NAME}.blob.core.windows.net/`,
};
};
module.exports = generateSasQueryToken;

Resources