Search code examples
asp.netconnection-stringazure-virtual-machineazure-keyvaultapp-secret

Storing SQL Database Connection Strings in Azure Key Vault


I'm moving application secrets from a source controlled web.config (with transforms) to Azure Key Vault secrets. This works well for things like passwords, but SQL database connection strings seem difficult to move out of the web.config. There are various references to the connection strings elsewhere in the web.config (e.g. role providers, membership providers, profile providers, entity framework, etc.).

Are there any patterns and best practices to help with this migration? I was planing to use the connection string name as the secret name and the connection string value as the secret value. However, I'm not sure what to do with the connection string provider name.

Also, ideally, only the key vault URL would be in the web.config, but then how do existing configurations in the web.config integrate with Key Vault if they are currently referencing an actual connection string.

The IIS hosted ASP.NET application is currently running within an Azure Virtual Machine, but local development must also be taken into consideration.

UPDATE What about configuration like the following added and used by other libraries/packages?

<sessionState mode="InProc" customProvider="DefaultSessionProvider">
  <providers>
    <add name="DefaultSessionProvider"
         type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         connectionStringName="DefaultConnection" />
  </providers>
</sessionState>
<profile defaultProvider="DefaultProfileProvider">
  <providers>
    <add name="DefaultProfileProvider"
         type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         connectionStringName="DefaultConnection" applicationName="/" />
  </providers>
</profile>
<membership defaultProvider="DefaultMembershipProvider">
  <providers>
    <add name="DefaultMembershipProvider"
         type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         connectionStringName="DefaultConnection" enablePasswordRetrieval="false"
         enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
         maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6"
         minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
  </providers>
</membership>
<roleManager defaultProvider="DefaultRoleProvider">
  <providers>
    <add name="DefaultRoleProvider"
         type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         connectionStringName="DefaultConnection" applicationName="/" />
  </providers>
</roleManager>

Solution

  • Came up with a solution: keep the connection strings in web.config since they are referenced by other sections of the web.config, but update the values at application startup.

    protected void Application_Start()
    {
        /* ... */
    
        var configurationReadOnlyField = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
    
        var connection = ConfigurationManager.ConnectionStrings[connectionName];
        s_configurationReadOnlyField.SetValue(connection, false);
    
        connection.ConnectionString = newValue;
    
        /* ... */
    }