Friday, May 21, 2021

 Introduction: This is a continuation of the previous article on Firewalls, Network Virtual Appliances on Microsoft Azure public cloud. There are many choices to make for the appropriate use and security of the services and applications hosted on this public cloud especially given that a variety of devices can be onboarded as products from networking companies.  This article continues the discussion with an emphasis on the Azure TrafficManager.


Description: Endpoints, virtual networks, ip addresses and ports are some of the key assets on which allow/disallow decisions need to be made. The endpoints are best served by the traffic manager because it has a variety of methods to choose from. These methods determine whether a particular endpoint can be allowed or not for the incoming traffic. In certain cases, these can even be diverted which is demonstrated by the program below.


Sample Program to divert traffic:


using Microsoft.Azure.Management.AppService.Fluent;

using Microsoft.Azure.Management.Fluent;

using Microsoft.Azure.Management.ResourceManager.Fluent;

using Microsoft.Azure.Management.ResourceManager.Fluent.Core;

using Microsoft.Azure.Management.ResourceManager.Fluent.Core.ResourceActions;

using Microsoft.Azure.Management.TrafficManager.Fluent;

using Microsoft.Azure.Management.TrafficManager.Fluent.TrafficManagerProfile.Definition;

using Microsoft.Rest.Azure;

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.IO;

 

namespace TrafficManagerZoneDownSimulator

{

    class Program

    {

        static void Main(string[] args)

        {

            var credentials = SdkContext.AzureCredentialsFactory.FromFile(Environment.GetEnvironmentVariable("AZURE_AUTH_LOCATION"));

 

            var azure = Azure

                .Configure()

                .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)

                .Authenticate(credentials)

                .WithDefaultSubscription();

 

            //============================================================

            // Creates a traffic manager profile

            string tmName = SdkContext.RandomResourceName("jsdktm-", 20);

            string rgName = "ravirajamani-test-rg";

            string privateEndpointResourceId1 = "ravirajamani-private-ep-test-1";

            string privateEndpointResourceId2 = "ravirajamani-private-ep-test-2";

            List<string> privateEps = new List<string>() { privateEndpointResourceId1, privateEndpointResourceId2 };

            Console.WriteLine("Creating a traffic manager profile " + tmName + " for the web apps...");

            IWithEndpoint tmDefinition = azure.TrafficManagerProfiles

                    .Define(tmName)

                    .WithExistingResourceGroup(rgName)

                    .WithLeafDomainLabel(tmName)

                    .WithPriorityBasedRouting();

            ICreatable<ITrafficManagerProfile> tmCreatable = null;

            int priority = 1;

            foreach (var ep in privateEps) {

                tmCreatable = tmDefinition.DefineAzureTargetEndpoint(ep)

                        .ToResourceId(ep)

                        .WithRoutingPriority(priority)

                        .Attach();

                priority++;

            }

            var trafficManagerProfile = tmCreatable.Create();

            Console.WriteLine("Created traffic manager " + trafficManagerProfile.Name);

            Console.WriteLine(trafficManagerProfile);

 

            //============================================================

            // Prioritizes endpoints

 

            Console.WriteLine("Enabling endpoint...");

            trafficManagerProfile = trafficManagerProfile.Update()

                .UpdateAzureTargetEndpoint(privateEndpointResourceId1)

                    .WithTrafficDisabled()

                    .Parent().Apply();

            trafficManagerProfile = trafficManagerProfile.Update()

                .UpdateAzureTargetEndpoint(privateEndpointResourceId2)

                    .WithTrafficEnabled()

                    .Parent()

                .Apply();

 

            //============================================================

            // reloads the policy

 

            trafficManagerProfile.Update()

                    .WithProfileStatusDisabled()

                    .Apply();

            trafficManagerProfile.Update()

                    .WithProfileStatusEnabled()

                    .Apply();

 

            // finally

           azure.TrafficManagerProfiles.DeleteById(trafficManagerProfile.Id);

        }

    }

}


x

Thursday, May 20, 2021

Authenticating with Microsoft.Azure Fluent library:

 


