Background
To ensure your application secrets remain secret on the sever, you might want to encrypt sections of Web.Config file on desk so that not everyone who has access to the server can open and read the file. Important sections of Web.Config include ConnectionString (which holds the credentials to databases) and AppSettings (which is typically used to store other API keys or secrets). Enabling encryption of Web.Config for ConnectionString is simple. Just set <MSDeployEnableWebConfigEncryptRule>true</MSDeployEnableWebConfigEncryptRule> within your project’s PublishProfiles and it is done. However, if you would like to encrypt the AppSettings component within Web.Config, it would take a lot more effort.
There are alternatives to running on-demand AppSettings encryption after each deployment. We could separate the project secrets into a separate file from Web.Config, host it a different path so that it will not be replaced after deployment, and manually encrypt the AppSettings component in the server. However, in today’s software development context on continuous delivery, I think it makes more sense to deploy my secrets on demand from Jenkins and would prefer to have a one-time setup for such deployment instead of manually deployment of app secrets. I feel the team will benefit in the long term with such setup.
- Add runCommand at WMSvc
- Add privileges to WMSvc and restart WMSvc
- Create batch script in the server
- Add Provider in your Web.Config
- Create Key Container and grant to running user
- Add the running script in Web Publishing Profile (WPP)
1. Add runCommand at WMSvc
Go to IIS > Management Service Delegation and add a runCommand rule. Path should be filled with the full path to the batch script created in step 3. You will be prompted with a add user textbox after clicking on Ok. Enter “*” for that.
2. Add privileges to WMSvc and restart WMSvc
Run the below command as Administrator
sc privs wmsvc SeChangeNotifyPrivilege/SeImpresonatePrivilege/SeAssignPrimaryTokenPrivilege/SeIncreaseQuotaPrivilege
You will see the response [SC] ChangeServiceConfig2 SUCCESS
What does the command do? It adds privileges to WMSvc account so that it can execute runCommand. Detailed information is documented here — https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/ee619740(v=ws.10)?redirectedfrom=MSDN#using-the-runcommand-provider-with-the-web-management-service-wmsvc
Next, restart WMSvc using the command net stop wmsvc and net start wmsvc.
Special thanks to Luke in this stackoverflow post — https://stackoverflow.com/questions/4380819/msdeploy-runcommand-priviliges
3. Create batch script in the server
Create a batch script with the below command and allow it to be executable by the deployment account.
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis -pef “appSettings” E:\inetpub\[Project Name] -prov “defaultProvider” > E:\scripts\encrypt.log
- -pef is to perform encryption
- the text after -pef is the section to execute encryption on
- the following text points directly to the path of the project
- -prov will use the provider information within the Web.Config which will be setup in step 4.
4. Add Provider in your Web.Config
Add the below XML within your project’s Web.Config. As the order seems to matter, I added it just above the connectionStrings.
5. Create Key Container and grant to running user
Go to the folder of aspnet_regiis (C:\Windows\Microsoft.NET\Framework\v4.0.30319\) within the command prompt and run the below commands as Administrator.
aspnet_regiis -pc “Project_KeyContainer”
aspnet_regiis -pa “Project_KeyContainer” "[Deployment account]"
aspnet_regiis -pa “Project_KeyContainer” "IIS_IUSRS"
- -pc creates the container
- -pa grants the use of the container to the users. This is to allow the deployment account that is executing your MSDeploy to use the container to encrypt and the IIS to decrypt while running your application
6. Add the running script in Web Publishing Profile (WPP)
Add the below XML within the Web Publishing Profile used in your project. The path in the XML should be the same as the batch script created in step 3.