Saturday, March 19, 2022

 

Identity claims:      

This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Functions with the link here. This article discusses Microsoft Identity Model.

One of the most important aspects of code that executes in the cloud is the identity invoking it along with the claims it presents. Identity refers to a security principal that is protected and whose access is well-managed. The data associated with this entity and its representation falls under and identity and access management routines for a cloud service. While the execution of code to provide certain functionalities requires privileges and an identity must provide claims to show that the code can be executed, services operate with the least privilege policy so that unauthenticated users are refuted, and unauthorized access is forbidden.

The use of principal and access is critical to Azure Functions just as much as it is for any service. Code must not only demand for privilege, but the identity must also provide adequate claims. This is particularly relevant to the user management.

 

Roles provide a convenient form of bundling these privileges and enabling access controls. Roles can also be graded to have incremental privileges. Certain deployment actions can also be performed with incremental privileges.

One of the fundamental aspects of privileged code execution is the ability to add privilege on demand.

The following code illustrates a way to do this programmatically:

 

using System.IO;

using IdentityClaim = Microsoft.IdentityModel.Claims.Claim;

using IdentityClaimTypes = Microsoft.IdentityModel.Claims.ClaimTypes;

using IdentityClaimsPrincipal = Microsoft.IdentityModel.Claims.ClaimsPrincipal;

using ClaimsIdentityCollection = Microsoft.IdentityModel.Claims.ClaimsIdentityCollection;

 

 

            IClaimsIdentity claimsIdentity = new ClaimsIdentity(Thread.CurrentPrincipal.Identity);

            var claimValue = string.Format("claim://{0}@{1}", DsmsResourceRole.PrivilegedDeploymentOperator, "sample-resource-folder-test");

            var identityClaim = new IdentityClaim(IdentityClaimTypes.Role, claimValue);

            claimsIdentity.Claims.Add(identityClaim);

            ClaimsIdentityCollection claimsIdentityCollection = new ClaimsIdentityCollection(new List<IClaimsIdentity>() { claimsIdentity });

            var newIcp = IdentityClaimsPrincipal.CreateFromIdentities(claimsIdentityCollection);

            Thread.CurrentPrincipal = newIcp;

 

 

The  above example uses the Microsoft.IdentityModel namespace to describe the elevation of privilege to run some code.

 

Friday, March 18, 2022

 Azure Functions:      

This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Functions with the link here. This article continues to discuss Azure Functions’ best practices with a focus on organization and scalability. 

 

Performance and scalability concerns are clearer with serverless function apps. Large long-running functions can cause unexpected timeout issues. Bloating of an application is noticeable when there are many libraries included. For example, a Node.js function application can have dozens of dependencies. Importing dependencies increases load times that result in unexpected timeouts. Dependencies tree can be of arbitrary breadth and length. Whenever possible, it is best to split the function applications into sets that work together and return responses fast. One way of doing this involves the HTTP trigger function being separate from a queue trigger function such that the HTTP trigger returns an acknowledgment while the payload is placed on the queue to be processed subsequently. 

 

Function applications in production should be as overhead-free as possible. There should not be any test-related functions. Shared code between functions must be in its own folder otherwise there will be multiple versions of it. Memory usage is averaged across functions so the less there are the better. Verbose logging in production code has a negative impact. 

Async calls can be used to avoid blocking calls. Asynchronous programming is a recommended best practice, especially when blocking I/O operations are involved. Any host instance for functions uses a single worker process. The functions_worker_process_count can increase the number of worker processes per host to up to 10 and function invocations are distributed across these workers. 

Messages can be batched which leads to better performance. This can be configured in the host.json file associated with the function application. C# functions can change the type to a strongly typed array to denote batching. Other languages might require setting the cardinality in function.json. 

Host behaviors can be configured to better handle concurrency. Host runtime and trigger behaviors can be configured in the host.json file. Concurrency can be managed for a number of triggers and these settings tremendously influence the scaling of the function applications. 

Settings apply across all functions in the application for a single instance of that application. A function application having two HTTP functions and maxConcurrentRequests set to 25 will count a request to either trigger towards the shared concurrent requests and when the application is scaled out to say ten instances, the maximum concurrency will be effectively 250 requests across those instances. 

Thursday, March 17, 2022

 

Azure Functions:    

This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Functions with the link here. This article continues to discuss Azure Functions’ best practices with focus on organization and scalability.

 

Performance and scalability concerns are clearer with serverless function apps. Large long-running functions can cause unexpected timeout issues. Bloating of an application is noticeable when there are many libraries included. For example, a Node.js function application can have dozens of dependencies. Importing dependencies increases load times that result in unexpected timeouts. Dependencies tree can be of arbitrary breadth and length. Whenever possible, it is best to split the function applications into sets that work together and return responses fast. One way of doing this involves HTTP trigger function to be separate from a queue trigger function such that the HTTP trigger returns an acknowledgement while the payload is placed on the queue to be processed subsequently.

Scalability is also improved when functions are stateless. When the state is combined with the data, the functions become stateless. For example, an order might have a state so that repeated processing of the order transitions it from one state to another while the functions remain stateless.

When a solution comprises of multiple functions, they are often combined into a single function app, but they can also run-in separate function applications. Multiple function applications can also share the same resources by running in the same plan if the Premium and dedicated hosting plan has been selected.  Each function has a memory footprint. When there are many functions in the same application, they might cause the function to load more slowly than for single function applications. Different functions might also have disproportionate requirements and those with excessive usage can be put in their own dedicated function application. Grouping of functions in a function application can also be motivated by load profiles. If one gets frequent messages and another is more resource intensive, then they can be put in separate function applications.

Function applications have a host.json file which can be used to configure advanced behavior of function triggers, and the Azure Functions runtime. Changes to this file can apply to all functions in the application. Organizing different functions based on this configuration will alleviate the operational concerns.

Functions can also be organized by privilege. Connection strings and other credentials stored in application settings need not be given access to all. Those that use them can be put in one function application.

Function scaling depends a lot on managing connections and storage accounts. It is best to avoid sharing storage accounts. Test and production code need not be mixed in the same function app. It is preferable not to have verbose logging in production code because it affects performance.

 

 

 

Wednesday, March 16, 2022

 

Azure Functions:     

This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Functions with the link here. This article continues to discuss Azure Functions best practices with focus on performance and reliability.

Performance and scalability concerns are clearer with serverless function apps. Large long-running functions can cause unexpected timeout issues. Bloating of an application is noticeable when there are many libraries included. For example, a Node.js function application can have dozens of dependencies. Importing dependencies increases load times that result in unexpected timeouts. Dependencies tree can be of arbitrary breadth and length. Whenever possible, it is best to split the function applications into sets that work together and return responses fast. One way of doing this involves HTTP trigger function to be separate from a queue trigger function such that the HTTP trigger returns an acknowledgement while the payload is placed on the queue to be processed subsequently.

State transitions and communications between multiple functions must be managed by Durable functions and Azure Logic applications otherwise a queue can be used to store messages for cross-function communication. The main reason for this is that storage queues are cheaper and much easier to provide than other storage options.

Individual messages in a storage queue are limited in size to 64 KB. Azure Service Bus queues can queue messages up to 256KB in standard tier and up to 100 MB in the premium tier. Use service bus topics when messages need to be filtered. Event subs are useful to support high volume communications.

Scalability is also improved when functions are stateless. When the state is combined with the data, the functions become stateless. For example, an order might have a state so that repeated processing of the order transitions it from one state to another while the functions remain stateless.

Idempotent functions are best recommended for use with timer triggers. This enables retry behavior to be correct. If a function must run once a day, then it can be written such that it can be run any time of the day with the same results. The functions can exit, when there is no work for a particular day. It can also resume if the previous run failed.

Defensive functions are built to handle exceptions. It enables the function to continue from a previous fail point upon next run. Processing that involves a large number of records from a database must handle a variety of faults such as those coming from network outages or quota limits. Tracking the progress of execution is especially helpful under such circumstances.

 

 

Tuesday, March 15, 2022

 Azure Functions:    

This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Functions with the link here. This article continues to discuss Azure Functions best practices with focus on retry and error handling.

When we want code to be triggered by events, Azure Functions become very useful because it is a compute-on-demand experience. It extends the existing Azure App Service platform with capabilities to implement code triggered by events occurring in Azure, in third-party service, and in on-premises systems. Functions can be built to be reactive, but they are also useful to process data from various data sources. Functions are hosted in environments that like VMs are susceptible to faults such as restarts, moves or upgrades. Functions may also have the same reliability as the APIs it invokes. But functions can scale out so that they never become a bottleneck. The previous articles discussed the best practices around security and concurrency. This article continues with some of the other best practices such as availability and monitoring.  

Intermittent failures can be overcome with retries. For example, a database may not be reachable within the limited timeout that is usually set for scripts. Nested commands can be called that might each take their own timeout. Such errors do not occur under normal conditions, so they escape the functional tests. If a limited number of retries were to be attempted, the code executes successfully, and the issue does not recur. Retry also has the side-effect that it reduces the cost of detection and investigation to other spurious errors from logs, incidents and false defects.. 

Error handling practices is important to avoid loss of data or missed messages. The recommended error handling best practices include enabling application insights, using structured error handling, designing for idempotency, and implementing retry policies. For example, the top most level of any function code should have a try catch and tge catch block should log errors.

 

Monday, March 14, 2022

 

This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Functions with the link here. This article continues to discuss Azure Functions best practices.  

When we want code to be triggered by events, Azure Functions become very useful because it is a compute-on-demand experience. It extends the existing Azure App Service platform with capabilities to implement code triggered by events occurring in Azure, in third-party service, and in on-premises systems. Functions can be built to be reactive, but they are also useful to process data from various data sources. Functions are hosted in environments that like VMs are susceptible to faults such as restarts, moves or upgrades. Functions may also have the same reliability as the APIs it invokes. But functions can scale out so that they never become a bottleneck. The previous articles discussed the best practices around security and concurrency. This article continues with some of the other best practices such as availability and monitoring. 

