2

Is there a way to get a web.config transformation in Visual Studio 2015+ to include the contents of an externally-referenced secrets file as described here?

This works well when developing locally, and doesn't include the file in source control, but when I go to deploy the web app to the server, I want it to include the username and password for another web service which it connects to. If I enter the settings manually in IIS on the server, they are lost each time I publish the app.

If I omit the keys in the appSettings block in my web.config (so that they are only referred to in the secrets file), the manually-entered settings in IIS on the server are removed completely whenever I publish the app.

Being able to refer to certain things in an external file for the sake of better security and not checking in passwords to source control isn't turning out to be a very good idea IMHO because my deployment is now a nightmare. I don't want to manually enter the passwords in the web.config file on the server after every deployment.

I'd rather not look into encryption, either, because I would have to do that for each server I deploy to so that the relevant machine key is used for each web.config file.

I've only recently thought about removing this password from source control, in response to a recent push to improve security practises at work - which I well understand and agree with - but I can also see why security is so poorly considered because the life of the ordinary developer becomes extremely unpleasant if there the tools available don't make it easy.

Surely there's a way without resorting to encryption?

Thanks.

Marc Fearby
  • 1,305
  • 1
  • 13
  • 28
  • How are you deploying your code? Injecting credentials is normally done as part of a CI pipeline during deployment – MisterSmith Jul 27 '18 at 10:50
  • I'm clicking the Publish button in Visual Studio and getting it to build then copy to the server folder where it lives. No fancy CI pipelines (yet). – Marc Fearby Jul 27 '18 at 12:09

2 Answers2

1

Without a CI system I think your best option is probably a pre/post build action that executes a script?

I'd suggest you replace the actual values with tokens for your sensitive web.config values (something unique/easy to find like MY_PRODUCT_DATABASE_PASSWORD etc). Your web.config can then be checked into source control safely.

In VS you can add a build action to run a custom powershell or exe to basically perform a find-and-replace on the tokens with actual values before you zip & deploy as normal.

Exactly how/where you store the real values and how the script works is up to you. you could easily find a file on your deployment machine or a row in some database based on data passed to the script/exe from vs or from data within web.config itself (or embedded as a comment in web.config even).

Here's details of the variables available from vs you could pass to your exe or script in a build action: https://msdn.microsoft.com/en-us/library/42x5kfw4.aspx

It you wanted to use PowerShell you could read/replace/write values to a web.config(or any text file) like this answer: How can I replace every occurrence of a String in a file with PowerShell?

MisterSmith
  • 2,884
  • 1
  • 10
  • 13
0

Following the Microsoft Docs example you've linked to, putting this XDT transformation inside Web.Release.config should do the trick:

<appSettings file="..\..\AppSettingsSecrets.config" xdt:Transform="SetAttributes">
    <add key="mailAccount" xdt:Locator="Match(key)" xdt:Transform="Remove" />
    <add key="mailPassword" xdt:Locator="Match(key)" xdt:Transform="Remove" />
    <add key="TwilioSid" xdt:Locator="Match(key)" xdt:Transform="Remove" />
    <add key="TwilioToken" xdt:Locator="Match(key)" xdt:Transform="Remove" />
    <add key="TwilioFromPhone" xdt:Locator="Match(key)" xdt:Transform="Remove" />
    <add key="GoogClientID" xdt:Locator="Match(key)" xdt:Transform="Remove" />
    <add key="GoogClientSecret" xdt:Locator="Match(key)" xdt:Transform="Remove" />
</appSettings>

You dont need xdt:Locator attribute on <appSettings> element itself, because there is only one appSettings.

Edit: I've misunderstood the original question. The goal is to include contents of referenced file, which is not possible using XDT. There has to be another way.

George Chakhidze
  • 1,269
  • 12
  • 15
  • I tried including the file="" in the appSettings in my web.Release.config but didn't also add the xdt:Transform="SetAttributes"; if I add this it still doesn't include the settings in that secrets file in the transformed file. Not sure why I'd want to xdt:Transform="Remove" those settings, but I tried adding that anyway, since you suggested it, but it still doesn't result in a transformed file with the secret settings included. – Marc Fearby Jul 29 '18 at 04:38
  • @MarcFearby Oh, I misunderstood your question, I thought you wanted config to look just like MSDN example. You want CONTENTS to be included in resulting file. To my knowledge, that is not possible using XDT. There has to be some other way. – George Chakhidze Jul 30 '18 at 10:26
  • It would be great if Microsoft allowed this for people without fancy CI/CD pipelines setup (which I may have access to soon, so I won't have to resort to powershell just yet, with any luck). – Marc Fearby Aug 01 '18 at 08:47