Click here to Skip to main content
Click here to Skip to main content

Keeping Sensitive Config Settings Secret with Azure Websites and GitHub

, 8 Jun 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
A strategy for keeping sensitive configuration values, such as connection strings, out of your source control repository, but still available to your app both locally and in the cloud. We're looking specifically at Azure websites and GitHub.

Introduction

With the introduction of Azure websites, which provide automated deployments from source control systems such as TFS and GitHub, it has become relatively easy to configure automated deployments to Azure, so that you can do a check-in and watching your deployment happen. Most of the online demos that you'll find online recommend that if you're building a web site for deployment and you need to store sensitive values such as storage connection strings, you should put them in your web.config. If you use a source control repository that provides restricted access to your source code, such as TFS, you can happily add these values to your web.config and check them in, and know that they are safe from the eyes of others. However, if you're using a public source control system, such as GitHub, you might not want others to see your sensitive configuration settings.

Azure websites allow you to modify your configuration settings using the Azure Management portal, which partially addresses this problem by letting you ensure your cloud web site has the correct configuration values, and ensures they are secure. However, what about settings that you'd like to have in your web.config locally, as well as in the cloud? For example:

  • Service bus connection strings
  • Storage connection strings
  • OAuth provider secrets and more....

If you add them to your web.config and check them into GitHub, anyone can see (and possibly use) them. BUT if you only add them in by using the Azure Management Portal, they won't be available locally. Surely, there must be a way to have them available in both, right? In this article, I'll present a way to avoid this problem, allowing you to store your secret configuration settings locally, keep them out of source control, and also use the correct settings in the cloud.

NOTE: If you're using Node.js, I found a really good tutorial which addresses the same problem here.

Source Code Download

All source code for this article is available here. I've also uploaded a zip file of the solution for those who can't access GitHub on CodeProject.

Background

There are a couple of methods I've seen thus far for keeping config secrets out of GitHub. The first involves:

  1. Adding a configuration file with your secret values in it
  2. Checking it in
  3. Using git update-index --assume-unchanged command to tell Git to ignore changes to this file in future, and adding it to your .gitignore file
  4. Making changes to this file which will not be checked in
Whilst this works if you only have a single branch, as soon as you change branches, this will break as Git detects changes in your config file, and you'll have to either undo them, or check them in.

Another option is to use pre and post-commit hooks to automatically add/remove your secret config values when checking in and out, as described here. Unfortunately, the solution provided uses python script, which we can't use automatically from within a standard Visual Studio ASP.NET solution.

We want a method that is easy to implement, will work well for ASP.NET web projects (Both MVC and ASP.NET webpages), and integrate with Azure and GitHub. And that's exactly what I'll provide.

The Solution

Getting Started

To give you a full explanation of how this technique works, we first need to setup a website and deploy it to Azure from GitHub. To do so, we need to:

  • Create an example ASP.NET website in Visual Studio 2012 using the MVC 4 internet application template
  • Configure source control with Git, and check our site into GitHub so the source code is publicly available for all to see
  • Sign up for an Azure trial account
  • Create a website
  • Setup automated deployments to Azure from our GitHub repository

Create a web site and set up source control with GitHub

The article here gives a good example of how to setup continuous deployment to Azure from GitHub, and I recommend reading it if you're not familiar with Git or Azure. For our example, I've downloaded Git Explorer for Windows, and created a local repository named CodeProjectConfigStrategy, as shown below:

Next, I'll open up Visual Studio 2012, and create a new MVC Web Application, ensuring that its Location is the same folder as my Git repository I created earlier, as shown below:

Next up, I'll exclude NuGet packages, as described in this article. I also added an entry to my .gitignore file to exclude the whole /packages directory from source control. My solution now looks similar to the following:

Finally, I'll go back to GitHub Explorer, commit my changes, and press the Sync button so my changes are pushed to GitHub. Now I need to create a site in Azure and deploy to it.

Creating the site in Azure and setting up automated deployments

