Handling configuration settings for environments/ development stages is not always easy and straight forward. Application characteristics, platform capabilities, business and security requirements are different per system you build and release.

Although all application differ it is always good to have guidance. Guidance in the form of guidelines, practices and opinions that worked and are adopted in projects will provide a consistent, flexible and secure way of working.

Levels.

Following general guidelines and common practices will help to keep systems flexible and secure. It is nog always possible or needed to follow them strict and in details, there are different ‘way of working’ levels each with its tradeoff. It is good to recognize which way of working your project and organization requires.

Three levels of application settings implementation each follows several guidelines and practices more or less. Level 3 follows the guidelines most.

Settings set by system admins. Manual maintained and set.

Settings set during release. Set and maintained via the CICD pipeline.

Settings captured at runtime. Set by resources, captured and used during runtime.

Guideline and Practices.

Configuration settings should be stored and maintained as close as possible to the environment they apply to.

Storing application settings close to the application makes it clear where these settings belong to. From a security point of view the settings can only be accessed and changed from that environment, mainly for production settings like connection strings and passwords this is required.

For example, application specific settings should be set next to the code or in the root of the application. Platform specific settings should be available at a higher level, for example in Environment Variables and in the webserver settings, which are in the root of the webserver no website specific settings should be available. As an example, the ApplicationHost.config is the root file of the configuration system when you are using IIS 7 and above. It includes definitions of all sites, applications, virtual directories and application pools, as well as global defaults for the web server settings (similar to machine.config and the root web.config for .NET Framework settings).

Configuration settings contain only environment specific settings.

To keep the settings files small and easy to understand they only should contain environment specific settings (cache, logging, connection strings etc). All other settings should live and be able to set in the application itself.

Configuration settings are NOT stored under version control, specially not secrets.

From security point of view, it is not allowed to store any environment specific setting under version control (passwords, connection strings, tokens, etcetera). These values can’t be stored in version control, they should be set and stored as close to the environment they belong to and accessible with a ‘just in time’ mindset.

There is only one location where application settings are configured.

Configuration settings should be set as close to the application it needs. When application settings can be configured at more locations, it will result in choas and unsecure maintenance.

Configuration values are automatic set.

With multiple environments and multiple settings to be set is advisable to make this happen automatically during deployment. The process will be repeatable and less faults wil happen.

A change in configuration setting shouldn’t require a new deployment.

Most often an application resource (for example a web application) relies on a core resource (for example a storage account). An application resource is depended on the existence of this core resource and needs its settings to run properly. For example, a web application needs a storage account key to access a blob storage, or a frontend needs an url and token address to access an API.

Changes in the core resource and it settings shouldn’t result in a redeploy of the application resource which relies on it. When an API has many unknown clients changing the url shouldn’t impact these clients. This can be challenging but there are many solutions for it.

Implementation example with Net Core, VSTS and Azure.

An implementation with a Net Core 1 MVC Web Site hosted on Azure Web Apps released with Visual Studio Team Services.

In theory, it doesn’t matter which tools, which platform and which language is used as long as the guidelines and principles are followed for now an example with Net Core.

Net Core applications and websites can use configuration settings from multiple resources via configuration providers. For environment, specific settings the JSON Configuration Provider is the most common available.

Within Visual Studio this environment variable can be set via the Application properties screen.

Via a PowerShell for Windows or Bash for Linux command the environment can be set.

When you use the JSON Configuration Provider for Appsettings in Net Core applications you already can follow several guidelines and practices:

Settings are set and available close to the environment they are used. One point of attention is that all settings from all environments are available in all environments when you simply just copy the package directory created by ‘dotnet package’, you don’t want production settings available in the development environment. A build pipeline can solve this.

There is only one location where the settings are set. As long as you don’t start using web.config or applicationhost.config files when hosted on iis, or when you put them in a database, or anywhere else. It is something that requires some discipline from the team and need to be validated by code reviews or build tasks.

And, when you don’t put other info in the appsettings json, the settings only contain environment specific settings, this also requires some team discipline, a proper branching strategy will help.

Secrets in settings

The challenge with the appsettings.{env.EnvironmentName}.json files is that they live in the solution. So, don’t put any secrets in it or don’t put them under version control (.gitignore is your friend) or leave them blanc and set them at another time during the release.

Azure Web App Settings.

Another way, next and together with appsettings.{env.EnvironmentName}.json is make use of the Azure Web App Settings or Environment Variables. As mentioned in this post the appsettings can be overridden by Azure Web App Settings or Environment Variables.

Make sysadmin responsible to set and maintain these setting in production (level 1) is not recommended, better to make it automated (level 2).

So, normal environment specific settings can be set in appsettings.{env.EnvironmentName}.json, like caching, logging etc. but settings which contain secrets, tokens, connection strings shouldn’t. let them either be set by the release pipeline in the Web App Settings or Environment Variables.

Release pipeline.

There are release tools where you can store secrets in the pipeline. VSTS even has a way to secure them per stage via Azure Active Directory, from there update the Web App Settings in the pipeline with a PowerShell task or you can takes this nice custom build task.

Still you need to update and maintain the secrets yourself or an admin in the release tool, still a manual maintenance activity which can and will go wrong. What if a redeploy of the whole system changes locations, connection strings and tokens, you have to walk through all secrets in your pipeline configuration to update them.

Better to let the systems store their secrets in a known location and let the pipeline grab them from there to update the Web App Settings or Environment Variables during deployment. For example, when a database is created let it store its connection string on a known place which can be accessed by the pipeline, or a storage account its keys, or a system it’s tokens. The pipeline doesn’t have to know the secrets only the location where they can be found and where they need to be set.

Vault.

A way to accomplish this ‘trusted storage of secrets’ in a secure way is make use of a vault, something like Azure KeyVault, AWS Parameter Store or HashiCorp Vault or any other secure store solution. During release of the system let, with Azure done via ARM templates, them store their secrets in this vault.

Give the pipeline access to the Azure KeyVault via a principle account in Azure Active directory and via a nested ARM template it can update the Web App Settings for all stages and from any Azure KeyVault.

Already following some more guidelines and practices:

Configuration values are automatic set.

A tradeoff is that you now have to redeploy the WebApp when the other systems change and a tradeoff is that the secrets are stored in plain text when set in Web App Settings or Environment Variables.

Microsoft Azure Key Vault configuration provider

Any secure storage is an option to store secret appsettings. Net Core has a next to the plain simple JSON Configuration Provider also a Microsoft Azure Key Vault configuration provider(you also can create your own provider if you want to use other secure stores).

For using the Azure Key Vault for storing and retrieving you need to create the Azure Key Vault, register you WebApp to Azure Azure Directory and add the WebApp as trusted party to the Azure KeyVault. You need to store the WebApps AAD ClientId and ClientSecret in the appsettings.{env.EnvironmentName}.json files or you can use a certificate to make a trust between WebApp and KeyVault. When this configuration is done the application takes the secrets from the vault at runtime every time it needs it. Let the secrets be stored and update by the systems they belong to, as described in the previuous paragraph and the settings will update itself.

It makes our system follows another guideline:

A change in configuration setting shouldn’t require a new deployment

Closing.

Not every system needs to follow all guidelines, using AAD, a KeyVault and stich everything together can be a bit too much sometimes. Keep an eye and understand the reasoning behind these common and proven guidelines and principles and know which you adopt for your system is a good step.

With the multi cloud trend you see happening at this moment understand and adopting guidelines will improve and mature your usages of different platforms, tools and languages in a consistent way.