App settings in environment variables in Sitecore.
November 23rd, 2024 by Adam Najmanowicz | Leave a CommentCreating back-end integrations is inevitably linked with having to authenticate against a remote endpoint. Be that a Rest API, FTP or an APM – secrets (credentials, api tokent, shared secrets) of some sort will be involved in the process.
Those credentials must be stored somewhere. At this point I hope no one even considers hardcoding those but even if you extract them to configuration – having them exposed in your repository may be a bad idea and is frowned upon by tools like SonarQube.
You would be encouraged to access those secrets by having them anchored against web.config appSettings
section such as:
<appSettings>
<add key="EmailReminder.FromAddress" value="name@server.net" />
<add key="Foundation.RemoteApi.AccessKey" value="" />
...
</appSettings>
This is because you can easily and conveniently edit such settings in Azure portal. Arguably you could also do this using connection strings, but those are not full connection strings we’re dealing with…
You cannot keep them in a dev only patch file as this section is not patchable with standard Sitecore practices… So for a long time, we just kept empty placeholders this list in web.config
and when you needed to work with a specific integration point you scrambled to find the credentials and struggled with them being wiped when the project was published.
This is handled elegantly in .Net Core OOTB as they can cascade from environment variables, but somehow despite decades of aggregated Sitecore experience in the team we just kept doing it.
Yesterday morning something in me broke… I’ve had enough! Decided that we need a proper reusable solution that would not be harder than sharing a file with the necessary secrets between developers.
I sat down with the intention of writing something that would just let me use environment variables. This way we still don’t have to store them in the repository, and they don’t get wiped when an app is republished (akin to how it works in Azure.
Let’s see what we’re dealing with…
So the xml had some AppSettings builder OOTB that maybe I could reuse/inherit in some capacity…
<appSettings configBuilders="SitecoreAppSettingsBuilder">
<add key="EmailReminder.FromAddress" value="name@server.net" />
...
</appSettings>
SitecoreAppSettingsBuilder
looked curiously like what I wanted to do…
<configSections>
<section name="sitecore" type="Sitecore.Configuration.RuleBasedConfigReader, Sitecore.Kernel" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging" />
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="SitecoreAppSettingsBuilder" mode="Strict" prefix="SITECORE_APPSETTINGS_" stripPrefix="true" type="Sitecore.Configuration.FlexibleEnvironmentConfigBuilder, Sitecore.Kernel" />
<add name="SitecoreConnectionStringsBuilder" mode="Strict" prefix="SITECORE_CONNECTIONSTRINGS_" stripPrefix="true" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment, Version=1.0.0.0, Culture=neutral" />
</builders>
</configBuilders>
I started investigating the classes, which looked intriguing, something didn?t feel right. Then it struck me?Sitecore already provided all the configuration builders for the job… undocumented…
The least buggy, most hassle-free code is the one you never write
There is no code to write here, when dealing with app settings defined in the main web.config <appSettings>
section (not patchable by the usual sitecore Sitecore-specific configs), such as:
<add key="Foundation.RemoteApi.AccessKey" value="" />
We can use environment variables with a prefix SITECORE_APPSETTINGS_
. For instance, the setting above could be stored in the following environment variable:
SITECORE_APPSETTINGS_Foundation.RemoteApi.AccessKey
Handling Environment Variables in IIS
Since environment variables are fixed at application startup, you can?t use a newly modified variable immediately. Unfortunately, even recycling the application wasn?t enough in my case. I had restart IIS for them to take:
iisreset /stop
iisreset /start
Automating the Process
To streamline this, I created short PowerShell script that globally sets all required variables. Here are some key points about the script:
- No repo storage: This script isn?t stored in the repository, but we can share it securely via direct messaging or other private channels.
- Elevated privileges: If you run it without admin rights, it will prompt you for confirmation and relaunch itself with elevated privileges.
- Environment-specific values: The script can easily be populated by keys we store in Azure app settings.
- IIS restart: It handles the IIS restart automatically.
Checking App Settings in Sitecore
To verify the value of an appSetting
in Sitecore, open Sitecore Desktop, launch PowerShell ISE, and run the following one-liner, replacing the variable name with the one you want to check:
[System.Web.Configuration.WebConfigurationManager]::AppSettings["Foundation.RemoteApi.AccessKey"]
PowerShell Script: Simplified and Ready
Below is the script I mentioned earlier:
# Check if the script is running as Administrator
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "The script is not running with administrative privileges. Relaunching as Administrator..."
# Get the current script's full path
$scriptPath = $MyInvocation.MyCommand.Path
# Create a new PowerShell process as Administrator
Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`"" -Verb RunAs
# Exit the current non-admin script
exit
}
# Code below runs with administrative privileges
Write-Host "Script is running with administrative privileges."
function Set-SitecoreAppSetting {
[CmdletBinding()]
param (
[Parameter(Position=0, Mandatory=$true)]
[string]$VariableName,
[Parameter(Position=1, Mandatory=$true)]
[string]$VariableValue
)
process {
Write-Host "Setting variable `"SITECORE_APPSETTINGS_$VariableName`" to value `"$VariableValue`""
[System.Environment]::SetEnvironmentVariable("SITECORE_APPSETTINGS_$VariableName", $VariableValue, [System.EnvironmentVariableTarget]::Machine)
}
}
# store your variables below - to speed up onboarding your colleagues...
Set-SitecoreAppSetting "VariableName1" 'VariableValue1'
Set-SitecoreAppSetting "VariableName2" 'VariableValue2'
Conclusion
This approach eliminates the need for any custom code while leveraging Sitecore?s built-in capabilities. The PowerShell script provides a clean way to manage environment variables without hardcoding sensitive details, and it ensures a consistent setup across the team. I hope this solution simplifies your workflow as much as it has mine!