External Configuration of ODS Connection Strings

While the primary source for .NET configuration information is the appsettings.json file in the EdFi.Ods.WebApi project, the .NET configuration architecture is highly extensible through the addition of custom configuration sources. This article provides an example of how to use additional .NET configuration sources for externalizing the configuration of the ODS connection strings used by the Ed-Fi ODS API, including the use of AWS Systems Manager Parameter Store.

Alternative Connection String Sources

While the EdFi_Admin database holds information about the available ODS instances and their connection strings, the Ed-Fi ODS/API also supports sourcing the ODS connection strings for the ODS instances through the configuration architecture. Examples of the applicable configuration formats are shown below (represented here in JSON format).

When you are using a configuration-based source for the ODS instance connection strings, be sure to set the ConnectionString column of the records in the OdsInstances table in the EdFi_Admin database to null.

Single-Tenant Configuration

In a single-tenant configuration, the overrides for ODS connection strings can be defined in the "OdsInstances" section of the configuration, keyed by the OdsInstanceId (as defined in the EdFi_Admin database). Note that in the example below, it shows an explicit database segmentation approach based on school year provided by the API client in the base route of the API.

appsettings_odsinstances.json
"OdsInstances": { "3": { "ConnectionString": "Server=(local); Database=EdFi_Ods_2022; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;", "ContextValueByKey": { "schoolYearFromRoute": "2022" }, "ConnectionStringByDerivativeType": { "Snapshot": "Server=(local); Database=EdFi_Ods_2022_Snapshot; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;" } }, "4": { "ConnectionString": "Server=(local); Database=EdFi_Ods_2023; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;", "ContextValueByKey": { "schoolYearFromRoute": "2023" } } }

Multi-Tenant Configuration

In a multi-tenant configuration, the overrides for ODS connection strings are defined in an "OdsInstances" section under the "Tenants" section of the configuration, keyed by tenant-specific OdsInstanceId (as defined in the tenant's EdFi_Admin database), as follows:

appsettings_tenants.json
"Tenants": { "Tenant1": { "ConnectionStrings": { "EdFi_Admin": "Server=(local); Database=EdFi_Admin_Tenant1; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;", "EdFi_Security": "Server=(local); Database=EdFi_Security_Tenant1; Encrypt=False; Trusted_Connection=True; Persist Security Info=True; Application Name=EdFi.Ods.WebApi;" }, "OdsInstances": { "3": { "ConnectionString": "Server=(local); Database=EdFi_Ods_Tenant1_2022; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;", "ContextValueByKey": { "schoolYearFromRoute": "2022" }, "ConnectionStringByDerivativeType": { "Snapshot": "Server=(local); Database=EdFi_Ods_Tenant1_2022_Snapshot; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;" } }, "4": { "ConnectionString": "Server=(local); Database=EdFi_Ods_Tenant1_2023; Encrypt=False; Trusted_Connection=True; Application Name=EdFi.Ods.WebApi;", "ContextValueByKey": { "schoolYearFromRoute": "2023" } } } }, "Tenant2": { ... } }

Examples

There are a variety of external configuration providers available and the concepts and approach should be similar to the examples below. Primarily you must understand the structure of the configuration values expected by the API (as documented above), and how to correctly represent these values with the external configuration source of your choosing so that they integrate correctly into the logical configuration hierarchy.

JSON Configuration Files

To add JSON files to the API configuration, include the file alongside the existing appsettings.json file (ensuring that it is copied to the output directory on build), and modify the host configuration in the Program.cs file of the EdFi.Ods.WebApi project as follows:

var hostBuilder = Host.CreateDefaultBuilder(args) .ConfigureLogging(ConfigureLogging) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureAppConfiguration(c => { c.AddJsonFile("appsettings_tenants.json", optional: false, reloadOnChange: true); }) .ConfigureWebHostDefaults(...) ...

AWS Systems Manager Parameter Store

To add AWS configuration support to the API, first add the Amazon.Extensions.Configuration.SystemsManager nuget package to the EdFi.Ods.WebApi project. Then modify the host configuration in the Program.cs file to register this as an additional configuration source using the ConfigureAppConfiguration extension method (with a hard-coded 10-minute refresh period in this example):

Finally, you'll need to create and maintain the necessary configuration entries in the AWS Systems Manager Parameter Store. The image below shows the configuration of secure connection strings for tenant-specific EdFi_Admin, EdFi_Security and EdFi_ODS databases in a multi-tenant configuration. Note the use of the same prefix on the individual item names as the first argument passed to the AddSystemsManager call in the code sample above.

In order for this code to work, you must perform some initialization of the AWS SDK so that it has the necessary information to authenticate with your AWS account. That information is outside the scope of this documentation.

Azure Key Vault

To add Azure Key Vault support to the API, first add the Azure.Extensions.AspNetCore.Configuration.Secrets nuget package to the EdFi.Ods.WebApi project. Then modify the host configuration in the Program.cs file as shown below to register this as an additional configuration source using the ConfigureAppConfiguration extension method. This example shows how to add the key vault information to the appsettings.json file and configure it with a 10-minute refresh period.

Add the supporting Azure Key Vault configuration information under the Services section in appsettings.json:

Ultimately, it is essential to create and manage the required configuration entries in Azure Key Vault, ensuring that the identity accessing the vault has the necessary permissions. The configuration for a secure connection string to an EdFi_ODS database (with OdsInstanceId = 2) in a single-tenant setup is depicted below. Note the use of an API-specific key vault and the use of double hyphens (--) to separate the segments of the configuration hierarchy.

image-20240427-204312.png

To run this code locally, you need to initialize the Azure SDK with the required information for Azure authentication. Details on setting up the Azure client and granting your application the necessary permissions to access key vault secrets are outside the scope of this documentation.