Bus Factor Mitigation

Heads Up!

This article is several years old now, and much has happened since then, so please keep that in mind while reading it.

With the release of Umbraco 9, there have been some conversations around how easy and quick it is to start a new Umbraco site. There’s even a video related to this.

That’s all pretty cool for the first person who sets up the site for a new project, but the reality is that the rest of the developers who will work on the project are more forgotten than the second page of Google.

Disclaimer: There are many ways of dealing with the following issues and everybody has a different approach or tools they use to overcome them. For example, you can store your secrets in different ways, even as environment variables. The goal of this article is to find the path of least friction.

The problem

When a new developer starts working on a project that is already underway, they need access to a bunch of resources to get the site up and running on their local machine. All those resources need to be retrieved and configured in specific ways to have a working site that a developer can start coding on. I have classified these resources into a few categories and each one needs a different approach to be shared with the involved developers.

Code

Someone has to tell you where to find the code for your project. We can’t get around this. 

Database

The second most important resource on a Umbraco site is the database. Your site won’t run without one. When you install a new site, one solution is to get a working database copy from one of the developers already working on the project. But what if they are not available? Do we have a second contact? We also need to be sure that the database is up-to-date with the latest doctypes and content.

Media

Media files are those files, like documents, images or videos, that are part of the content of the site and not actual design assets. Because these files are not part of the solution and don’t need to be source controlled, they shouldn’t be included in the repository along with the rest of our code. Many times, those files are missing when you install a project on your computer for the first time and you need to ask a developer to give you those files in order to render the pages properly on your local machine.

Credentials

Another wall I sometimes hit on new projects is not having access to the back office for the first time. Sure, you can ask another developer, or you can even try to restore the admin password. The other option is to have a company-wide enterprise-level password management system.

Secrets

What about other types of settings like API keys or passwords? Surely, you are not storing those on the web.config and pushing them to the repo, right? Right!? 🙈

As you can see from the points above, there’s a bottleneck here. We will always need someone to help us set up  an existing project on our local machine.

 

Making the site self-sufficient

The goal of this article is to find, which collection of techniques and tools we can use to make a Self-Sufficient Umbraco Site (SSUS, just because everything sounds cooler with acronyms).

I’m going to define SSUS as:

A site, that once we have the code, we can run it on our computer without the involvement of another person.

Code

There are many services that offer source code repositories where you can upload your code. GitHub, Bitbucket, and Gitlab are a few of the most commonly used. To access these services you usually need a username and password or you can use other types of credentials like SSH keys. The best way of accessing this without the help of others is having access to proper documentation that describes where and how to access the code. At Luminary, each project has a playbook and a dedicated confluence page which makes this easier for us.

Database

Of course, the most basic solution to grab a copy of the database is getting someone to give you one. But there are some other techniques that can help us to have a working database without having a backup.

Unattended Install

Umbraco ships with one great feature called Unattended Install. When you configure and enable this option, the Umbraco site will install itself without stopping to ask for any details. These details can come pre-configured in the project’s appsettings.json file, or via environment variables. If the credentials are on the appsettings file it will be a good idea to modify them after the installation is done. Probably configuring these details as environment variables instead sounds like a more secure way. Take a look at the Umbraco docs to see all the available options when you create your project.

This step, apart from installing a fresh new Umbraco database, will also create the admin user with the given credentials. This will effectively spare us from hounding anyone to give us the credentials to log into the back office (sweet!).

LocalDB

LocalDB is a lightweight SQL server that runs on request instead of as a service. This uses less of the computer’s resources. I strongly recommend you use this type of server, instead of SQL Express, for example. As an added benefit, when you run the unattended install and use LocalDB, it will create the database on the fly for you automatically if it doesn’t exist, so you don’t need to create the database beforehand.

Structure and content

At this point, we would have an empty database. We will need to restore all our site’s data like doctypes, data types, or content. To help us with this, we have chosen the amazing uSync. uSync can export all of our Umbraco content and data into files that we can push to our repo. It’s out of the scope of this article to explain how to use uSync, but the website has some easy to follow instructions.

Media

The best way I have found to share media items without relying on someone else is to use Azure Storage. Multiple developers running the same site can share the same Azure Storage account. To configure your site to use Azure Storage, you can follow these instructions. Having the media in a shared location frees us from having to include them in our repositories or sharing zip files with other people.

