In which I discuss techniques to manage the storage of a secret configuration setting (connection credentials) on a production webserver, when the development team (and their automated build/depoy process) shouldn't actually know the secret itself (and especially shouldn't store it in source control).
It's a bit of a ramble to myself as I think this stuff through.
What's new in .Net 2
In .Net 2, the configuration infrastructure includes support for encrypted connection strings out-of the box. One can simply call aspnet_regiis to encrypt (almost) any given section of a configuration file:
aspnet_regiis -pe "connectionStrings" -app "/MachineDPAPI" -prov "DataProtectionConfigurationProvider"
Pasted from <http://msdn2.microsoft.com/en-us/library/ms998280.aspx>
However
- This encrypts the whole section, which makes inspection and verification of other settings harder
- This requires the .config file to have the credentials in in the first place
- So either the credentials sit in source control at the dev end :-(
- Or the install process has to both prompt for them, and add them into the web.config before encryption. This is a pain, but manageable.
A variation on this technique is available for web farm scenarios, where the config is encrypted with a custom exportable RSA key.
aspnet_regiis -pe "connectionStrings" -app "/WebFarmRSA" -prov "CustomProvider"
aspnet_regiis -px "CustomKeys" "C:\CustomKeys.xml" -pri
Pasted from <http://msdn2.microsoft.com/en-us/library/ms998283.aspx>
Apart from being web-farm aware, this technique has the advantage that the public part of the key could be exported to the build server, and the settings encrypted prior to deployment
However this still means the build server (and by inference source control) contains the production credentials in plain text. This is generally what we want to avoid most - internal information leakage is far more likely than a compromise of the production environment, especially in an intranet scenario.
How did we used to manage this in Net 1.1?
Under .Net 1.1 the approach was to use the ASPNET_SETREG tool to move settings into the registry, under DPAPI encryption, then adjust the configuration using a special syntax that said 'read this from the registry instead'.
aspnet_setreg.exe -k:SOFTWARE\MY_SECURE_APP\identity -u:"yourdomainname\username" -p:"password"
Pasted from <http://support.microsoft.com/kb/329290>
identity impersonate="true"
userName="registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,userName"
password="registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,password"
Pasted from <http://support.microsoft.com/kb/329290>
This has the following advantages:
- Secret only needs to be known once, on initial install, and is thereafter stored in the registry
- Source control and build process doesn't need to know the secret
- Same config file deployed to both boxes in a web farm
Whilst under .net 1.1 this was only supported for specific keys:
identity userName= password=
processModel userName= password=
sessionState stateConnectionString= sqlConnectionString=
Pasted from <http://support.microsoft.com/kb/329290>
…a common pattern, and one I've used a couple of times, was to use aspnet_setreg to put arbitrary settings into the registry in an encrypted manner, and use custom DPAPI code to retrieve them. There was no equivalent of the DPAPI wrapper class 'DataProtection' in .Net 1.1, so Keith Brown provided one:
"Version 2.0 of the .NET Framework introduces a class called DataProtection that wraps DPAPI. It's simple to use; in fact, it looks almost exactly like the wrapper class I provided above. I've shown an example in figure 70.2."
Pasted from <http://pluralsight.com/wiki/default.aspx/Keith.GuideBook.HowToStoreSecretsOnAMachine>
So where are we going with this?
Well to my mind at least the .Net 1.1 registry approach was actually better than the .Net 2 model - it separated the configuration and the secret in a way that perfectly reflected the normal division of labour between development and infrastructure teams (where the devs are expected to provide the configs, but they shouldn't know the secret).
There should be no reason why one cannot use the .Net 1.1 technique (ie use ASPNET_SETREG to store the secret), whilst still using the .Net 2 DataProtection class to unencrypt it.
- This does require careful monitoring of the ACL on the registry key in question
- There's no real requirement to use ASPNET_SETREG over a custom exec (using the DPAPI), bar convenience. That having been said a custom EXE could set the registry key ACL at the same time, which I remember as being a headache otherwise.
No comments:
Post a Comment