Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Host/appsettings.Central.json
T

88 lines
4.3 KiB
JSON

{
"ScadaBridge": {
"_secretsClusterPosture": "Central pair KEK/store posture (production): see docs/operations/2026-07-16-secrets-clustered-master-key.md. Committed default is Source=Environment + relative SqlitePath (dev-safe); production uses a File KEK + shared store volume delivered out-of-band. Do NOT hardcode /shared paths here — the pre-host expander migrates the store at every Central boot and would break dev/test.",
"_nodeName": "Host-018: NodeName stamps SourceNode on AuditLog/Notifications/SiteCalls rows (CLAUDE.md 'Centralized Audit Log' decision) and backs IX_AuditLog_Node_Occurred. Convention: 'central-a'/'central-b' for central nodes, 'node-a'/'node-b' for site nodes. Override per-node in multi-node deployments (the docker per-node configs do this). When left at the default below, single-node dev rows are stamped with 'central-a'; an empty value normalises to a NULL SourceNode.",
"Node": {
"Role": "Central",
"NodeHostname": "localhost",
"RemotingPort": 8081,
"NodeName": "central-a"
},
"Cluster": {
"SeedNodes": [
"akka.tcp://scadabridge@localhost:8081",
"akka.tcp://scadabridge@localhost:8082"
],
"SplitBrainResolverStrategy": "keep-oldest",
"StableAfter": "00:00:15",
"HeartbeatInterval": "00:00:02",
"FailureDetectionThreshold": "00:00:10",
"MinNrOfMembers": 1
},
"_secrets": "Host-003: Secrets are NOT committed in this file. The ${secret:...} references below are resolved at startup by the pre-host secrets expander (before StartupValidator runs) from the encrypted secrets store (SQLite, seeded via the ZB.MOM.WW.Secrets store/CLI/UI). The KEK is supplied out-of-band via the ZB_SECRETS_MASTER_KEY environment variable and never committed; an unseeded reference fails closed (SecretNotFoundException) before any SQL/LDAP/cluster wiring. ROLLBACK: the whole-key environment override still wins — set ScadaBridge__Database__ConfigurationDb / ScadaBridge__Security__Ldap__ServiceAccountPassword / ScadaBridge__Security__JwtSigningKey and .AddEnvironmentVariables() overlays the concrete value before expansion runs, so the ${secret:...} token is never evaluated. NOTE (Task 1.4): the LDAP settings moved into the nested Security:Ldap sub-section (bound to the shared ZB.MOM.WW.Auth LdapOptions) — the service-account-password env var is ScadaBridge__Security__Ldap__ServiceAccountPassword (was ScadaBridge__Security__LdapServiceAccountPassword).",
"Database": {
"ConfigurationDb": "${secret:sql/scadabridge/configdb-connection}"
},
"Security": {
"Ldap": {
"Server": "localhost",
"Port": 3893,
"Transport": "None",
"AllowInsecure": true,
"SearchBase": "dc=zb,dc=local",
"ServiceAccountDn": "cn=admin,dc=zb,dc=local",
"ServiceAccountPassword": "${secret:ldap/scadabridge/service-account-password}"
},
"JwtSigningKey": "${secret:security/scadabridge/jwt-signing-key}",
"JwtExpiryMinutes": 15,
"IdleTimeoutMinutes": 30
},
"Communication": {
"DeploymentTimeout": "00:02:00",
"LifecycleTimeout": "00:00:30",
"QueryTimeout": "00:00:30",
"TransportHeartbeatInterval": "00:00:05",
"TransportFailureThreshold": "00:00:15",
"CentralFetchBaseUrl": "http://localhost:5000"
},
"HealthMonitoring": {
"ReportInterval": "00:00:30",
"OfflineTimeout": "00:01:00"
},
"InboundApi": {
"DefaultMethodTimeout": "00:00:30"
},
"Notification": {
"SmtpServer": "localhost",
"SmtpPort": 1025,
"AuthMode": "None",
"FromAddress": "scada-notifications@company.com"
},
"NotificationOutbox": {
"DispatchInterval": "00:00:10",
"DispatchBatchSize": 100,
"StuckAgeThreshold": "00:10:00",
"TerminalRetention": "365.00:00:00",
"PurgeInterval": "1.00:00:00",
"DeliveredKpiWindow": "00:01:00"
},
"KpiHistory": {
"SampleInterval": "00:01:00",
"RetentionDays": 90,
"PurgeInterval": "1.00:00:00",
"DefaultMaxSeriesPoints": 200
},
"Transport": {
"BundleSessionTtlMinutes": 30,
"MaxBundleSizeMb": 100,
"MaxUnlockAttemptsPerSession": 3,
"MaxUnlockAttemptsPerIpPerHour": 10,
"Pbkdf2Iterations": 600000,
"SchemaVersionMajor": 1
},
"Logging": {
"MinimumLevel": "Information"
}
}
}