Secrets

With the previous steps, you should be able to get a site up and running. This is true if you don’t have any external integrations, but we all know this is normally not the case. Our sites most of the time have external dependencies like keys, passwords, or any other secure dependency you can think of. These types of secrets shouldn’t be stored in our repositories. Even if our repos are private, there’s always the risk of someone getting access to them and all the information about our sites.

Azure Vault

There are a few techniques to store these secrets. For our SSUS, we don’t want to depend on other developers or managers to give us those secrets. The best solution to solve this is to use something like Azure Vault. Vault stores your secrets on the cloud and they can only be accessed through proper authentication. On Azure, this authentication is provided by Active Directory (AD).

At Luminary, this is very convenient, as we have all our internal resources protected by AD. So having access to a shared Azure Vault is a no-brainer. In our case, we would create a Vault for our project and store all the secrets in it. Then we would give read and write access to the AD team that is going to work on the project. This way, any user belonging to that team would have access to the secrets straight away. In order for our site to grab those secrets, either from our local machine or from a web app, we need to configure it in a certain way that will make it run in both environments.

Creating the Key Vault

First, you will need to create a Key Vault in Azure

Once you have that, you will need to create your secrets in there.

Be sure that you properly configure your access policies and give permission to read your secrets to the right users or groups.

 

Managed Identities

The recommended way of accessing protected Azure resources is using ‘Managed Identities’. Managed Identities allows a ‘source’ resource to access a ‘target’ resource without needing to use any credentials. When you have your Vault protected with Managed Identities, your app will try to authenticate using your Visual Studio account if you are running the app for development or, a system-managed or user-managed identity if you are running the app from a different environment, like a WebApp.

I’m going to show you quickly how to set up your local environment to connect to a protected Key Vault. There are more in-depth tutorials out there, but this should give you the main steps to start off.

Creating the Managed Identity

There are two types of Managed Identity:

  • System-assigned: belongs only to a resource, for example, the web app, but it cannot be used to authenticate any other resource. This is deleted if the web app is removed.
  • User-assigned: can be shared between different resources, for example, the web app and an Azure Function.

To stay within the scope of this article and because we are running the site locally, our identity is validated by our AD account. So, we don’t need to create a managed identity.

Accessing the secrets

Now that we have our secrets in a secure place, we need to be able to access them from our Umbraco site. To be able to access your secrets you will need to install Azure Identity which comes as a NuGet package. This will offer the required classes to identify yourself.

Also, you will have to install the client to access the Key Vault. This comes in another NuGet package.

Once you have these two libraries installed, the code to access your secret goes like this:

public class InitSecrets : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        var vaultUri = builder.Config["vaultUri"];
        var client = new SecretClient(vaultUri: new Uri(vaultUri), credential: new DefaultAzureCredential());
        var secret = client.GetSecret("mykey");
    }
}

As you can see in the example, we need our vault URI. You can get this value from your Key vault:

 

 

For testing purposes, I have used a Composer to grab my secret, but this is not the recommended approach!

You could use the IOption interface, following the Options pattern, and inject your settings where you are going to need them or register some type of service that has access to those secrets. That’s totally up to you. 

If you intend to host your app on Azure, the preferred way of authenticating is using the DefaultAzureCredential of this library. When we use this, the app will fall back between different ways of authentication until it finds a suitable one.


Awesome! Now all the devs can access the secrets without having to share any files, which would be a big security risk. The vault URI can be a part of the codebase and checked in to source control. Only authorized users or team members can access the key vault.

Conclusion

When starting to work on an existing project that another developer has already installed, it’s not always very straightforward to get all the required resources to have the site running locally.

We have seen that there are a few key areas where we will need assistance from someone else to provide some required assets. We have identified those areas as code, database, media, credentials, and secrets.

We have defined a Self-Sufficient Umbraco Site (SSUS) as a site that is configured in a certain way, following some techniques and using external tools to potentially allow a developer to run a site locally without any external assistance.

This article offers a potential solution but it is not the only possible solution. The most important part is identifying that we have a problem, and finding ways to overcome that problem.

Hopefully, this opens a discussion around the topic and we can identify other approaches collaboratively.

 

Thanks to Emmanuel Tissera from Luminary for the idea which lead to this article.

Mario Lopez

Mario is on Twitter as