Dynamic Setting Values

Token Replacement

Engine provides the ability to use some tokens in your setting values that will be replaced at runtime with the appropriate value. Currently, the tokens you can use are ${RegistrationId} and ${TenantName}.

If you wanted to use a registration's ID as part of the value of RedirectOnExitUrl, for example, your setting value could be: http://example.org/lms?registrationId=${RegistrationId}. That way, your redirect page would receive the registration id of the current launch at runtime.

Alternatively, you may use the ${TenantName} token for settings which you want to vary by tenant, but the only difference is the tenant name. For example, you could keep each tenant's content under a different path:

<add key="WebPathToContentRoot" value="/courses/${TenantName}"/>
<add key="FilePathToContentRoot" value="C:\inetpub\wwwroot\courses\${TenantName}"/>

<entry key="WebPathToContentRoot">/courses/${TenantName}</entry>
<entry key="FilePathToContentRoot">/var/www/courses/${TenantName}</entry>

Note: If you use the ${TenantName} token in any settings that govern file paths, make sure that the tenant name you pass into Engine follows the same capitalization standards every time you use it. Engine trusts the tenant name that you specify, and will it in token replacement even if the tenant name is capitalized differently than previously recorded. When Engine compares file paths, it has to do so case-sensitively to support case-sensitive file systems. This pattern can cause negative affects, even when running on applications that use case-insensitive file paths.

Environment Variables

We support the use of environment variables as another option for token replacement. However, only environment variables contained in the EnvironmentVariableTokenAllowList will be replaced. For example, if all of your environments save their course content to different directories on the same network drive, you could set your FilePathToContentRoot to //network-drive/server-content/${env:CONTENT_FOLDER_NAME}/ and set EnvironmentVariableTokenAllowList to CONTENT_FOLDER_NAME or {any previously added variables}, CONTENT_FOLDER_NAME. Assuming every web server has an environment variable CONTENT_FOLDER_NAME set to the appropriate value, each instance of Engine will save its course content to their own separate directories.

Connection Strings

Engine supports the use of <connectionStrings> in its web.config. For example, you can add a new <connectionStrings> section to the web.config that contains an entry to define a connection string.

<configuration>
    <connectionStrings>
        <add name="MyEngineConnectionString" connectionString="Server=ServerName;Database=Engine;User Id=user;Password=password;" />
    </connectionStrings>
</configuration>

In the RusticiEngineSettings.config file, you can change the value of the DatabaseConnectionString setting from the connection string to a token with the following syntax:

<add key="SystemDatabaseConnectionString" value="${connectionStrings.MyEngineConnectionString}" />

At runtime, Engine replaces "${connectionStrings.MyEngineConnectionString}" with the named connection string from the web.config's <connectionStrings> section. This can be a desirable approach to take advantage of the additional encryption options that .NET provides.

Special Tenant Syntax

Many configuration settings can be specified on a per-tenant basis. When getting a tenant-specific configuration setting, Engine will check for the setting prefixed by the lower-case tenant name and a dot. If found, the value of that entry will be used; if not, the value of the non-prefixed setting will be used.

For example, your LMS might have 5 tenants: AcmeCo, BusinessPlus, MaximumProfit, MoneyCorp, and SolutionsInc. If the first three use connection string database=a;password=secret; and the last two use connection string database=b;password=secret, then you can include the following two entries in your configuration file:

<add key="DataPersistenceEngine" value="sqlserver"/>
<add key="SystemDatabaseConnectionString" value="database=system;password=secret;"/>
<add key="TenantDatabaseConnectionString" value="database=a;password=secret;"/>
<add key="moneycorp.TenantDatabaseConnectionString" value="database=b;password=secret;"/>
<add key="solutionsinc.TenantDatabaseConnectionString" value="database=b;password=secret;"/>

<!-- For secure values, use Vault -->
<entry key="SystemDatabaseConnectionString">jdbc:sqlserver://foo.some-company.com;database=foo-db;user=${hashiCorpVault:dbUser};password=${hashiCorpVault:dbPassword}|com.microsoft.sqlserver.jdbc.SQLServerDriver</entry>

<!-- For non-secure values, use Consul -->
<entry key="FilePathToContentRoot">//network-drive/server-content/${hashiCorpConsul:contentFolderName}/</entry>

Alternate Configuration Sources

Overview

As of Engine 23.x, we support two alternative sources for configuration values out of the box.

  • HashiCorp Vault for storage of sensitive values. (e.g. auth tokens, passwords, etc.)
  • HashiCorp Consul for storage of non-sensitive values. (e.g. URLs, timeout values, etc.)

These features can be enabled by adding KeyValueStore.HashiCorp.Vault and/or KeyValueStore.HashiCorp.Consul respectively to the Plugins configuration setting in addition to any other plugins you may have listed. Values stored in an alternate configuration source (ACS) can be used in any Engine configuration setting.

For more details on configuring your Vault or Consul instance, see HashiCorp's documentation.

Storage

Values are lazily read from the ACS once and then cached in memory. If the stored value changes, Engine will not reload the value automatically and must be restarted.

Configuration

Once enabled, you'll need to set some additional Engine configuration settings. Details for these settings can be found under AlternateConfigurationSources Settings.

For Vault:

For Consul:

If your ACS access token is a short-lived token, it's important that all stored values be cached by Engine before that token expires. The /ping endpoint and changing the ApiPingCheckDatabase setting to true can be useful for forcing the load of tenant related values before the access token expires. It's important to note that this must be done for each server in an Engine cluster including new servers as they come online.

Usage

Similar to environment variables, you use a replacement token to insert the value into a configuration setting. Use the replacement token ${hashiCorpVault:someKeyName} for Vault or ${hashiCorpConsul:someKeyName} for Consul as a placeholder to inject the value of key someKeyName into a setting.

If your Vault or Consul configuration requires that the name of the key be in the path, you can use ${HashiCorpVaultKey} or ${HashiCorpConsulKey} to inject the key name into the path.

<entry key="HashiCorpVaultHostMountPath">https://foo.vaulthost.com/v1/foo/bar/${HashiCorpVaultKey}</entry>
<entry key="HashiCorpConsulHostPath">https://foo.consulhost.com/v1/foo/bar/${HashiCorpConsulKey}</entry>

Security

While values from an ACS are only stored in memory on the Engine instance, it's important to be mindful of how a potentially sensitive configuration value could be written to disk by a mechanism outside of the Engine configuration system. Engine is already designed to handle sensitive configuration settings (e.g. connection strings, passwords, etc.) with care, particularly when RedactLogs is enabled.

Therefore, care must be taken to prevent using a replacement token to inject a sensitive value into a setting that's not considered sensitive. Doing so could result in a sensitive value being written to disk, published in a log, sent over the network, or returned in an error message.

results matching ""

    No results matching ""