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
- Azure SDK Website: aka.ms/azsdk
- Azure SDK Intro (3 minute video): aka.ms/azsdk/intro
- Azure SDK Intro Deck (PowerPoint deck): aka.ms/azsdk/intro/deck
- Azure SDK Releases: aka.ms/azsdk/releases
- Azure SDK Blog: aka.ms/azsdk/blog
- Azure SDK Twitter: twitter.com/AzureSDK
- Azure SDK Design Guidelines: aka.ms/azsdk/guide
- Azure SDKs & Tools: azure.microsoft.com/downloads
- Azure SDK Central Repository: github.com/azure/azure-sdk
- Azure SDK for .NET: github.com/azure/azure-sdk-for-net
- Azure SDK for Java: github.com/azure/azure-sdk-for-java
- Azure SDK for Python: github.com/azure/azure-sdk-for-python
- Azure SDK for JavaScript/TypeScript: github.com/azure/azure-sdk-for-js
- Azure SDK for Android: github.com/Azure/azure-sdk-for-android
- Azure SDK for iOS: github.com/Azure/azure-sdk-for-ios
- Azure SDK for Go: github.com/Azure/azure-sdk-for-go
- Azure SDK for C: github.com/Azure/azure-sdk-for-c
- Azure SDK for C++: github.com/Azure/azure-sdk-for-cpp
0 comments