Please note that Emulator for Azure App Configuration is unofficial and not endorsed by Microsoft.
docker pull tnc1997/azure-app-configuration-emulator
docker run -p 8080:8080 tnc1997/azure-app-configuration-emulator
The emulator supports HMAC authentication and Microsoft Entra ID authentication.
The credential and secret may be overridden using the environment variables Authentication__Schemes__Hmac__Credential
and Authentication__Schemes__Hmac__Secret
respectively.
services:
azure-app-configuration-emulator:
environment:
- Authentication__Schemes__Hmac__Credential=xyz
- Authentication__Schemes__Hmac__Secret=c2VjcmV0
image: tnc1997/azure-app-configuration-emulator
The client may authenticate requests using the connection string for the emulator.
using Azure.Data.AppConfiguration;
var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__AzureAppConfiguration");
var client = new ConfigurationClient(connectionString);
var setting = new ConfigurationSetting("AzureAppConfigurationEmulator", "Hello World");
await client.SetConfigurationSettingAsync(setting);
services:
azure-app-configuration-emulator:
image: tnc1997/azure-app-configuration-emulator
console-application:
build:
context: .
dockerfile: ./ConsoleApplication/Dockerfile
depends_on:
- azure-app-configuration-emulator
environment:
- ConnectionStrings__AzureAppConfiguration=Endpoint=http://azure-app-configuration-emulator:8080;Id=abcd;Secret=c2VjcmV0;
The authentication related headers may be generated using the following script:
const credential = "abcd";
const secret = "c2VjcmV0";
const date = new Date().toUTCString();
const contentHash = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(pm.request.body.toString())).toString(CryptoJS.enc.Base64);
const signedHeaders = "x-ms-date;Host;x-ms-content-sha256";
const stringToSign = `${pm.request.method}\n${pm.request.url.getPathWithQuery()}\n${date};${pm.request.url.getRemote()};${contentHash}`;
const signature = CryptoJS.HmacSHA256(CryptoJS.enc.Utf8.parse(stringToSign), CryptoJS.enc.Base64.parse(secret)).toString(CryptoJS.enc.Base64);
pm.request.headers.upsert(`x-ms-date: ${date}`);
pm.request.headers.upsert(`x-ms-content-sha256: ${contentHash}`);
pm.request.headers.upsert(`Authorization: HMAC-SHA256 Credential=${credential}&SignedHeaders=${signedHeaders}&Signature=${signature}`);
HMAC authentication is recommended because it does not require a Microsoft Entra tenant and an Azure App Configuration resource.
- Register an application within the Microsoft Entra tenant.
- On the Overview page, in the Essentials accordion, copy the following values:
- Application (client) ID
- Directory (tenant) ID
- On the Certificates & secrets page, in the Client secrets tab, add a client secret.
- On the Overview page, in the Essentials accordion, copy the following values:
- Create an Azure App Configuration resource to be emulated.
- On the Overview page, in the Essentials accordion, copy the following values:
- Endpoint
- On the Access control (IAM) page, add a role assignment.
- In the Role tab, select the App Configuration Data Owner role.
- In the Members tab, assign access to the registered application.
- On the Overview page, in the Essentials accordion, copy the following values:
- Generate a self-signed certificate with the
<endpoint>
as the Subject Alternative Name.
The metadata address must be set using the environment variable Authentication__Schemes__MicrosoftEntraId__MetadataAddress
.
services:
azure-app-configuration-emulator:
environment:
- ASPNETCORE_HTTP_PORTS=80
- ASPNETCORE_HTTPS_PORTS=443
- Authentication__Schemes__MicrosoftEntraId__MetadataAddress=https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration
image: tnc1997/azure-app-configuration-emulator
networks:
default:
aliases:
- <endpoint>
volumes:
- ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro
- ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro
The valid audience should be overriden using the environment variable Authentication__Schemes__MicrosoftEntraId__ValidAudience
.
services:
azure-app-configuration-emulator:
environment:
- ASPNETCORE_HTTP_PORTS=80
- ASPNETCORE_HTTPS_PORTS=443
- Authentication__Schemes__MicrosoftEntraId__MetadataAddress=https://login.microsoftonline.com/<tenant-id>/.well-known/openid-configuration
- Authentication__Schemes__MicrosoftEntraId__ValidAudience=https://<endpoint>
image: tnc1997/azure-app-configuration-emulator
networks:
default:
aliases:
- <endpoint>
volumes:
- ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro
- ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro
The client may authenticate requests using the Microsoft Entra tenant.
using Azure.Data.AppConfiguration;
using Azure.Identity;
var tenantId = Environment.GetEnvironmentVariable("Authentication__Schemes__MicrosoftEntraId__TenantId");
var clientId = Environment.GetEnvironmentVariable("Authentication__Schemes__MicrosoftEntraId__ClientId");
var clientSecret = Environment.GetEnvironmentVariable("Authentication__Schemes__MicrosoftEntraId__ClientSecret");
var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var endpoint = Environment.GetEnvironmentVariable("Endpoints__AzureAppConfiguration");
var client = new ConfigurationClient(new Uri(endpoint), credential);
var setting = new ConfigurationSetting("AzureAppConfigurationEmulator", "Hello World");
await client.SetConfigurationSettingAsync(setting);
services:
azure-app-configuration-emulator:
environment:
- ASPNETCORE_HTTP_PORTS=80
- ASPNETCORE_HTTPS_PORTS=443
- Authentication__Schemes__MicrosoftEntraId__MetadataAddress=https://login.microsoftonline.com/<tenant-id>/.well-known/openid-configuration
- Authentication__Schemes__MicrosoftEntraId__ValidAudience=https://<endpoint>
image: tnc1997/azure-app-configuration-emulator
networks:
default:
aliases:
- <endpoint>
volumes:
- ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro
- ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro
console-application:
build:
context: .
dockerfile: ./ConsoleApplication/Dockerfile
depends_on:
- azure-app-configuration-emulator
entrypoint: /bin/sh -c "update-ca-certificates && dotnet ConsoleApplication.dll"
environment:
- Authentication__Schemes__MicrosoftEntraId__ClientId=<client-id>
- Authentication__Schemes__MicrosoftEntraId__ClientSecret=<client-secret>
- Authentication__Schemes__MicrosoftEntraId__TenantId=<tenant-id>
- Endpoints__AzureAppConfiguration=https://<endpoint>
volumes:
- ./emulator.crt:/usr/local/share/ca-certificates/emulator.crt:ro
The access token may be obtained using the following configuration:
Configuration | |
---|---|
Auth Type | OAuth 2.0 |
Grant Type | Client Credentials |
Access Token URL | https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token |
Client ID | <client-id> |
Client Secret | <client-secret> |
Scope | https://<endpoint>/.default |
The emulator is compatible with the following operations:
Operation | |
---|---|
Get | ✔️ |
Get (Conditionally) | ✔️ |
Get (Select Fields) | ✔️ |
Get (Time-Based Access) | ✔️ |
List | ✔️ |
List (Pagination) | ❌ |
List (Filtering) | ✔️ |
List (Select Fields) | ✔️ |
List (Time-Based Access) | ✔️ |
Set | ✔️ |
Set (Conditionally) | ✔️ |
Delete | ✔️ |
Delete (Conditionally) | ✔️ |
Operation | |
---|---|
List | ✔️ |
List (Pagination) | ❌ |
List (Filtering) | ✔️ |
List (Select Fields) | ✔️ |
List (Time-Based Access) | ✔️ |
Operation | |
---|---|
List | ✔️ |
List (Pagination) | ❌ |
List (Filtering) | ✔️ |
List (Select Fields) | ✔️ |
List (Time-Based Access) | ✔️ |
Operation | |
---|---|
Lock | ✔️ |
Lock (Conditionally) | ✔️ |
Unlock | ✔️ |
Unlock (Conditionally) | ✔️ |
Operation | |
---|---|
List | ❌ |
List (Pagination) | ❌ |
List (Range) | ❌ |
List (Filtering) | ❌ |
List (Select Fields) | ❌ |
List (Time-Based Access) | ❌ |
The emulator stores configuration settings in a SQLite database.
The data that is generated by the emulator during a session may be persisted between sessions using a volume.
services:
azure-app-configuration-emulator:
image: tnc1997/azure-app-configuration-emulator
volumes:
- azure-app-configuration-emulator:/var/lib/azureappconfigurationemulator
volumes:
azure-app-configuration-emulator:
The connection string for the database may be overridden using the environment variable ConnectionStrings__DefaultConnection
.
services:
azure-app-configuration-emulator:
environment:
- ConnectionStrings__DefaultConnection=Data Source=/var/lib/azureappconfigurationemulator/emulator.db
image: tnc1997/azure-app-configuration-emulator
The database may be seeded with data and mounted into the container however care should be taken to ensure that the database has the required schema.
services:
azure-app-configuration-emulator:
image: tnc1997/azure-app-configuration-emulator
volumes:
- ./emulator.db:/var/lib/azureappconfigurationemulator/emulator.db
The emulator integrates with Azure Event Grid to publish events using the Event Grid event schema when configuration settings are deleted or modified.
The endpoint and key for the Event Grid Topic may be set using the environment variables Messaging__EventGridTopics__xyz__Endpoint
and Messaging__EventGridTopics__xyz__Credential__Key
respectively where xyz
is an arbitrary name.
services:
azure-app-configuration-emulator:
environment:
- Messaging__EventGridTopics__Contoso__Credential__Key=a2V5
- Messaging__EventGridTopics__Contoso__Endpoint=https://contoso.uksouth-1.eventgrid.azure.net/api/events
image: tnc1997/azure-app-configuration-emulator
The emulator integrates with OpenTelemetry to provide metrics and traces.
The endpoint for the OpenTelemetry Protocol (OTLP) Exporter may be overridden using the environment variable OTEL_EXPORTER_OTLP_ENDPOINT
.
services:
azure-app-configuration-emulator:
depends_on:
- opentelemetry-collector
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=http://opentelemetry-collector:4317
image: tnc1997/azure-app-configuration-emulator
opentelemetry-collector:
image: otel/opentelemetry-collector-contrib
The emulator may be configured to serve requests over HTTPS using a self-signed certificate.
openssl req -x509 -out ./emulator.crt -keyout ./emulator.key -newkey rsa:2048 -nodes -sha256 -subj '/CN=azure-app-configuration-emulator' -addext 'subjectAltName=DNS:azure-app-configuration-emulator'
The port for HTTPS must be set using the environment variable ASPNETCORE_HTTPS_PORTS
.
The paths for the certificate and key must be set using the environment variables Kestrel__Certificates__Default__Path
and Kestrel__Certificates__Default__KeyPath
respectively.
The certificate and key must be mounted into the container at the paths that are set above.
services:
azure-app-configuration-emulator:
environment:
- ASPNETCORE_HTTP_PORTS=8080
- ASPNETCORE_HTTPS_PORTS=8081
- Kestrel__Certificates__Default__Path=/usr/local/share/azureappconfigurationemulator/emulator.crt
- Kestrel__Certificates__Default__KeyPath=/usr/local/share/azureappconfigurationemulator/emulator.key
image: tnc1997/azure-app-configuration-emulator
volumes:
- ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro
- ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro
The emulator integrates with Testcontainers to ease the integration testing of applications that use Azure App Configuration.
var container = new ContainerBuilder()
.WithImage("tnc1997/azure-app-configuration-emulator:1.0")
.WithPortBinding(8080, true)
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Now listening on"))
.Build();
await container.StartAsync();
var client = new ConfigurationClient($"Endpoint={new UriBuilder(Uri.UriSchemeHttp, container.Hostname, container.GetMappedPublicPort(8080))};Id=abcd;Secret=c2VjcmV0");
await client.SetConfigurationSettingAsync(nameof(ConfigurationSetting.Key), nameof(ConfigurationSetting.Value));
var response = await client.GetConfigurationSettingAsync(nameof(ConfigurationSetting.Key));
Coming Soon testcontainers/testcontainers-dotnet#1198
var container = new AzureAppConfigurationBuilder().Build();
await container.StartAsync();
var client = new ConfigurationClient(container.GetConnectionString());
await client.SetConfigurationSettingAsync(nameof(ConfigurationSetting.Key), nameof(ConfigurationSetting.Value));
var response = await client.GetConfigurationSettingAsync(nameof(ConfigurationSetting.Key));