How to keep your production config secured on public GitHub repo

February 14 , 2016

Introduction

GitHub is a great place to store your projects. However, free plan allows you to have only public repositories. That means all your source codes will be available for everyone to see. This is not bad. This is great actually to share knowledge among developers. But what you don't want for sure is to share configuration settings from your production server like database connection string or email address credentials. 

There is a way how to secure all sensitive data in your config file in a way when only you and your production server can read values from it.

aspnet_regiis.exe

To perform encryption/decryption operations for your Web.config/App.config you can use aspnet_regiis.exe that can be found here: C:\ Windows\ Microsoft.NET\ Framework\ v4.0.30319\ aspnet_regiis.exe

Creating an RSA Key Container

First you need to generate RSA key container that will be used for encryption/decryption.

aspnet_regiis.exe -pc "MyRsaKeyName" –exp

-exp option means that you will be able to export this key container later.

This container is stored inside your operation system.

Modify Web.config/App.config

Then you need to add 'configProtectedData' with 'provider' to your configuration file (inside 'configuration' section and under 'configSections' if you have it)

<configProtectedData>
  <providers>
    <add name="MyProvider"
         type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
         keyContainerName="MyRsaKeyName"
         useMachineContainer="true" />
  </providers>
</configProtectedData>

As you can see 'keyContainerName' attribute referes to your RSA key container name.

Encrypt sections in Web.config/App.config

Now you can use aspnet_regiis.exe to encrypt something in configuration file.

aspnet_regiis.exe -pef "[Section Name]" "[Path To Your Project Directory]" -prov MyProvider

[Section Name] is the section you want to encrypt. For example "appSettings" or "connectionStrings". You can also specify applicationSettings or userSettings like this: "applicationSettings/X.Properties.Settings" but in this case make sure that <configProtectedData> is specified AFTER <configSections><sectionGroup name="applicationSettings"...

[Path To Your Project Directory] is the local physical path to your project Directory (not to the Web.config or App.config)

After executing this command when you open your configuration file you will see something like this:

  <connectionStrings configProtectionProvider="MyProvider">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
      xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <KeyName>Rsa Key</KeyName>
          </KeyInfo>
          <CipherData>
            <CipherValue>R5o7kfji3zOyto8jsB2RuJX9bRiNinPYXQ+0tku2kuzQVmqNwscJJHA8oM/FSH2SHhvmYR1FNA3HdKTQsKQd0IsMuIWqPYS8WRKW8Es2umtIk8wY3UuogusZ775siUaXDO/s9GJZZqfXsVojPaSrtuqadvbuZiYu2vbAv8XZbVk=</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>1cstGw/fBWBo9UEVElepNzMGbEkw3YuNQ54+ZwWK2/P7k48EBkq+y2BueQMILqVrwwHQI/uT6W5UNKJkOsHnE5goRHOglmEVQHA+U3QcSksWLrqflcU96YK5EQUSO7IQ5j9OobrwQxH8Yld+LInwHPofNCH2XAqz0xKPXsMM7P8=</CipherValue>
      </CipherData>
    </EncryptedData>
  </connectionStrings>

Copy encrypted section to Web[App].Release.config

You're using config transformation, aren't you? You can grab the whole encrypted section and put it there with 'Replace' transform. You will have to repeat this procedure each time you modify something in the encrypted section. This is a pain for sure, but AFAIR this is the only way.

<connectionStrings configProtectionProvider="MyProvider" xdt:Transform="Replace">
...
</connectionStrings

Export RSA Key Container

aspnet_regiis.exe -px "MyRsaKeyName" "c:/key.xml" -pri

-pri option means that private key will also be included during export

Import RSA Key Container on Production Server

aspnet_regiis.exe -pi "MyRsaKeyName" "c:\keys.xml"

Allow IIS process to access RSA key container

aspnet_regiis.exe -pa "MyRsaKeyName" "[Process Account]"

[Process Account] is an account name that your Web Application is running from (for example 'NT AUTHORITY\NETWORK SERVICE' or 'IIS APPPOOL\DefaultAppPool')

Deploy your application

Now you can push encrypted configuration in VCS such as GitHub. None but you can decrypt your values unless they have your RSA container. So be careful with it.

Working application reads values from encrypted sections transparently. 

If you need to decrypt

You can use the following command to decrypt your sections back:

aspnet_regiis.exe -pdf "[Section Name]" "[Path To Your Project Directory]"