Skip to content

Migrating to secure defaults

Some Arc defaults used to be convenient but unsafe on a deployed host. Arc now ships safe defaults instead. Read each section below and check whether your application relies on the old behavior. Each section ends with the single change that restores it.

Forwarded identity headers need an explicit opt-in

Section titled “Forwarded identity headers need an explicit opt-in”

Who is affected: applications that authenticate users through the unsigned x-ms-client-principal, x-ms-client-principal-id and x-ms-client-principal-name headers. That is every application that calls builder.AddCratis(), or builder.Services.AddMicrosoftIdentityPlatformIdentityAuthentication(), and runs behind Azure App Service or Container Apps authentication (EasyAuth) or Cratis AuthProxy. On the Arc.Core HttpListener host it is every application that relies on the built-in MicrosoftIdentityPlatformAuthenticationHandler.

What changed: Arc used to trust these headers from any caller. Anyone who could reach the application directly could send them and act as any user. Arc now ignores them until the host opts in. Without the opt-in, these headers do not authenticate requests; endpoints that require an authenticated user return 401 unless another authentication scheme authenticates the caller.

How to tell: an ASP.NET Core host that calls AddMicrosoftIdentityPlatformIdentityAuthentication() (including through AddCratis()) without the opt-in logs a warning that names the setting on every startup. The built-in header handlers log a warning on the first request that carries the headers while they are not trusted.

What to do: if every request reaches your application through an ingress that strips caller-supplied identity headers and sets its own, opt in. In a C# host, add one line to the options you pass to AddCratis or AddCratisArc:

builder.AddCratis(options => options.TrustForwardedIdentityHeaders = true);

View C# snippet source on GitHub

Or in configuration, for example as the environment variable Cratis__Arc__TrustForwardedIdentityHeaders=true:

{
"Cratis": {
"Arc": {
"TrustForwardedIdentityHeaders": true
}
}
}

If the application can be reached without going through such an ingress, do not opt in: configure a real authentication scheme instead.

Cratis:Arc:Introspection:TrustForwardedIdentityHeaders is now obsolete. Setting it still turns on the host-wide TrustForwardedIdentityHeaders, so a host that already set it keeps working. Move the setting to Cratis:Arc:TrustForwardedIdentityHeaders. Startup no longer refuses protected catalogs behind the header scheme, because the scheme authenticates nobody until the host opts in.

See Microsoft Identity.

Discovery endpoints require authentication outside Development

Section titled “Discovery endpoints require authentication outside Development”

Who is affected: applications or tools that read the discovery endpoints of a host running outside Development without signing in. The discovery endpoints are the command and query catalogs (/.cratis/commands and /.cratis/queries) and identity discovery (/.cratis/users, /.cratis/tenants and /.cratis/identity-details/schema). Command and query invocation and /.cratis/me are not affected.

What changed: these endpoints used to be anonymous in every environment. They are now anonymous only in Development, where Lens and the Cratis CLI read them locally. Everywhere else they require an authenticated caller, so an anonymous request gets 401. A host outside Development that has no way to authenticate callers, such as an ASP.NET Core host without a default authentication scheme or an Arc.Core host without authentication handlers, does not map them at all (404) and logs a warning that names the setting below on startup. Development is decided by the host’s IHostEnvironment.IsDevelopment(), including environment names configured through DOTNET_ENVIRONMENT, command-line arguments or host options. Only when no host environment is registered does Arc fall back to ASPNETCORE_ENVIRONMENT.

What to do: nothing, if only signed-in users or local tooling read these endpoints. To expose them anonymously as before, add one line to the options in a C# host that you pass to AddCratis or AddCratisArc:

builder.AddCratisArc(options => options.Introspection.RequireAuthentication = false);

View C# snippet source on GitHub

Or set Cratis__Arc__Introspection__RequireAuthentication=false. Outside Development the host then logs a warning on startup that the endpoints are anonymous.

Introspection.RequireAuthentication remains a bool for source compatibility. Its getter returns false when unset, but leaving it unset selects the environment default; explicitly assigning false opts into anonymous discovery in every environment. Introspection.Roles now implies authentication on its own instead of needing RequireAuthentication: true.

See Introspection.