23
votes

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
How about not including the web.config file in source control? And/or checking in a "blank" file, and a dev would have to copy and customize the config file before use?gunr2171
@gunr2171 I can't speak for OP but I'm running into the same thing because I'm using my source control for continuous deployment. Normally I'd say that the alternative is to put the connection string in a higher level web.config or machine.config but this approach unfortunately isn't viable when deploying to azure web-services.Kelly Robins
@BrianDiggs if you refer to this article by scott hanselman, This is how I secure private app setting and connection strings.Nkosi
I appreciate the additional answers and ideas that were added to this question. While most of them provided superior approaches to handling secure/secret information, I awarded the bounty to the one which addressed the narrow question of encrypting, in a aspnet_regiis manor, the web.release.config file in place.Brian Diggs

7 Answers

9
votes

The way I was able to make this work was by going to each machine and encrypting the web.config there with the correct connection string and then copying the newly encrypted connection string section into the appropriate web.cong transform. It is a huge pain but it works.

2
votes

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.

2
votes

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();
                }
1
votes

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.

0
votes

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

0
votes

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

0
votes

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...