As mentioned earlier, the article here provides a good example of how to setup automated deployments from GitHub, in the section titled "Deploy files from a repository web site like BitBucket, CodePlex, Dropbox, GitHub, or Mercurial." If you're following along, I'd recommend reading it so you're familiar with how to integrate your Azure website with GitHub for automated deployments.

In my case, I:

  1. Signed up for an Azure free trial and logged into the Azure Management Portal
  2. Created a website named codeprojectconfigstrategy (http://codeprojectconfigstrategy.azurewebsites.net/)
  3. Configured the site so that it was automatically deployed from the GitHub repository I created earlier
The end result is the site as follows, which is nothing special:

Keeping our configuration secrets safe

We now have a vanilla MVC web app. Imagine if we wanted to add something which required the use of a configuration value, for example a connection string for Azure service bus, or perhaps an API key for OAuthn using Facebook? This could apply to any situation in which you need to store sensitive values in your web.config file, but I'll use the Azure service bus connection string as an example. How will we go about this?

For demonstration purposes, you might have code to access the service bus connection string such as this:

string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString); 

And in your web.config, you might put the storage connection string for your Azure service bus as below:

<appSettings>
    <add key="Microsoft.ServiceBus.ConnectionString" value="Endpoint=sb://exampleservicebus.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=longlongsecretguid" /> 

Now this will work fine when debugging locally, and also if we check in and deploy it to Azure, as our cloud instance will be able to access the connection string in the web.config. But if we check this file in now, others who access our GitHub repository can see and use our connection string. So, how do we stop this?

Moving sensitive config settings to a separate file

First, we'll add two new files to our solution, one named HiddenSettings.config, and another called HiddenSettings.template.config. Both of these should have their build action set to Content, just like the web.config file does. This means they'll be deployed automatically when the site is published.

Next, we'll update our web.config file to use the values in our HiddenSettings.config file, by updating the AppSettings element as follows (If you're not familiar with how this works, see this link):

<appSettings file="HiddenSettings.config"> 

Next, we open our HiddenSettings.template.config file and add the following contents:

<?xml version="1.0"?>
<appSettings>
</appSettings> 

We then open our HiddenSettings.config file and add entries for all of the sensitive configuration settings that we want to override. In our case, we only have one, as follows:

 <?xml version="1.0"?>
<appSettings>
  <add key="Microsoft.ServiceBus.ConnectionString" 
value="Endpoint=sb://exampleservicebus.servicebus.windows.net/;
SharedSecretIssuer=owner;SharedSecretValue=longlongsecretguid" />
</appSettings> 

Next, we go back to our web.config file and replace our sensitive value with a dummy value, to indicate to anyone else using our solution that this value needs to be updated with their own chosen value.

<appSettings>
    <add key="Microsoft.ServiceBus.ConnectionString" value="ThisWillBeOverriddenAtRuntimeByYourSecretValue" /> 

Finally, we open up our .gitignore file in the solution root directory, and add an entry for our HiddenSettings.config file so it doesn't get checked into source control. E.g.

HiddenSettings.config 

Add a post-build event so that our HiddenSettings.config file will be created automatically on the build server

At this stage, we've moved our sensitive values into a separate configuration file, and added an entry to .gitignore to ensure they don't get into source control. However, if we check this in, the deployment to Azure will fail, as when performing a publish on the build server, the publishing process won't be able to find the HiddenSettings.config file, as it doesn't exist since it was never checked in. That's where our empty HiddenSettings.template.config file comes in! What we'll do is configure a post-build event, so that if the build process can't find the HiddenSettings.config file (e.g. if it's on the build server) then it should create it automatically, and populate it with the contents of the HiddenSettings.template.config file.

To do this, we need to:

  • Open our MvcApplication1.csproj file in Notepad or another text editor
  • Find the AfterBuild element (commented out by default)
  • Uncomment it, and replace it with the following code:
 <Target Name="AfterBuild">
    <Copy SourceFiles="HiddenSettings.Template.config" 
    DestinationFiles="HiddenSettings.config" SkipUnchangedFiles="true" 
    Condition="!Exists('HiddenSettings.config')">
    </Copy>
  </Target> 