The steps to managing the Function Applications include the following:

1.       A function app provides the execution for the individual functions, therefore, any connection strings, environment variables and other application settings must be tightly controlled for smooth running and scaling. Any data that is shared between function applications must be stored in an external persisted store

2.       The portal is the right place to set the application settings and the platform features. Any number of settings can be added but there are also predefined settings. These settings are stored encrypted.

3.       The hosting plan in which the application runs must be properly chosen to suit the scaling and pricing for one or more function applications.

4.       The eventual migration of a function application between plans must be taken into account as the loads increase and age over time. Only certain migrations are allowed but each migration involves creating a destination plan and deleting the source plan. Forward and backward migrations are permitted in certain cases.

5.       The function access keys are required to support REST calls. The url will be in the format https://<App_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?code=<FUNCTION_ACCESS_KEY> for authorized calls. These keys must be shared with the caller after they are generated from the portal.

6.       The platform features such as App Service editor, Console, Kudu advanced tools, deployment options, CORS, and authentication can be leveraged for operational needs. For example, the App Service editor allows json configuration to be spot edited and it enables integration with the git repository which can trigger the CI/CD pipeline steps. The console is an ideal developer tool to interact with the function application via command line interface. Kudu is an administrator friendly app service administration tool that helps with setting system information, settings and variables, site extensions and HTTP headers. It can be browsed with https://<FUNCTION_NAME>.scm.azurewebsites.net. The deployment center can help automate the deployment from source control. The Cross-origin resource sharing lets an “Access-Control-Allow-Origin” to be declared where origins are allowed to call endpoints on the function application. When functions use HTTP triggers, those requests must be authenticated. The App Service provide Azure Active Directory authentication and allows configuring specific authentication providers.

Sunday, March 13, 2022

 This is a continuation of a series of articles on Azure services from an operational engineering perspective with the most recent introduction to Azure Function core tools with the link here. This article discusses Azure Functions best practices. 

When we want code to be triggered by events, Azure Functions become very useful because it is a compute-on-demand experience. It extends the existing Azure App Service platform with capabilities to implement code triggered by events occurring in Azure, in third-party service, and in on-premises systems. Functions can be built to be reactive, but they are also useful to process data from various data sources. Functions are hosted in environments that like VMs are susceptible to faults such as restarts, moves or upgrades. Functions may also have the same reliability as the APIs it invokes. But functions can scale out so that they never become a bottleneck. The previous articles discussed the best practices around security and concurrency. This article continues with some of the other best practices such as availability and monitoring.

Functions are popular because they can scale out as load increases. Considerations for enabling this scale out are important and these demand that the way the functions respond to load and handle the incoming events be determined. One way to handle parallelism is when the function itself does parallel processing using workers. The FUNCTIONS_WORKER_PROCESS_COUNT setting determines the maximum number of such workers. After this threshold is exceeded, function app is scaled out by creating new instances. When the planning is for throughput and scaling, then the trigger configuration allows us to control the batching behaviors and manage concurrency. Adjusting the values in these options can help each instance scale appropriately. These configuration options are applied to all triggers in a function application, and maintained by the host.json for the application. When we plan for connections, the number for connections on a per-instance basis must be set. This limit affects the Consumption plan and all outbound connections from the function code. 

Availability of Azure functions is impacted by cold start. This is the delay before a new instance of the function is available to process the incoming request. It occurs both when the instances have been scaled down towards zero count and when there are no active instances.  The function becomes ready only when the dependencies are also available. One of the ways to mitigate is turning on the “always on” setting in premium plans of the function app but it is equally important to understand when the scaling occurs. Scaling can vary on a number of factors but those that stand out are maximum instances, new instance rate, and scale efficiency. A function app can scale out to a maximum of 200 instances. A lower value can limit the scaling. New instances can come up at the rate of 1 per second for http triggers and 1 for every 30 seconds for non-http triggers such as Service Bus triggers. Efficiency can be set by using the Manage rights on the resources such as for Service Bus. This can be set in the access policies. The billing for different plans can be found on the Azure Functions pricing page but the usage is aggregated at the app level and only counted for the duration the app was executing and not when it was idle. The units for billing include: Resource consumption in gigagbyte-seconds (GB-s) and Executions. Another way to overcome cold start is to implement a warm-up trigger in the function app. For non-http triggers, a virtual network trigger can be used. When the autoscaling feature is supported as part of the plan, it can be implemented.

Azure Functions offer built-in integrations with Azure Application Insights which monitors function executions and traces written from the code. The AzureWebJobsDashboard application setting must be removed for improved performance and the Application Insight logs must be reviewed. Sampling can be configured to makes sure entries are found in the logs.