Introduction: Many people spend a lot of time figuring out how to authenticate with the Microsoft.Azure fluent library because it is different from the authentication used with its predecessor. In addition, Microsoft libraries for Azure.Identity and Microsoft.Azure.Services.AppAuthentication only complicate the earlier methods. This article tries to cut the chase.

Description: A little bit of context around the earlier method of authentication will help before the description of the new method. This involved instantiating one of the credential class like so:

_tfsDataConnection = new TfsTeamProjectCollection(new Uri(this._tfsLink));

_tfsDataConnection.Authenticate();

By default, it reads the current user and authenticates with that service principal.

The Azure.Identity library was developed to package all the identity related routines into one assembly. We could now use tokens as a form of identity with the help of code like this:

            var aadSettings = new ActiveDirectoryServiceSettings

            {

                AuthenticationEndpoint = new Uri(authSettings.ActiveDirectoryEndpointUrl),

                TokenAudience = new Uri(authSettings.ManagementEndpointUrl),

                ValidateAuthority = true

            };

 

            return await ApplicationTokenProvider.LoginSilentAsync(

                authSettings.TenantId,

                authSettings.ClientId,

                authSettings.ClientSecret,

                aadSettings);

        }

 

The fluent library can accept ApplicationTokenProvider and the new method looks like this:

// Use AzureServiceTokenProvider’s built-in callback for KeyVaultClient

var azureServiceTokenProvider = new AzureServiceTokenProvider();

var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

 

// Request an access token for SqlConnection

sqlConnection = new SqlConnection(YourConnectionString))

{

    sqlConnection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net");

    sqlConnection.Open();

}

 

The Fluent library started recognizing a new primitive for credentials called the AzureCredentials instead of the erstwhile TokenCredentials or DefaultCredentials. Although there is a DefaultAzureCredentials(), the Fluent library does not recognize interactive credentials because of the error cannot convert ‘Azure.Identity.DefaultAzureCredential’ to ‘Microsoft.Rest.ServiceClientCredential’. This calls for a modification to the new methods as follows:

var azureServiceTokenProvider = new AzureServiceTokenProvider(connectionString, azureAdInstance);

var token = await azureServiceTokenProvider.GetAccessTokenAsync(“https://management.azure.com”, tenantId);

TokenCredentials tokenCredentials = new TokenCredentials(token);

Var azure  = Azure

                      .Configure()

                      .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)

                      .Authenticate(new AzureCredentials(tokenCredentials, tokenCredentials, tenantId, AzureEnvironment.AzureGlobalCloud))

                     .WithSubscription(subscriptionId);             

 

Wednesday, May 19, 2021

Availability zones in Azure

Introduction: Region redundant deployment of the public cloud resources are quite popular because it builds resilience and improves availability. However, regions are quite far apart for 2ms latency perimeter. Availability zones are within the same region but distinct from one another. Each zone comprises of one or more data centers. Each region may have three availability zones. These zones maintain synchronous replication, withstand datacenter failures and ensure minimal customer impact. This article describes what it takes to get a service ready for Azure availability zones.

Description: Availability Zones (AZs) are easy to opt into and guarantee 99.99% uptime SLA. Though they sound like Availability sets, the AZs comprise of datacenters with independent power, cooling and networking and the availability sets are logical groupings of virtual machines. AZ is a combination of both a fault domain as well as an update domain, so changes do not occur at the same time. Services that support availability zones fall under two categories: zonal services – where a resource is pinned to a specific zone and a zone-redundant service for a platform that replicates automatically across zones. Business continuity is established with a combination of zones and azure region pairs.

Azure classifies services into three categories - foundational, mainstream and specialized. Service categories are assigned at general availability. They start their lifecycle as a specialized service and as demand and utilization increases, it may be promoted to mainstream or foundational. A specialized service has demand driven ability across regions. It might require customizations.  A mainstream service is one that is available in all recommended regions. A foundational service is one that is available in all regions where the region is generally available. Some examples of services that support zone-redundant services under each of the three categories can be listed as below:

Zone-resilient:

        - Foundational service: Application gateway v2, Cosmos DB, Express Route, Disk Storage, Key Vault, Load Balancer, Service Bus, Service Fabric, Virtual Network, VPN Gateway.

        - Mainstream service: Azure Cognitive Search, Active Directory services, Azure API management, Data Explorer, Firewall, Site recovery, Power BI, Virtual WAN.

        - Specialized service:  OpenShift, Bot Service, Front Door, Managed applications, Resource Graph, Azure Stack, Microsoft Graph, security center and Traffic manager

The availability zones can be queried from SDK, and they are mere numbers within a location. For example: az vm list-skus --location eastus2 --output table will list vm skus based on region and zones. The zones are identified by numbers such as 1, 2, 3 and these do not mean anything other than that the zones are distinct. The numbers don’t change for the lifetime of the zone, but they don’t have any direct correlation to physical zone representations.

There are ways in which individual zone-resilient services can allow zone-redundancy to be configured.

The clients in the sdk for these services have a builder pattern where there is an option to specify the redundancy rules as well as a supported region via the location parameter.  Resources can also be requested to be created in a zone redundant service at a specific location by mentioning a supported region where the availability zones are present. This might entail other resources to be collocated in the same region.

Tuesday, May 18, 2021

 

Comparisons between Azure Firewall and Traffic Manager.

Introduction: There are competing techniques available from Microsoft Azure all of which allow traffic between the Azure resource to be managed. This article discusses some of those options.

Description: There are two networking technologies to assist with this purpose that we evaluate here. They are Azure Firewall and traffic manager. A firewall is not just a virtual machine or a router, it is also offered as a Firewall-as-a-service. When it is in the form of a virtual machine or a router, it is referred to as a Network Virtual Appliance in the Azure parlance. The ability to deploy an NVA or a router is probably the most flexible way to manage traffic rules at the IP layer simply because it acts as a man-in-the-middle.  The traffic manager offers out-of-box capabilities but it is not the same as what an NVA can provide. This has the flip side that it might be overkill and more advanced than it needs to be. Azure Firewall provides a specialized service in this regard. It is a cloud-native security service that distinguishes it from a traditional NVA by offering its cloud-native security service as a stateful network and application-level service also known as firewall as a service. Firewalls can easily be configured with REST-based APIs.

 

The traffic manager supports six routing methods based on priority, weighted, performance, geographic, multi-value, and subnet. Only one method can be specified at any time. The weighted routing method serves very well for the purpose of simulating zone-down because it can use DNS and weights to divert traffic. The default weight is 1. The higher the weight, the more frequently that endpoint is used.  The status of an endpoint can reflect whether it is downgraded. Within a region, a nested traffic manager profile may be needed. The Internet latency tables will continually change, so assigning a higher weight to a diversion in all cases will help. All traffic managers have health monitoring and automatic failover of endpoints. 

Some services allow the virtual networks to be defined in terms of address range and prefix. By switching the virtual networks, the traffic handled by the service can be diverted.

For example,

Monday, May 17, 2021

 Problem statement: Find the maximal sum of elements in a rectangular region of an integer matrix 

Solution:  

    public static int getMax(int[][] A) {

        assert (A != null && A.length > 0 && A[0].length > 0);

        int result = 0; // maximum profit of a rectangle

        int M = A.length;

        int N = A[0].length;

        if (M > N) {

            // transpose

            int[][] A1 = new int[N][M];

            for (int j = 0; j < N; j++) {

                for (int i = 0; i < M; i++) {

                    A1[j][i] = A[i][j];

                }

            }

            A = A1;

            M = A1.length;

            N = A1[0].length;

        }

        int[][] sum = new int[M+1][N+1];

        for (int i = 1; i < M + 1; i++) {

            for (int j = 1; j < N + 1; j++) {

                sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + A[i-1][j-1];

            }

        } 

        for (int i1 = 0; i1 < M; i1++) {

            for (int i2 = i1+1; i2 < M+1; i2++) {

                // region init

                int min1 = 0; // minimum value of a rectangle [i1..i2-1]x[0..j-1]

                int minJ1 = 0; // minimum for such j when minimum in one dimension using a formula like that for sum but in one dimension

                // sum'[j] = sum[i2 + 1][j] - sum[i1][j]

                int maxValue1 = 0; // maximum value of a rectangle [i1..i2-1]x[j'..j-1]

                int max1 = 0; // maximum value of a rectangle [i1..i2-1]x[0..j-1]

                int maxJ1 = 0; // minimum such j

 

                int minCost1 = 0; // minimum value of a rectangle [i1..i2-1]x[j'..j-1]

                int min2 = 0; // minimum value of a rectangle [0..i1-1, i2..M-1] x [0..j-1]

                int minJ2 = 0; // maximum such j

 

                int maxValue2 = 0; // maximum value of a rectangle [0..i1-1, i2..M-1] x [j'..j-1]

                int max2 = 0; // maximum value of a rectangle [0..i1-1, i2..M-1] x [0..j-1]

                int maxJ2 = 0; // minimum such j

 

                int minCost2 = 0; // minimum value of a rectangle [0..i1-1, i2..M-1] x [j'..j-1]

                // endregion init

                for (int j = 1; j < N+1; j++) {

                    int value1 = sum[i2][j] - sum[i1][j];

                    min1 = Math.min(value1, min1);

                    minJ1 = (value1 == min1)? j : minJ1;

                    maxValue1 = Math.max(value1 - min1, maxValue1);

                    max1 = Math.max(max1, value1);

                    maxJ1 = (max1 == value1) ? j : maxJ1;

                    minCost1 = Math.min(minCost1, value1 - max1);

                    int value2 = sum[M][j] - value1;

                    min2 = Math.min(min2, value2);

                    minJ2 = (min2 == value2) ? j : minJ2;

                    maxValue2 = Math.max(maxValue2, value2 - min2);

                    max2 = Math.max(value2, max2);

                    maxJ2 = (max2 == value2)  ? j : maxJ2;

                    minCost2 = Math.min(minCost2, value2 - max2);

                    result = Arrays.asList(result, maxValue1, maxValue2, value1 - minCost1, value2 - minCost2).stream().mapToInt(x -> x).max().getAsInt();

                }

            }

        }

        return result;

    }


    public static void main(String[] args) { 

        int[][] A = new int[2][2]; 

        A[0][0] = 1; 

        A[0][1] = 1; 

        A[1][0] = 1; 

        A[1][1] = 0; 

        System.out.println(getMax(A)); 

3 // output


Sunday, May 16, 2021

 Writing a Python Flask application to serve content over https. 

 

Problem statement: Python Flask is a framework that serves web API over HTTP. Their documentation suggests running the server over HTTPS so that clients can send requests and receive responses securely. This article is a blog post to describe how to do that. 

Solution:  A Flask application takes command line input parameters in the form: 

python3.5 run -m flask --port=8443 --host=0.0.0.0 --cert=cacert.pem --key=privkey.pem 

This should start the server to serve over https. 

There are a few caveats.  

First, the certificate requested must be trusted for it to be universally accepted by browsers, clients, and mobile device platforms. Getting a trusted certificate from a certificate authority is a well-documented procedure but the input parameters to that method are just as relevant and prone to mistakes as they are to the command line invocation shown above. 

The hostname registration parameter for the certificate request must match that of the server. It is better to use a fully qualified domain name that is registered with name servers so that can be resolved from anywhere in the world. If the server hosts multiple applications, then the certificate is issued to the server and may be trusted for one app but not the other. This is a commonly encountered situation and is resolved in one of two different ways: 

The first way is to use different certificates to be passed in via the command line arguments and each of those certificates points to unique endpoint names for their corresponding applications. These names have alias records in nameservers, so they are mapped to the IP address of the host.  

The second way is to use subdomains within the host endpoint and have a wild card certificate issued for all subdomains from that server registered with the certificate request.  This certificate allows any application to be reached if there is a partial match with the domain part of the subdomain inclusive fully qualified domain name. 

Once the certificate is trusted, the mutual authentication between client and server kicks in and the request-responses work seamlessly over the internet just as if it were over HTTP.  

The use of untrusted certificates is possible but not universally accepted because the untrusted certificates require to be permitted by the host and runtime of the client applications. Even the server host and runtime might demand exclusions and overrides to the security check with the use of untrusted certificates. A certificate helps with the encryption of traffic, so an untrusted certificate may pass for this task as much as a trusted certificate but the default security settings on client and server may warn or reject its use. This might be an option for development use but not for production use because the former control both the client and the server, but the latter can only secure the server. 

Finally, the method to generate a certificate request is facilitated with the use of standard cryptographic tools such as OpenSSL and involves generating a public key and a private key to make a certificate request. 

The invocation for Django applications is: 

django-admin runserver --host=0.0.0.0 runserver --certfile cacert.pem  --keyfile privkey.pem 

If a reverse proxy for HTTPS is configured on the host, running a server with HTTPS is unnecessary 

 

Saturday, May 15, 2021

 

Question: Find the maximum rectangle enclosed by the following barchart:

                                       ____

12 |                               |      |

10 |                               |      |

  8 |           ___              |      |-----

  6 |   ___|     |      ___|              |___

  4 |  |    |       |__|                              |____________

  2 |  |    |             |                                                           |

  0  --------------------------------------------------------------------------

Solution: public class Main {

    public static void main(String[] args) throws Exception {

        List<Integer> A = Arrays.asList(4, 6, 2, 4, 12, 7, 4,2,2,2);

        System.out.println(getMaxRectangleStreaming(A.stream());

    }

    public static int getMaxRectangleStreaming(BaseStream<Integer> stream) {

        int maxArea = Integer.MIN_VALUE;

        int maxHeight = Integer.MIN_VALUE;

        List<Integer> heights = new ArrayList<>();

        // parallel sums of unit-areas of bounding boxes with top-left at incremental heights of the current bar in a barchart

        List<Integer> areas = new ArrayList<>();

        int prev = 0;

        Iterator<Integer> iterator = stream.iterator();

        While(iterator.hasNext()){

            Integer a = iterator.Next();

            if (a > maxHeight) {

                maxHeight = a:

            }

            if (prev < a) {

                for (int j = 0; j < a; j++) {

                    if (heights.size() < j+1) heights.add(0);

                    if (areas.size() < j+1) areas.add(0);

                    heights.set(j, (j+1) * 1);

                    if ( j < areas.size()) {

                        int newArea = areas.get(j) + (j + 1) * 1;

                        areas.set(j, newArea);

                        if (newArea > maxArea) {

                            maxArea = newArea;

                        }

                    } else {

                        areas.set(j, (j+1) * 1);

                    }

                }

            } else {

                for (int j = 0; j < a; j++) {

                    heights.set(j, (j+1) *1);

                    if ( j < areas.size()) {

                        int newArea = areas.get(j) + (j + 1) * 1;

                        areas.set(j, newArea);

                        if (newArea > maxArea) {

                            maxArea = newArea;

                        }

                    } else {

                        areas.set(j, (j+1) * 1);

                    }

                }

                for (int j = a; j < prev; j++){

                    heights.set(j, 0);

                    if (areas.size() > j && areas.get(j) > maxArea) {

                        maxArea = areas.get(j);

                    }

                    areas.set(j, 0);

                }

            }

            prev = a;

            System.out.println("heights:" + print(heights));

            System.out.println("areas:" + print(areas));

        }

  

        return maxArea;

    }

    public static String print(List<Integer> A){

        StringBuilder sb = new StringBuilder();

        for (Integer a : A) {

            sb.append(a + " ");

        }

        return sb.toString();

    };

}

 

//Output:

heights:1 2 3 4

areas:1 2 3 4

heights:1 2 3 4 5 6

areas:2 4 6 8 5 6

heights:1 2 0 0 0 0

areas:3 6 0 0 0 0

heights:1 2 3 4 0 0

areas:4 8 3 4 0 0

heights:1 2 3 4 5 6 7 8 9 10 11 12

areas:5 10 6 8 5 6 7 8 9 10 11 12

heights:1 2 3 4 5 6 7 0 0 0 0 0

areas:6 12 9 12 10 12 14 0 0 0 0 0

heights:1 2 3 4 0 0 0 0 0 0 0 0

areas:7 14 12 16 0 0 0 0 0 0 0 0

heights:1 2 0 0 0 0 0 0 0 0 0 0

areas:8 16 0 0 0 0 0 0 0 0 0 0

heights:1 2 0 0 0 0 0 0 0 0 0 0

areas:9 18 0 0 0 0 0 0 0 0 0 0

heights:1 2 0 0 0 0 0 0 0 0 0 0

areas:10 20 0 0 0 0 0 0 0 0 0 0

20