Manage Azure CDN Endpoint in Node.js
The Azure Content Delivery Network (CDN) offers a global solution for delivering high-bandwidth content that is hosted in Azure or any other location. Using the CDN, we can cache publicly available objects loaded from Azure blob storage, a web application, virtual machine, application folder, or other HTTP/HTTPS location. The major advantages of using the CDN are lower latency and faster delivery of content to users irrespective of their geographical location in relation to the datacenter where the application is hosted.
Though we can manage Azure CDN in Azure portal, there is still requirement to make it programming, for example we might purge the content in a CICD pipeline after a new web application deployment. Also, we might make a daemon application to monitor CDN status and perform operation automatically. Azure CDN REST API has provided rich functionalities to achieve these, and I will demonstrate how to make it in Node.js.
Before calling the REST API, we need get authorized by Azure AD via OAuth protocol firstly. Azure AD OAuth supports different grants including Authorization code, Implicit flow, Client Credential flow for different application scenario. For example, authorization code flow is best for server side web application and implicit flow works for SPA web app. In most condition, we will login by our own account and password to retrieve the token, while client credential flow is suitable for a daemon application as it doesn't need user interactivity. If you are interested in all these OAuth flows, you may also refer to Azure Active Directory Authentication Libraries which contains the related libraries introduction.
When we use client credential flow to access the resource (call REST API), we need set up an identity for the app and authenticate the app with its own credentials. This identity is known as a service principal, and we can understand it as a service account which has enough permission to perform some specific operations. You may refer to https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal about how to create a service principal by PowerShell or Azure CLI, I will demonstrate how to make it in portal. Firstly, we need register an application in Azure AD by click "App registrations". Then click "Required permissions" blade and grant "Windows Azure Service Management API" delegate permission shown below.
Lastly, we need navigate to Azure CDN endpoint and grant Contributor role to the SPN. Notice that we can also assign the SPN as Azure CDN profile or even resource group's contributor, the difference is the SPN will have more privilege if it is a contributor for resource group.
Now, it is time to write the code. The following is a simple Node.js application sample to call Purge REST API of Azure CDN. Run the below command in cmd to configure the application.
npm init
npm install adal-node --save
npm install superagent --save
Then create app.js shown below. clientId and clientSecret can be retrieved in the registered application. If you would like to know your tenantId, click help button in Azure portal's top right corner, click "Show Diagnostics", you will be able to find tenantId in the downloaded PortalDiagnostics.json.
var adal = require('adal-node');
var request = require('superagent');
var AuthenticationContext = adal.AuthenticationContext;
var parameters = {
tenantId : '{tenantId}',
authorityHostUrl : 'https://login.microsoftonline.com',
clientId : '{clientId}',
clientSecret : '{clientSecret}'
};
var authorityUrl = parameters .authorityHostUrl + '/' + parameters .tenantId;
var resource = 'https://management.core.windows.net/';
var context = new AuthenticationContext(authorityUrl);
context.acquireTokenWithClientCredentials(resource, parameters.clientId, parameters.clientSecret, function(err, tokenResponse) {
if (err) {
console.log(err.stack);
} else {
console.log(tokenResponse);
request
.post('https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cdn/profiles/{profileName}/endpoints/{endpointName}/purge?api-version=2016-10-02')
.send({"contentPaths": ["/img", "/js"]})
.set('Authorization', 'Bearer ' + tokenResponse.accessToken)
.end((err, res) => {
//callback(err, res);
console.log(res);
});
}
});