As you can see, this looks for the HiddenSettings.config file, and if it doesn't exist, simply creates it and copies the contents of HiddenSettings.template.config into it.

Checking in and updating our settings in Azure

We can now check our project into GitHub, safe in the knowledge that our secrets are safe. However, we need to ensure that those settings are available to our app when deployed to Azure. Azure web sites allow you to override configuration values in the web.config file with values you provide in the management portal. To do this, I:

  • Go the management portal
  • Open the codeprojectconfigstategy website and click on the Configure tab
  • Navigate to the App Settings section, and add an entry for Microsoft.ServiceBus.ConnectionString, with a value that points to our production service bus, as shown below:


Now our Azure site will have the correct value, as will our local site, and none of our sensitive data is available for others to see in GitHub! Brilliant!

Using the Code

If you'd like to see the solution, all of the source code is available on GitHub here.

Feel free to download and browse the code as you wish. Smile | :) Please also let me know if you have any comments or ideas on how I could improve this solution.

Points of Interest

Whilst this isn't the only solution to the initial problem, I feel like it makes best use of the built-in features that already come with ASP.NET and Azure websites, such as:

  • Storing configuration settings in a separate file
  • Utilizing the post-build process
  • Automated source control with GitHub
  • Updating app settings in the Azure Management Portal
Finally, if you found this article useful, be sure to check out my main CodeProject article - http://www.codeproject.com/Articles/584534/YouConf-Your-Live-Online-Conferencing-Tool, which contains a multitude of tips like this to help you build a rock-solid Azure website. This was just one of the many discoveries I made during the Azure Developer Challenge.

Thanks for reading and I hope you've learned something useful!

History

  • 2013/06/04 - Initial article
  • 2013/06/09 - Added source code download in addition to GitHub link

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Phil Lee NZ
Software Developer (Senior)
New Zealand New Zealand
I'm a software developer based in the beautiful city of Wellington, New Zealand. I love experimenting with new .Net technologies as they arrive, and these days there seems to be a lot of choice as there are so many new features in the framework! My current interests are Azure, ASP.Net MVC, SignalR, Knockout, AngularJS, and responsive design (inc. using Bootstrap, Foundation, Skeleton). These change fairly often as I tinker with various new technologies...

Comments and Discussions

 
QuestionAfterBuild step should be BeforeBuild PinmemberAnjdreas11-Oct-13 12:39 
AnswerRe: AfterBuild step should be BeforeBuild PinmemberPhil Lee NZ12-Oct-13 23:08 
GeneralRe: AfterBuild step should be BeforeBuild PinmemberAnjdreas13-Oct-13 12:18 
GeneralRe: AfterBuild step should be BeforeBuild PinmemberPhil Lee NZ14-Oct-13 16:46 
GeneralMy vote of 5 PinprofessionalTim Corey20-Jun-13 4:07 
GeneralRe: My vote of 5 PinmemberPhil Lee NZ20-Jun-13 18:37 
GeneralMy vote of 5 Pinprofessionalroscler8-Jun-13 2:50 
GeneralRe: My vote of 5 PinmemberPhil Lee NZ8-Jun-13 14:55 
GeneralRe: My vote of 5 Pinprofessionalroscler8-Jun-13 15:07 
GeneralRe: My vote of 5 PinmemberPhil Lee NZ8-Jun-13 16:47 
GeneralRe: My vote of 5 Pinprofessionalroscler8-Jun-13 17:52 
GeneralMy vote of 5 Pinmember Gun Gun Febrianza4-Jun-13 9:53 
QuestionRe: My vote of 5 PinmemberPhil Lee NZ5-Jun-13 1:21 
GeneralMy vote of 5 PinprofessionalRanjan.D4-Jun-13 6:41 
GeneralRe: My vote of 5 PinmemberPhil Lee NZ5-Jun-13 1:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 9 Jun 2013
Article Copyright 2013 by Phil Lee NZ
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid