March 2nd, 2021

Creating Azure Solutions with the new Azure SDKs, F#, and Farmer

Isaac Abraham
Founder

Deployment and configuration of infrastructure and code into Azure can be challenging – especially when it comes to following best practices in areas such as repeatability and security. However, it doesn’t have to be this way. In this post, I want to focus on three areas that help us fall into the “pit of success” when it comes to simple, secure, and repeatable deployments of .NET applications and Azure infrastructure.

1. New Azure SDKs

One of the biggest changes happening right now for .NET developers on Azure is the complete re-design of many of the core Azure SDK libraries. One of the new additions is a self-contained library designed specifically for identity, Azure.Identity.

2. Type-safe and powerful Azure provisioning

.NET developers now have the ability rapidly create ARM templates in an easy-to-understand DSL through the Farmer project, which allows you to safely, quickly, and succinctly create, configure, and deploy entire Azure topologies using trusted Microsoft technologies such as ARM Templates and the Azure CLI.

3. Cross platform, high performance functional programming

Many of the newest developments in .NET (such as .NET Core, .NET 5 and recent versions of ASP .NET Core) have enabled F# developers to write high-performance cross-platform web applications whilst still taking advantage of all of F#’s features that enable the rapid development of safe, simple, and maintainable code.

Securely creating and connecting Azure services with Farmer

Let’s take a common scenario: an ASP.NET web application that reads blob data from an Azure Storage account. How do you deploy and configure the web application to securely access the storage account?

There are a myriad of ways to achieve this, from storing the connection string directly in your application’s source code (please don’t do this!), to storing it in the Azure Website’s application configuration settings (possibly combined with ASP.NET’s new settings library) or even within an external service such as Key Vault.

Yet another alternative is to simply not use secrets at all! Instead, a Storage Account can grant permissions to a web application identity. This provides many benefits, such as the ability to provide fine-grained access to individual applications and accounts, as well as revoke permissions without requiring any modification to client applications.

From a resource perspective, setting a permission in this fashion is trivial using Farmer:

let myWeb = webApp {
    name "isaacswebapp"
    // turn on the system identity for the web application
    system_identity
}

let storage = storageAccount {
    name "isaacsstorageaccount"
    // grant the role of blob read reader to the web app's system identity on the storage account
    grant_access myWeb.SystemIdentity Roles.StorageBlobDataReader
}

Farmer is a relatively simple DSL that runs on .NET whose goal is to be the easiest way to create repeatable Azure deployments. In this case, we create a web application and storage account, and then tell Farmer to grant the Storage Blob Data Reader permission to the web application.

There are actually a number of different ARM resources that need to be created behind the scenes here, including activating the system identity principal for the web app, but also creating a role assignment that links the identity to the storage account using a “pre-defined” GUID for the StorageBlobDataReader role.

If all that doesn’t sounds like much fun, that’s because it isn’t. Thankfully, Farmer does all the heavy lifting for us, constructing the appropriate ARM resources, permissions, and dependencies as required (all with strong typing and intellisense!).

Securely accessing Azure with the new Azure SDKs for .NET

Once you’ve created your Azure resources, you still have to access your storage account within code. Previously, this might have been a challenge to do, but the new .NET Azure Identity library has been designed to work with a number of different services, including Storage, out of the box:

open Azure.Identity
let blobClient =
    let accountUri = Uri "https://isaacsstorageaccount.blob.core.windows.net"
    BlobServiceClient (accountUri, DefaultAzureCredential ())

The DefaultAzureCredential is a flexible abstraction designed to work with a number of different credential mechanisms such as environment variables and system identities, without any custom arguments.

All this means that we can start to write applications that have no need for secrets at all, yet still can be secured at a granular level.

Accessing the new Azure SDKs from F#

As a standard .NET library, we can access the BlobServiceClient in F# naturally:

// print out the names of all blobs in all pages in the "data" container
for blobPage in blobClient.GetBlobContainerClient("data").GetBlobs().AsPages() do
    for blobItem in blobPage.Values do
        printfn "%s" blobItem.Name

The new Azure SDK client libraries are lightweight, follow a consistent pattern and are easy to consume in F# within either full-blown applications or exploratory scripts. For the growing number of F# developers it’s great to see that these new SDKs work seamlessly from F#, and are simple to consume without requiring heavyweight constructs such as inheritance.

Tying it all together

To illustrate how you might turn this all together in a single application, we’ve constructed a basic ASP.NET web application and Farmer template here for you to experiment with.

The web application connects to an Azure storage account account using the aforementioned Azure SDK and renders a table of the contents of the blobs in a specific container. The application in this case also happens to be in F#, but there’s no requirement for that – this could be a C# ASP.NET MVC app, or a NodeJS web app etc.

From a fresh clone, and with zero existing infrastructure, it will securely provision, configure and deploy the ASP.NET web application into Azure with no hard-coded storage account names and no secrets (hard coded or otherwise) anywhere, at any time!

Remember that although Farmer wraps many concepts into a simple domain-specific language (DSL), behind the scenes it uses standard ARM templates and the Azure CLI for all deployment orchestration tasks, and is just a standard NuGet library running on netstandard2.

Summary

It’s an exciting time for developing cloud native applications in .NET and Azure. .NET 5 has launched, providing improved capabilities and performance; the evolution of .NET Azure libraries provides a consistent and lightweight approach to accessing services, whilst F# and libraries such as Farmer provide an excellent way to rapidly create applications and their required services. Bring them all together and it starts to become much easier to building, configuring and deploying performant, high quality and secure applications in Azure.

Azure SDK Blog Contributions

Thank you for reading this Azure SDK blog post! We hope that you learned something new and welcome you to share this post. We are open to Azure SDK blog contributions. Please contact us at azsdkblog@microsoft.com with your topic and we’ll get you set up as a guest blogger.

Azure SDK Links

Author

F# MVP, .NET and Azure consultant. Author of "Get Programming with F#". Founder of @compositionalit

0 comments

Discussion are closed.