I have a requirement to not store any sensitive information (e.g. usernames and passwords) in source control. We are doing a .NET 4.5 MVC app so my plan was to encrypt the web.config using the aspnet_regiis.exe and the built in functionality of ASP.NET. I have no problem getting this to work here but the issue I am having is that I would also like to encrypt the transforms (Web.Release.config, etc.) because that also contains the sensitive information. I have looked around and not seen any way to do this. Does anyone know a way to accomplish this?
7 Answers
You can keep your production transform file in a secrets repository that only your ops team can access. Your CI system would reference both repos and copy the transform file from your secrets repo to your build directory and compile as you do now.
This would remove any sensitive config values from your primary repository and still allow your to leverage the transforms capabilities.
Try following, I have just given the example of protecting connection string. Replace the tag you want to replace using System.Configuration;
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = modulePath + "Web.Release.config";
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
System.Configuration.ConfigurationSection section = config.GetSection("connectionStrings");
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
config.Save();
}
There are a couple different ways of handling this depending on you're needs and the different types of access that you and your development team have to the servers.
Option 1. Check in encrypted transforms files to source control.
Create your web.config and encrypt the appsettings and connectionstrings using aspnet_regiis.exe. Then in your transform (ex. web.release.config) for each environment use the following values:
<appSettings configProtectionProvider="ProviderName" xdt:Transform="Replace">
<EncryptedData>.....</EncryptedData
</appSettings>
If you are using different providers in each environment (you should be), then you will need to do the encryption for each environment.
Problem: If you have multiple developers/projects going on, it can be easy to miss a new appsetting value and you won't know until its deployed
Option 2. Use Transforms + Token Replacement and Encrypt in place on the server
For this option you would use your traditional transforms, but replace all sensitive data with tokens, such as {{WebServicePassword}}. Token replacement is a common functionality that exists in most deployment tools. In this case you would create a variable in your deployment tool (VSTS, UrbanCode, etc..) that has the true value of {{WebServicePassword}}. You would then need to configure your deployment to do a tokenized replacement and the specific details of this would differ base don the deployment tool in question. Once the file is deployed, then run the aspnet_regiis.exe remotely on the server to encrypt the web.config file in place.
Problem: The unencrypted file will be sitting on the server for a brief moment before it is encrypted. Depending on your situation, this may or may not be an issue.
Personally I prefer option #2 as it allows you to see all of the appsettings keys and you can easily handle changes to keys (not the values) through pull requests/code reviews. When dealing with the encrypted appsettings/databaseconnections values in source control, you have no idea if the encrypted value actually contains the keys your application needs.
There is one way to encrypt sensitive information by using Protected Configuration else you need to keep the file in any folder inside appdata and encrypt it using application
I have a requirement to not store any sensitive information (e.g. usernames and passwords) in source control.
Yes you shouldn't, and one way to accomplish this is by using either environment Variables or user-level config options. According to Microsoft
During development
appSettings element has a file attribute that allows you to specify an external file that contains sensitive app config settings. You can move all your secrets to an external file as long as the external file is not checked into your source tree.
Then you can do something like:
</connectionStrings>
<appSettings file="relative\path\to\AppSettingsSecrets.config">
</appSettings>
<system.web>
As for connectionStrings
You can use the configSource attribute to replace the entire markup. Unlike the file attribute that merges the markup, the configSource attribute replaces the markup.
During deployment
You could go to the Azure Management Portal and set them manually, in WebApps > you webApp > All settings > Application settings
check this link for further reference
The way I handle this in my projects is that the transforms remove all the dev connection strings and the values of any secure appSettings, etc... so that they can be managed individually in each environment.
Our setup is this...
The project web.config has all the common dev stuff in it. Including any dev app settings that in a production environment would be considered private. In our case it does not matter that these settings are checked-in as they are just for our internal use. The transforms remove all that info upon publish.
Our build servers manage the "publish" and transforms. So what happens is: when we build for a specific Configuration, that transform is run and it removes all the sensitive info.
The next step is that the build renames the web.config
to web.config.default
. This allows us to provide a config file that has all the default settings in it that are specific to that build but without the sensitive data.
On the first deployment it is up to the person deploying to rename the web.config.default
to web.config
and fill in the sensitive info. From there they can choose whether or not to encrypt the info.
Every subsequent deployment never overwrites the current web.config
- it only adds the defaults - it is up to the person doing the deployment to add or remove any new/deprecated config elements.
In addition, the manual steps here could also be automated using some sort of installer...
aspnet_regiis
manor, theweb.release.config
file in place. – Brian Diggs