{"id":19444452,"url":"https://github.com/tnc1997/azure-app-configuration-emulator","last_synced_at":"2025-04-25T01:30:41.953Z","repository":{"id":197595823,"uuid":"698856292","full_name":"tnc1997/azure-app-configuration-emulator","owner":"tnc1997","description":"Please note that Emulator for Azure App Configuration is unofficial and not endorsed by Microsoft.","archived":false,"fork":false,"pushed_at":"2024-06-15T20:40:26.000Z","size":202,"stargazers_count":3,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-06-15T21:40:31.963Z","etag":null,"topics":["azure-app-configuration","emulator"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tnc1997.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-01T07:17:53.000Z","updated_at":"2024-06-15T20:40:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"63fc10de-9228-44f9-92ff-0bb46752d318","html_url":"https://github.com/tnc1997/azure-app-configuration-emulator","commit_stats":null,"previous_names":["tnc1997/azure-app-configuration-emulator"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnc1997%2Fazure-app-configuration-emulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnc1997%2Fazure-app-configuration-emulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnc1997%2Fazure-app-configuration-emulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tnc1997%2Fazure-app-configuration-emulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tnc1997","download_url":"https://codeload.github.com/tnc1997/azure-app-configuration-emulator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223976321,"owners_count":17234751,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure-app-configuration","emulator"],"created_at":"2024-11-10T16:07:05.024Z","updated_at":"2024-11-10T16:07:05.578Z","avatar_url":"https://github.com/tnc1997.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Emulator for Azure App Configuration\n\n![Docker Pulls](https://img.shields.io/docker/pulls/tnc1997/azure-app-configuration-emulator?link=https%3A%2F%2Fhub.docker.com%2Fr%2Ftnc1997%2Fazure-app-configuration-emulator) ![Docker Stars](https://img.shields.io/docker/stars/tnc1997/azure-app-configuration-emulator?link=https%3A%2F%2Fhub.docker.com%2Fr%2Ftnc1997%2Fazure-app-configuration-emulator)\n\nPlease note that Emulator for Azure App Configuration is unofficial and not endorsed by Microsoft.\n\n## Getting Started\n\n```shell\ndocker pull tnc1997/azure-app-configuration-emulator\ndocker run -p 8080:8080 tnc1997/azure-app-configuration-emulator\n```\n\n## Authentication\n\nThe emulator supports HMAC authentication and Microsoft Entra ID authentication.\n\n### HMAC\n\nThe credential and secret may be overridden using the environment variables `Authentication__Schemes__Hmac__Credential` and `Authentication__Schemes__Hmac__Secret` respectively.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - Authentication__Schemes__Hmac__Credential=xyz\n      - Authentication__Schemes__Hmac__Secret=c2VjcmV0\n    image: tnc1997/azure-app-configuration-emulator\n```\n\n#### .NET\n\nThe client may authenticate requests using the connection string for the emulator.\n\n```csharp\nusing Azure.Data.AppConfiguration;\n\nvar connectionString = Environment.GetEnvironmentVariable(\"ConnectionStrings__AzureAppConfiguration\");\nvar client = new ConfigurationClient(connectionString);\n\nvar setting = new ConfigurationSetting(\"AzureAppConfigurationEmulator\", \"Hello World\");\nawait client.SetConfigurationSettingAsync(setting);\n```\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    image: tnc1997/azure-app-configuration-emulator\n  console-application:\n    build:\n      context: .\n      dockerfile: ./ConsoleApplication/Dockerfile\n    depends_on:\n      - azure-app-configuration-emulator\n    environment:\n      - ConnectionStrings__AzureAppConfiguration=Endpoint=http://azure-app-configuration-emulator:8080;Id=abcd;Secret=c2VjcmV0;\n```\n\n#### Postman\n\nThe authentication related headers may be generated using the following script:\n\n```javascript\nconst credential = \"abcd\";\nconst secret = \"c2VjcmV0\";\n\nconst date = new Date().toUTCString();\nconst contentHash = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(pm.request.body.toString())).toString(CryptoJS.enc.Base64);\n\nconst signedHeaders = \"x-ms-date;Host;x-ms-content-sha256\";\nconst stringToSign = `${pm.request.method}\\n${pm.request.url.getPathWithQuery()}\\n${date};${pm.request.url.getRemote()};${contentHash}`;\nconst signature = CryptoJS.HmacSHA256(CryptoJS.enc.Utf8.parse(stringToSign), CryptoJS.enc.Base64.parse(secret)).toString(CryptoJS.enc.Base64);\n\npm.request.headers.upsert(`x-ms-date: ${date}`);\npm.request.headers.upsert(`x-ms-content-sha256: ${contentHash}`);\npm.request.headers.upsert(`Authorization: HMAC-SHA256 Credential=${credential}\u0026SignedHeaders=${signedHeaders}\u0026Signature=${signature}`);\n```\n\n### Microsoft Entra ID\n\nHMAC authentication is recommended because it does not require a Microsoft Entra tenant and an Azure App Configuration resource.\n\n1. [Register an application](https://learn.microsoft.com/entra/identity-platform/quickstart-register-app) within the Microsoft Entra tenant.\n    1. On the Overview page, in the Essentials accordion, copy the following values:\n        * Application (client) ID\n        * Directory (tenant) ID\n    2. On the Certificates \u0026 secrets page, in the Client secrets tab, add a client secret.\n2. [Create an Azure App Configuration resource](https://learn.microsoft.com/azure/azure-app-configuration/quickstart-azure-app-configuration-create) to be emulated.\n    1. On the Overview page, in the Essentials accordion, copy the following values:\n        * Endpoint\n    2. On the Access control (IAM) page, add a role assignment.\n        1. In the Role tab, select the App Configuration Data Owner role.\n        2. In the Members tab, assign access to the registered application.\n3. [Generate a self-signed certificate](#ssl--tls) with the `\u003cendpoint\u003e` as the [Subject Alternative Name](https://wikipedia.org/wiki/Subject_Alternative_Name).\n\nThe metadata address must be set using the environment variable `Authentication__Schemes__MicrosoftEntraId__MetadataAddress`.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - ASPNETCORE_HTTP_PORTS=80\n      - ASPNETCORE_HTTPS_PORTS=443\n      - Authentication__Schemes__MicrosoftEntraId__MetadataAddress=https://login.microsoftonline.com/\u003ctenant-id\u003e/v2.0/.well-known/openid-configuration\n    image: tnc1997/azure-app-configuration-emulator\n    networks:\n      default:\n        aliases:\n          - \u003cendpoint\u003e\n    volumes:\n      - ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro\n      - ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro\n```\n\nThe valid audience should be overriden using the environment variable `Authentication__Schemes__MicrosoftEntraId__ValidAudience`.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - ASPNETCORE_HTTP_PORTS=80\n      - ASPNETCORE_HTTPS_PORTS=443\n      - Authentication__Schemes__MicrosoftEntraId__MetadataAddress=https://login.microsoftonline.com/\u003ctenant-id\u003e/.well-known/openid-configuration\n      - Authentication__Schemes__MicrosoftEntraId__ValidAudience=https://\u003cendpoint\u003e\n    image: tnc1997/azure-app-configuration-emulator\n    networks:\n      default:\n        aliases:\n          - \u003cendpoint\u003e\n    volumes:\n      - ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro\n      - ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro\n```\n\n#### .NET\n\nThe client may authenticate requests using the Microsoft Entra tenant.\n\n```csharp\nusing Azure.Data.AppConfiguration;\nusing Azure.Identity;\n\nvar tenantId = Environment.GetEnvironmentVariable(\"Authentication__Schemes__MicrosoftEntraId__TenantId\");\nvar clientId = Environment.GetEnvironmentVariable(\"Authentication__Schemes__MicrosoftEntraId__ClientId\");\nvar clientSecret = Environment.GetEnvironmentVariable(\"Authentication__Schemes__MicrosoftEntraId__ClientSecret\");\nvar credential = new ClientSecretCredential(tenantId, clientId, clientSecret);\n\nvar endpoint = Environment.GetEnvironmentVariable(\"Endpoints__AzureAppConfiguration\");\nvar client = new ConfigurationClient(new Uri(endpoint), credential);\n\nvar setting = new ConfigurationSetting(\"AzureAppConfigurationEmulator\", \"Hello World\");\nawait client.SetConfigurationSettingAsync(setting);\n```\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - ASPNETCORE_HTTP_PORTS=80\n      - ASPNETCORE_HTTPS_PORTS=443\n      - Authentication__Schemes__MicrosoftEntraId__MetadataAddress=https://login.microsoftonline.com/\u003ctenant-id\u003e/.well-known/openid-configuration\n      - Authentication__Schemes__MicrosoftEntraId__ValidAudience=https://\u003cendpoint\u003e\n    image: tnc1997/azure-app-configuration-emulator\n    networks:\n      default:\n        aliases:\n          - \u003cendpoint\u003e\n    volumes:\n      - ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro\n      - ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro\n  console-application:\n    build:\n      context: .\n      dockerfile: ./ConsoleApplication/Dockerfile\n    depends_on:\n      - azure-app-configuration-emulator\n    entrypoint: /bin/sh -c \"update-ca-certificates \u0026\u0026 dotnet ConsoleApplication.dll\"\n    environment:\n      - Authentication__Schemes__MicrosoftEntraId__ClientId=\u003cclient-id\u003e\n      - Authentication__Schemes__MicrosoftEntraId__ClientSecret=\u003cclient-secret\u003e\n      - Authentication__Schemes__MicrosoftEntraId__TenantId=\u003ctenant-id\u003e\n      - Endpoints__AzureAppConfiguration=https://\u003cendpoint\u003e\n    volumes:\n      - ./emulator.crt:/usr/local/share/ca-certificates/emulator.crt:ro\n```\n\n#### Postman\n\nThe access token may be obtained using the following configuration:\n\n| Configuration    |                                                                   |\n|------------------|-------------------------------------------------------------------|\n| Auth Type        | OAuth 2.0                                                         |\n| Grant Type       | Client Credentials                                                |\n| Access Token URL | `https://login.microsoftonline.com/\u003ctenant-id\u003e/oauth2/v2.0/token` |\n| Client ID        | `\u003cclient-id\u003e`                                                     |\n| Client Secret    | `\u003cclient-secret\u003e`                                                 |\n| Scope            | `https://\u003cendpoint\u003e/.default`                                     |\n\n## Compatibility\n\nThe emulator is compatible with the following operations:\n\n### Key Values\n\n| Operation                |     |\n|--------------------------|-----|\n| Get                      | ✔️  |\n| Get (Conditionally)      | ✔️  |\n| Get (Select Fields)      | ✔️  |\n| Get (Time-Based Access)  | ✔️  |\n| List                     | ✔️  |\n| List (Pagination)        | ❌   |\n| List (Filtering)         | ✔️  |\n| List (Select Fields)     | ✔️  |\n| List (Time-Based Access) | ✔️  |\n| Set                      | ✔️  |\n| Set (Conditionally)      | ✔️  |\n| Delete                   | ✔️  |\n| Delete (Conditionally)   | ✔️  |\n\n### Keys\n\n| Operation                |    |\n|--------------------------|----|\n| List                     | ✔️ |\n| List (Pagination)        | ❌  |\n| List (Filtering)         | ✔️ |\n| List (Select Fields)     | ✔️ |\n| List (Time-Based Access) | ✔️ |\n\n### Labels\n\n| Operation                |    |\n|--------------------------|----|\n| List                     | ✔️ |\n| List (Pagination)        | ❌  |\n| List (Filtering)         | ✔️ |\n| List (Select Fields)     | ✔️ |\n| List (Time-Based Access) | ✔️ |\n\n### Locks\n\n| Operation              |    |\n|------------------------|----|\n| Lock                   | ✔️ |\n| Lock (Conditionally)   | ✔️ |\n| Unlock                 | ✔️ |\n| Unlock (Conditionally) | ✔️ |\n\n### Revisions\n\n| Operation                |   |\n|--------------------------|---|\n| List                     | ❌ |\n| List (Pagination)        | ❌ |\n| List (Range)             | ❌ |\n| List (Filtering)         | ❌ |\n| List (Select Fields)     | ❌ |\n| List (Time-Based Access) | ❌ |\n\n## Data\n\nThe emulator stores configuration settings in a [SQLite](https://sqlite.org) database.\n\nThe data that is generated by the emulator during a session may be persisted between sessions using a [volume](https://docs.docker.com/storage/volumes).\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    image: tnc1997/azure-app-configuration-emulator\n    volumes:\n      - azure-app-configuration-emulator:/var/lib/azureappconfigurationemulator\nvolumes:\n  azure-app-configuration-emulator:\n```\n\nThe connection string for the database may be overridden using the environment variable `ConnectionStrings__DefaultConnection`.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - ConnectionStrings__DefaultConnection=Data Source=/var/lib/azureappconfigurationemulator/emulator.db\n    image: tnc1997/azure-app-configuration-emulator\n```\n\nThe 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.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    image: tnc1997/azure-app-configuration-emulator\n    volumes:\n      - ./emulator.db:/var/lib/azureappconfigurationemulator/emulator.db\n```\n\n## Messaging\n\nThe emulator integrates with Azure Event Grid to publish events using the [Event Grid event schema](https://learn.microsoft.com/en-us/azure/event-grid/custom-topics#event-grid-event-schema) when configuration settings are deleted or modified.\n\nThe endpoint and key for the [Event Grid Topic](https://learn.microsoft.com/en-us/azure/event-grid/custom-topics) may be set using the environment variables `Messaging__EventGridTopics__xyz__Endpoint` and `Messaging__EventGridTopics__xyz__Credential__Key` respectively where `xyz` is an arbitrary name.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - Messaging__EventGridTopics__Contoso__Credential__Key=a2V5\n      - Messaging__EventGridTopics__Contoso__Endpoint=https://contoso.uksouth-1.eventgrid.azure.net/api/events\n    image: tnc1997/azure-app-configuration-emulator\n```\n\n## Observability\n\nThe emulator integrates with OpenTelemetry to provide metrics and traces.\n\nThe endpoint for the [OpenTelemetry Protocol (OTLP) Exporter](https://opentelemetry.io/docs/specs/otel/protocol/exporter) may be overridden using the environment variable `OTEL_EXPORTER_OTLP_ENDPOINT`.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    depends_on:\n      - opentelemetry-collector\n    environment:\n      - OTEL_EXPORTER_OTLP_ENDPOINT=http://opentelemetry-collector:4317\n    image: tnc1997/azure-app-configuration-emulator\n  opentelemetry-collector:\n    image: otel/opentelemetry-collector-contrib\n```\n\n## SSL / TLS\n\nThe emulator may be configured to serve requests over HTTPS using a [self-signed certificate](https://wikipedia.org/wiki/self-signed_certificate).\n\n```shell\nopenssl 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'\n```\n\nThe port for HTTPS must be set using the environment variable [`ASPNETCORE_HTTPS_PORTS`](https://learn.microsoft.com/aspnet/core/security/enforcing-ssl#port-configuration).\n\nThe paths for the certificate and key must be set using the environment variables `Kestrel__Certificates__Default__Path` and `Kestrel__Certificates__Default__KeyPath` respectively.\n\nThe certificate and key must be [mounted](https://docs.docker.com/storage/bind-mounts) into the container at the paths that are set above.\n\n```yaml\nservices:\n  azure-app-configuration-emulator:\n    environment:\n      - ASPNETCORE_HTTP_PORTS=8080\n      - ASPNETCORE_HTTPS_PORTS=8081\n      - Kestrel__Certificates__Default__Path=/usr/local/share/azureappconfigurationemulator/emulator.crt\n      - Kestrel__Certificates__Default__KeyPath=/usr/local/share/azureappconfigurationemulator/emulator.key\n    image: tnc1997/azure-app-configuration-emulator\n    volumes:\n      - ./emulator.crt:/usr/local/share/azureappconfigurationemulator/emulator.crt:ro\n      - ./emulator.key:/usr/local/share/azureappconfigurationemulator/emulator.key:ro\n```\n\n## Testcontainers\n\nThe emulator integrates with [Testcontainers](https://testcontainers.org) to ease the integration testing of applications that use Azure App Configuration.\n\n```csharp\nvar container = new ContainerBuilder()\n    .WithImage(\"tnc1997/azure-app-configuration-emulator:1.0\")\n    .WithPortBinding(8080, true)\n    .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged(\"Now listening on\"))\n    .Build();\n\nawait container.StartAsync();\n\nvar client = new ConfigurationClient($\"Endpoint={new UriBuilder(Uri.UriSchemeHttp, container.Hostname, container.GetMappedPublicPort(8080))};Id=abcd;Secret=c2VjcmV0\");\n\nawait client.SetConfigurationSettingAsync(nameof(ConfigurationSetting.Key), nameof(ConfigurationSetting.Value));\n\nvar response = await client.GetConfigurationSettingAsync(nameof(ConfigurationSetting.Key));\n```\n\n**Coming Soon** [testcontainers/testcontainers-dotnet#1198](https://github.com/testcontainers/testcontainers-dotnet/issues/1198)\n\n```csharp\nvar container = new AzureAppConfigurationBuilder().Build();\n\nawait container.StartAsync();\n\nvar client = new ConfigurationClient(container.GetConnectionString());\n\nawait client.SetConfigurationSettingAsync(nameof(ConfigurationSetting.Key), nameof(ConfigurationSetting.Value));\n\nvar response = await client.GetConfigurationSettingAsync(nameof(ConfigurationSetting.Key));\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftnc1997%2Fazure-app-configuration-emulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftnc1997%2Fazure-app-configuration-emulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftnc1997%2Fazure-app-configuration-emulator/lists"}