Restrict POST /configuration endpoint to loopback#3669
Conversation
The POST /configuration endpoint used in late-configured (hosted) mode now requires the request to originate from a loopback address. An optional bootstrap token (DAB_CONFIG_AUTH_TOKEN env var, X-DAB-CONFIG-AUTH header) can be required as an additional check. Backward compatible: in-process callers (TestServer) and loopback callers without a token continue to work.
There was a problem hiding this comment.
Pull request overview
This PR hardens the late-bound hosted-mode POST /configuration bootstrap endpoint by restricting access to loopback callers and (optionally) requiring a bootstrap token header, reducing exposure prior to the auth middleware running.
Changes:
- Added
IsConfigurationRequestAuthorized(HttpContext)and enforced it in the/configurationgating middleware (returning403 Forbiddenwhen unauthorized). - Introduced optional bootstrap-token validation via
DAB_CONFIG_AUTH_TOKEN+X-DAB-CONFIG-AUTHusing fixed-time comparison. - Added new test coverage for authorization behavior across loopback/non-loopback and token combinations.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Service/Startup.cs | Adds loopback + optional bootstrap-token authorization gating for POST /configuration. |
| src/Service.Tests/Configuration/ConfigurationEndpointAuthorizationTests.cs | Adds unit + TestServer coverage for the new authorization behavior. |
- Handle ::ffff:127.0.0.1 (dual-stack Kestrel) as loopback by calling MapToIPv4 first - Fix stray quote in IsConfigurationRequestAuthorized XML doc - Add matrix row covering IPv4-mapped IPv6 loopback
…tion Other tests in the assembly (e.g. TestLoadingLocalCosmosSettings) set ASPNETCORE_ENVIRONMENT and DAB_ENVIRONMENT without cleanup. Those env vars caused FileSystemRuntimeConfigLoader to find an environment-specific dab-config.*.json on disk and auto-initialize the runtime, which made POST /configuration return 409 Conflict before the new security middleware was exercised, breaking the EndToEnd matrix in CI. Snapshot and clear ASPNETCORE_ENVIRONMENT and DAB_ENVIRONMENT before creating the TestServer, and restore them in a finally block. Verified locally by setting ASPNETCORE_ENVIRONMENT=CosmosDb_NoSql in the parent shell and rerunning all 22 tests successfully.
anushakolan
left a comment
There was a problem hiding this comment.
Just a minor comment to address; otherwise LGTM.
It would be helpful to create a tracking task and link it to this PR, along with relevant context. This makes it easier to understand the background and motivations for the change in the future.
RubenCerna2079
left a comment
There was a problem hiding this comment.
LGTM! Approving with the expectation that the comment from Anusha gets resolved.
Addresses two review comments on PR #3669: 1. (anushakolan) Move DAB_CONFIG_AUTH_TOKEN, ASPNETCORE_ENVIRONMENT, and DAB_ENVIRONMENT snapshot/restore into TestInitialize/TestCleanup so any pre-existing values are preserved verbatim. Previously TestCleanup reset DAB_CONFIG_AUTH_TOKEN to null which could perturb other tests. 2. (RubenCerna2079) Add explicit unit-test matrix rows for private/public IPv4 with correct token, wrong token, and missing header so the 'non-loopback is always denied regardless of token' contract is regression-locked. Matrix grows from 14 to 18 rows; total tests 22 -> 26. Verified locally by setting both ASPNETCORE_ENVIRONMENT=CosmosDb_NoSql and DAB_CONFIG_AUTH_TOKEN=preexisting-value in the parent shell: all 26 tests pass and both env vars retain their original values after the run.
…3671) Cherry-pick of #3669 (commit 7a0d7e3) onto `release/2.0`. ## Summary Restricts the late-configured `POST /configuration` endpoint to loopback callers, with an optional bootstrap token via `DAB_CONFIG_AUTH_TOKEN` / `X-DAB-CONFIG-AUTH` (fixed-time comparison). Addresses CWE-306 on the hosted-mode bootstrap channel. ## Change - `src/Service/Startup.cs`: added `IsConfigurationRequestAuthorized(HttpContext)` and wired it into the existing `POST /configuration` gating middleware (returns 403 when unauthorized). Null `RemoteIpAddress` (in-process callers like TestServer) treated as loopback. IPv4-mapped IPv6 normalized via `MapToIPv4()` before `IPAddress.IsLoopback`. - `src/Service.Tests/Configuration/ConfigurationEndpointAuthorizationTests.cs`: 26 tests (18 unit matrix + 8 end-to-end TestServer rows). ## Backward compatibility - Azure Static Web Apps platform config injector (loopback inside the container) keeps working unchanged. - In-process `TestServer` callers keep working unchanged. - Bootstrap token is opt-in -- behavior on loopback matches today's when `DAB_CONFIG_AUTH_TOKEN` is unset. ## Validation - Clean cherry-pick (no conflicts; `src/Service/Startup.cs` auto-merged). - `dotnet build` clean (0 warnings, 0 errors). - All 26 `ConfigurationEndpointAuthorizationTests` pass locally on the cherry-pick branch.
Summary
Restrict the late-configured
POST /configurationendpoint so it is only callable from the loopback interface, with an optional bootstrap-token check on top.Why
POST /configurationis used in hosted mode (e.g. Azure Static Web Apps) to deliver the runtime config — including the database connection string — to an uninitialized DAB instance. It currently runs before the authentication middleware and has no other access control, which is more permissive than required for what is effectively a host-to-runtime bootstrap channel.Change
In
src/Service/Startup.cs, the existing middleware that gatesPOST /configurationnow also checksIsConfigurationRequestAuthorized(HttpContext)and returns403 Forbiddenif it fails. The check enforces:RemoteIpAddress(in-process callers such asTestServer) is treated as loopback.DAB_CONFIG_AUTH_TOKENenvironment variable is set, the request must include a matchingX-DAB-CONFIG-AUTHheader (fixed-time comparison).The rest of the middleware ordering is unchanged.
Backward compatibility
TestServertests keep working unchanged.Tests