I know you can track normal operations using the standard API: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-async-operations
However I was wondering if there was a known way to utilize the Fluent Azure Management Libraries to track long async operations such as VM operations etc. For example the VM restart method is a void Task which does not return an operation-id for tracking.
async Task IVirtualMachineScaleSetVM.RestartAsync(CancellationToken cancellationToken)
{
await this.RestartAsync(cancellationToken);
}
Cheers!
AFAIK, it seems that it's hard to trace VM restart status which does not return an operationId.
Logging in the fluent Azure management libraries for .NET leverages the underlying AutoRest service client tracing.
Create a class that implements Microsoft.Rest.IServiceClientTracingInterceptor. This class will be responsible for intercepting log messages and passing them to whatever logging mechanism you're using.
class ConsoleTracer : IServiceClientTracingInterceptor
{
public void ReceiveResponse(string invocationId, HttpResponseMessage response) { }
}
Before creating the Microsoft.Azure.Management.Fluent.Azure object, initialize the IServiceClientTracingInterceptor you created above by calling ServiceClientTracing.AddTracingInterceptor() and set ServiceClientTracing.IsEnabled to true. When you create the Azure object, include the .WithDelegatingHandler() and .WithLogLevel() methods to wire up the client to AutoRest's service client tracing.
ServiceClientTracing.AddTracingInterceptor(new ConsoleTracer());
ServiceClientTracing.IsEnabled = true;
var azure = Azure
.Configure()
.WithDelegatingHandler(new HttpLoggingDelegatingHandler())
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.Authenticate(credentials)
.WithDefaultSubscription();
For more details, you could refer to this article.
Related
I am building an ASP NET Core web application that will perform a delete operation for a user on a remote datastore. Currently, I have a frontend web app that communicates with Azure Functions to delete a user. I have a concern with security. How can I make sure the user is the logged-in user? Currently, in my ASP Net Core Web App, I have the user authenticate with AAD using Microsoft as an Identity Provider. From a client-side, the user is verified and taken care of. However, my app calls the Azure Functions endpoints. Is there an extra level of security that I could add. I only want to give my web app (registered in Azure) the ability to call the endpoints.
There are two main ways to authenticate your users. One is to use the App Services authentication options: https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad. This is by far the easier method.
If you need more control over things than what is available in the service, then you can implement validation within the Function itself as Thiago mentioned. Ben Morris did a fairly detailed post on how to implement your own OAUTH provider inside your Function App with C#: https://www.ben-morris.com/custom-token-authentication-in-azure-functions-using-bindings/ If you can take care of the validation in the Function's DI container, validation inside a specific function is fairly clean as seen in the post:
public class ExampleHttpFunction
{
private readonly IAccessTokenProvider _tokenProvider;
public ExampleHttpFunction(IAccessTokenProvider tokenProvider)
{
_tokenProvider = tokenProvider;
}
[FunctionName("ExampleHttpFunction")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "example")] HttpRequest req, ILogger log)
{
var result = _tokenProvider.ValidateToken(req);
if (result.Status == AccessTokenStatus.Valid)
{
log.LogInformation($"Request received for {result.Principal.Identity.Name}.");
return new OkResult();
}
else
{
return new UnauthorizedResult();
}
}
}
We are planning to build a web application, and I was hoping someone could help us to decide whether to use Azure App Service or Azure Function for providing rest API to the client side.
Our requirements are as follows.
Authentication and authorization
CRUD on Azure SQL and Cosmos DB
Multi region
100,000,000 API calls per month
At first, we were going to build the backend using Azure App Service. But after studying pros and cons on Azure Functions, Azure Functions became more appealing to us.
So is it even a good idea to build a web application that depends on Azure Functions as a REST API provider?
Does anyone have an experience building, managing and scaling up and out Azure Functions as a REST API provider?
Is it even a good idea to build a web application that depends on Azure Functions as a REST API provider?
It seems you are planning to have REST API using Web Service or Azure Function. Your decision is perfect I would say. For Azure Function its not mandatory to have web service for that. Azure function would be best option for you. You can implement all the feature that Web API provides. So if your target is only develop API then you can start with Azure Function with no other alternative. Its outstanding actually!
Does anyone have an experience building, managing and scaling up and out Azure Functions as a REST API provider?
I am working with Azure Function for our AI Base Bot with LUIS integration. From my understanding it's a very easily maintainable, fastest response time, you can build it from anywhere. So you can undoubtedly go with Azure function.
Why Choose Azure Function:
It's stateless, need not any server to run
Full REST, can call from anywhere any Region
Can develop both Azure Portal and local Visual Studio
Cost-effective, you can pay only how much you use.
Multiple language support
Easy Authorization and Authentication functionality
No limit of calling as per your consumption plan
Do A Lot With Azure Function:
You can develop a robust API service with Azure functions. It has many outstanding features. Please check Check here
Authorization and Authentication:
You can simply integrate your authorization and authentication on your function App. Even you can implement it on each function separately or on a full application. It supports most of the popular authentication provider for example:
Azure Active Directory
Microsoft Identity
Goggle
Facebook
Twitter auth
See how can you implement authentication:
Step:1
Step:2
Rest Function Code Sample:
Here I am giving you a simple code snippet to start with: though it's on Azure Table Storage, but help you to develop azure function and CRUD concept.
Your Sample Class:
public class YourSampleClass
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
}
Table Storage Class:
public class TableStorageClass
{
public TableStorageClass()
{
}
public TableStorageClass(DynamicTableEntity entity)
{
PartitionKey = entity.PartitionKey;
RowKey = entity.RowKey;
}
public string PartitionKey { get; set; }
public string RowKey { get; set; }
}
Azure Function V2 Example:
public static class FunctionReadFromTableStorage
{
[FunctionName("FunctionReadFromTableStorage")]
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.");
//Read Request Body
var content = await new StreamReader(req.Body).ReadToEndAsync();
//Extract Request Body and Parse To Class
YourSampleClass objYourSampleClass = JsonConvert.DeserializeObject<YourSampleClass>(content);
// Validate param because PartitionKey and RowKey is required to read from Table storage In this case , so I am checking here.
dynamic validationMessage;
if (string.IsNullOrEmpty(objYourSampleClass.PartitionKey))
{
validationMessage = new OkObjectResult("PartitionKey is required!");
return (IActionResult)validationMessage;
}
if (string.IsNullOrEmpty(objYourSampleClass.RowKey))
{
validationMessage = new OkObjectResult("RowKey is required!");
return (IActionResult)validationMessage;
}
// Table Storage operation with credentials
var client = new CloudTableClient(new Uri("https://YourStorageURL.table.core.windows.net/"),
new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials("YourStorageName", "xtaguZokAWbfYG4QDkBjT+YourStorageKey+T/kId/Ng+cl3TfYHtg=="));
var table = client.GetTableReference("YourTableName");
//Query filter
var query = new TableQuery()
{
FilterString = string.Format("PartitionKey eq '{0}' and RowKey eq '{1}'", objYourSampleClass.PartitionKey, objYourSampleClass.RowKey)
};
//Request for storage query with query filter
var continuationToken = new TableContinuationToken();
var storageTableQueryResults = new List<TableStorageClass>();
foreach (var entity in table.ExecuteQuerySegmentedAsync(query, continuationToken).GetAwaiter().GetResult().Results)
{
var request = new TableStorageClass(entity);
storageTableQueryResults.Add(request);
}
//As we have to return IAction Type So converting to IAction Class Using OkObjectResult We Even Can Use OkResult
var result = new OkObjectResult(storageTableQueryResults);
return (IActionResult)result;
}
}
Point To Remember:
In case of Azure Portal execution just get rid of FunctionReadFromTableStorage class
You Need following reference to execute above code
using System;
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 Microsoft.WindowsAzure.Storage.Table;
using System.Collections.Generic;
Postman Request Pattern:
Function Invoke Sample:
{
"PartitionKey": "Your Param According to Table Storage Design" ,
"RowKey": "Your Param According to Table Storage Design",
"Directory": "Your Param According to Table Storage Design"
}
See The Screen Shot:
Post Man Response:
Response is subject to my own table design
[
{
"partitionKey": "Microsoft SharePoint Server",
"rowKey": "2016"
}
]
See The Screen Shot Below:
Note: For CosmosDb Integration you could check here. Azure SQL with Function take a look here.
I understand that Azure Functions are potentially open endpoints on the internet if I read Microsoft’s documentation correctly and per conversations with a friend who has some experience working with web development paradigms that Azure Functions leverages. A cursory reading of security forums and stack overflow questions on the topic leads me to understand at least a couple options of securing them namely
Azure Active Directory
Shared Access Signatures (SAS) and
Azure Virtual Networks.
Context/ What does my Azure Function do? It manages a blob container related to an ETL of vendor data from a SFTP source to a SQL Endpoint which this ETL utilizes an intermediary blob container for file transfer and long term cold storage of source data. The Azure Function moves the blobs from one container to an archive container after they have been loaded to the SQL endpoint. Why Azure Function to manage the blob containers?
SSIS lacks ability to perform blob manipulation (i.e copy and delete)
Logic App lacks ability to perform a join (of files loaded to SQL endpoint and file names in blob container)
An example of one of the functions is shown here below:
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net;
using Microsoft.WindowsAzure.Storage.Blob;
using System.Collections.Generic;
using System.Text;
namespace AFA_ArchiveBlob
{
public static class HttpTrigger_BlobInput
{
[FunctionName("HttpTrigger_BlobInput")]
public static async Task<HttpResponseMessage> Run(
//public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "{name}")] HttpRequest req,
string name,
ILogger log,
[Blob("{name}/blobname",FileAccess.ReadWrite,Connection = "AzureWebJobsStorage")] CloudBlobContainer myCloudBlobContainer
)
{
//Execution Logged.
log.LogInformation($"HttpTrigger_BlobInput - C# HTTP trigger function processed a request.");
//Run the query against the blob to list the contents.
BlobContinuationToken continuationToken = null;
List<IListBlobItem> results = new List<IListBlobItem>();
do
{
var response = await myCloudBlobContainer.ListBlobsSegmentedAsync(continuationToken);
continuationToken = response.ContinuationToken;
results.AddRange(response.Results);
}
while (continuationToken != null);
//Query the names of the blobs. Todo: can this be a single line linq query select instead?
List<string> listBlobNames = new List<string>();
foreach (CloudBlockBlob b in results)
{
listBlobNames.Add(b.Name);
}
//Serialize the list of blob names to json for passing to function caller via return statement
var jsonReturn = JsonConvert.SerializeObject(listBlobNames);
log.LogInformation("Returning the following JSON");
log.LogInformation(jsonReturn);
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jsonReturn, Encoding.UTF8, "application/json")
};
}
}
}
Firstly, even though using keys might be convenient, I see that official documentation advises against using keys to secure function endpoint in production scenarios.
I suggest it would be a better choice to go with Azure Active Directory for security.. as explained here Secure an HTTP endpoint in production
How to Implement
I see two possible approaches:
1. Simple Approach: Check that calling application is your Azure logic app specifically
Enable Azure Active Directory Authentication for your Azure Function App. You can simply use Express settings (with create a new Azure AD app)
Enable Managed Service Identity for your Logic App.
Find out appid for Managed Service Identity associated with your logic app.. go to Azure Portal > Azure Active Directory > Enterprise Applications > All Applications > Relevant Service Principal (Explained in more detail with screenshots in another SO post here)
Authenticate your logic app to Azure function using Managed Service Identity as explained here.. Authenticate with managed identity in logic app.. note that resource being accessed will be your Azure function.
In your function code, now you can check that appid claim in access token should exactly match the appid for logic app (i.e. logic app is the one calling your function).. otherwise you can reject the call with Unauthorized exception.
2. A more declarative Approach: Have an application permission defined for Azure function app and check for this permission/role being present in auth token from client calling your function
This approach is a little more declarative, as you define an application permission that needs to be assigned to any application that can call your Azure function.
Enable Azure Active Directory Authentication for your Azure Function App. You can simply use Express settings (with create a new Azure AD app)
Now go to Azure Active Directory > App Registrations > App registration for your function app > Manifest
Add a new application role.. using json like this:
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Can invoke my function",
"id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
"isEnabled": true,
"description": "Apps that have this role have the ability to invoke my Azure function",
"value": "MyFunctionValidClient"
}]
Enable Managed Service Identity for your Logic App.
Find out appid for Managed Service Identity associated with your logic app.. as already explained in approach 1 above
Assign the app permission to this managed service identity..
New-AzureADServiceAppRoleAssignment -ObjectId <logicappmsi.ObjectId> -PrincipalId <logicappmsi.ObjectId> -Id "fc803414-3c61-4ebc-a5e5-cd1675c14bbb" -ResourceId <yourfunctionaadapp.ObjectId>
Authenticate your logic app to Azure function using Managed Service Identity.. as already explained in approach 1 above
Now, in the auth token received by your function, you can check that the role claims collection must contain a role named "MyFunctionValidClient" otherwise you can reject the call with Unauthorized exception.
In addition to the above steps explained by #Rohit Below step is important:
Go to Host.json of the function.
Default authLevel : "function" should be changed to "authLevel": "anonymous".
This does not mean anyone can access the function as with Log on AD sign-in authentication required sign user however with managed identity in logic app function authenticate with service principle.
Simplified scenario:
One Azure Mobile App "ServiceManagement" in eu (including database)
Two Azure Mobile Apps, same code, one in EU "ServiceEU", one in US "ServiceUS" (each with their own seperate database)
Customer signs in to ServiceManagement, selects what region he wants his data to be hosted at. Customer buys service options -> payment record, selected options etc. are saved in ServiceManagement.
Now ServiceManagement connects to either ServiceEU or ServiceUS and and tells it to create the corresponding service plan for the customer. Beyond the times the customer buys service options there will be no communication between the services.
Are there any other options besides HttpClient to handle the communication between the Azure Mobile App "ServiceManagement" and "ServiceEU" or "ServiceUS"?
My current code seems to work but I couldn't find any resources/documentation for cases like this. So I'm not sure if there are better alternatives.
/// <summary>
/// Hosted in ServiceManagement
/// </summary>
/// <returns></returns>
[HttpGet]
[ActionName("completeRemote")]
[ResponseType(typeof(String))]
public async Task<string> completeRemote()
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("ZUMO-API-VERSION", "2.0.0");
//Calling completeAll from different Azure Mobile App "<url>"
var res = await client.GetAsync("https://<url>/api/Test/completeAll");
res.EnsureSuccessStatusCode();
var str = await res.Content.ReadAsStringAsync();
str = JsonConvert.DeserializeObject<String>(str);
//verify request completed
//Do something with str
return str;
}
Please keep in mind that this is a very simplified concept
Are there any other options besides HttpClient to handle the communication between the Azure Mobile App "ServiceManagement" and "ServiceEU" or "ServiceUS"?
As far as I know, the C# mobile app backend is a web api. Normally we will use httpclient to send the request to the web api application to get the result.
If you don't want to use the httpclient, you could use azure mobile client SDK.
It is easily to write codes.
You could install it from the Nuget Package.
Install-Package Microsoft.Azure.Mobile.Client
Here is the sample code, hope it gives you some tips:
Notice: It still will send the request to the mobile app backend.
public static async Task<string> GetApplicationToken()
{
var clientUri = $"https://your-mobile-app-id.azurewebsites.net";
var client = new MobileServiceClient(clientUri);
var response = await client.InvokeApiAsync<string>("/api/values", HttpMethod.Get, null);
return response;
}
You could make use of Azure Service Bus (or host your own service bus)
Depend on Azure Service Bus when you need highly reliable cloud
messaging service between applications and services, even when one or
more is offline.
about Enterprise service bus on wikipedia:
An enterprise service bus (ESB) implements a communication system
between mutually interacting software applications in a
service-oriented architecture (SOA).
...
As it implements a software architecture for distributed computing, it
therefore also implements a special variant of the more general
client-server model. Whereas in general any application using ESB can
behave as server or client in turns.
The Azure API app documentation briefly describe three methods of protecting the API app. One of them is the internal accessibility settings: “Internal - Only other API apps or web apps in the same resource group are allowed to call the API app.”
I have create another Azure API app in the same resource group and hosting plan. But a get a HTTP 403 authorization failure with the following error message when I try to connect to the interal API app from the Web App:
“Permissions for service are set to internal but this request was external.”
Has anyone been able to use the internal settings between API Apps in the same Resource Group?
We will be documenting this soon. in the meantime, what you need to do is the following. You need to install nuget package Microsoft.Azure.AppService.ApiApps.Service. Then, create a delegating handler as follows:
class InternalCredentialHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Runtime.FromAppSettings(request).SignHttpRequest(request);
return base.SendAsync(request, cancellationToken);
}
}
Then when you use HttpClient or a generated client to connect to another internal API, simply pass in the delegating handler. For example:
MySampleClient client = new MySampleClient(new DelegatingHandler[] { new InternalCredentialHandler() });
Thanks,
Mohit
Edit: the documentation for this is now available at https://azure.microsoft.com/documentation/articles/app-service-api-dotnet-consume-internal/