review(Host): allow-anonymous /metrics + unconditional LDAP validator
Code review at HEAD 7286d320. Host-001 (High): /metrics was auth-gated on admin
nodes (Prometheus 401) -> AllowAnonymous. Host-002: register LdapOptionsValidator
unconditionally for fail-fast startup validation on admin-only nodes. Host-004: fix
metrics XML doc. Host-003 (docs) left Open.
This commit is contained in:
@@ -37,14 +37,16 @@ public static class ObservabilityExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mounts the Prometheus scrape endpoint on the existing ASP.NET pipeline. Call after
|
||||
/// <c>app.UseAuthentication/UseAuthorization</c> if metrics access should require auth;
|
||||
/// the default leaves it unauthenticated for local Prometheus scrapes.
|
||||
/// Mounts the Prometheus <c>/metrics</c> scrape endpoint on the existing ASP.NET pipeline.
|
||||
/// The endpoint is explicitly marked <c>AllowAnonymous</c> so unauthenticated Prometheus
|
||||
/// scrapers can reach it regardless of the host's auth fallback policy (which on admin-role
|
||||
/// nodes is <c>RequireAuthenticatedUser</c>). This mirrors the behaviour of
|
||||
/// <c>MapZbHealth</c>, which also marks its endpoints anonymous.
|
||||
/// </summary>
|
||||
/// <param name="app">The endpoint route builder.</param>
|
||||
public static IEndpointRouteBuilder MapOtOpcUaMetrics(this IEndpointRouteBuilder app)
|
||||
{
|
||||
app.MapZbMetrics();
|
||||
app.MapZbMetrics().AllowAnonymous();
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,13 @@ builder.AddZbSerilog(o => o.ServiceName = "otopcua");
|
||||
builder.Services.AddOtOpcUaConfigDb(builder.Configuration);
|
||||
builder.Services.AddOtOpcUaCluster(builder.Configuration);
|
||||
|
||||
// Validate LdapOptions unconditionally so ANY role node (admin-only, driver-only, or fused)
|
||||
// fails fast at startup on a misconfigured or insecure-transport LDAP section.
|
||||
// The validator's own guard (if !Enabled || DevStubMode) keeps it a safe no-op on disabled/dev
|
||||
// configs. Previously this was inside the hasDriver block, which left admin-only nodes without
|
||||
// the startup check (AddOtOpcUaAuth binds LdapOptions but does not attach a validator).
|
||||
builder.Services.AddValidatedOptions<LdapOptions, LdapOptionsValidator>(builder.Configuration, LdapOptions.SectionName);
|
||||
|
||||
if (hasDriver)
|
||||
{
|
||||
builder.Services.AddOtOpcUaRuntime();
|
||||
@@ -160,7 +167,6 @@ if (hasDriver)
|
||||
ScriptRootLoggerFactory.Build(
|
||||
sp.GetRequiredService<IScriptLogPublisher>(), scriptLogFilePath, scriptLogTopicMinLevel, Serilog.Log.Logger)));
|
||||
|
||||
builder.Services.AddValidatedOptions<LdapOptions, LdapOptionsValidator>(builder.Configuration, LdapOptions.SectionName);
|
||||
// TryAdd so a fused admin+driver node (where AddOtOpcUaAuth also registers these) ends up
|
||||
// with exactly one descriptor; on a driver-only node these are the sole registrations.
|
||||
// OtOpcUaLdapAuthService is the app ILdapAuthService (Enabled switch + DevStubMode over the
|
||||
@@ -168,6 +174,8 @@ if (hasDriver)
|
||||
// <string> per call to turn the directory's groups into roles, so register it here for driver-
|
||||
// only nodes (AddOtOpcUaAuth registers it on admin nodes); ILdapGroupRoleMappingService it
|
||||
// depends on is already registered unconditionally by AddOtOpcUaConfigDb above.
|
||||
// Note: AddValidatedOptions<LdapOptions, LdapOptionsValidator> is now registered unconditionally
|
||||
// above both role blocks so admin-only nodes also get fail-fast LDAP startup validation.
|
||||
builder.Services.TryAddSingleton<ILdapAuthService, OtOpcUaLdapAuthService>();
|
||||
builder.Services.TryAddScoped<IGroupRoleMapper<string>, OtOpcUaGroupRoleMapper>();
|
||||
builder.Services.AddSingleton<IOpcUaUserAuthenticator, LdapOpcUaUserAuthenticator>();
|
||||
|
||||
Reference in New Issue
Block a user