infra(docker-env2)+infra(docker): init:true + secrets posture parity for env2; regen-proto EXIT trap (arch-review 2026-08-19 P8-2 + P8-3 + P8-4)
This commit is contained in:
@@ -20,20 +20,27 @@
|
||||
"MinNrOfMembers": 1
|
||||
},
|
||||
"Database": {
|
||||
"ConfigurationDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeConfig2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true",
|
||||
"MachineDataDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeMachineData2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
"_comment": "ConfigurationDb/MachineDataDb (which carry the dev SQL password) are supplied as ScadaBridge__Database__* whole-key env overrides in docker-env2/docker-compose.yml (dev-only-insecure, mirroring docker/docker-compose.yml and the ApiKeyPepper convention). The same dev password already ships committed for the sibling scadabridge-mssql container (infra/docker-compose.yml MSSQL_SA_PASSWORD) — this is consolidation, not new exposure. Env overrides layer over JSON before the ${secret:} expander runs, so the dev cluster boots with no KEK/secret store. Real/prod config uses ${secret:} tokens in src/.../appsettings.Central.json (T4)."
|
||||
},
|
||||
"Security": {
|
||||
"Ldap": {
|
||||
"Server": "10.100.0.35",
|
||||
"Server": "host.docker.internal",
|
||||
"Port": 3893,
|
||||
"FallbackServers": [
|
||||
"host.docker.internal:3894"
|
||||
],
|
||||
"_comment_FallbackServers": "Redundant local GLAuth pair (scadaproj/infra/glauth-redundant): zb-ldap-primary :3893 + zb-ldap-backup :3894 on the Docker host — mirrors docker/central-node-a/appsettings.Central.json. Replaces the shared 10.100.0.35 GLAuth, whose serviceaccount password was rotated (SEC-36) away from the rig's dev bind creds; env2 hit this directly (every login failing) before this fix.",
|
||||
"Transport": "None",
|
||||
"AllowInsecure": true,
|
||||
"SearchBase": "dc=zb,dc=local",
|
||||
"ServiceAccountDn": "cn=serviceaccount,dc=zb,dc=local",
|
||||
"ServiceAccountPassword": "serviceaccount123"
|
||||
"_comment_ServiceAccountPassword": "Supplied as ScadaBridge__Security__Ldap__ServiceAccountPassword env override in docker-env2/docker-compose.yml (dev-only-insecure)."
|
||||
},
|
||||
"JwtSigningKey": "scadabridge-env2-dev-jwt-signing-key-must-be-at-least-32-characters-long",
|
||||
"Auth": {
|
||||
"DisableLogin": false,
|
||||
"User": "multi-role"
|
||||
},
|
||||
"_comment_JwtSigningKey": "Supplied as ScadaBridge__Security__JwtSigningKey env override in docker-env2/docker-compose.yml (dev-only-insecure).",
|
||||
"JwtExpiryMinutes": 15,
|
||||
"IdleTimeoutMinutes": 30,
|
||||
"RequireHttpsCookie": false,
|
||||
|
||||
@@ -20,20 +20,27 @@
|
||||
"MinNrOfMembers": 1
|
||||
},
|
||||
"Database": {
|
||||
"ConfigurationDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeConfig2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true",
|
||||
"MachineDataDb": "Server=scadabridge-mssql,1433;Database=ScadaBridgeMachineData2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
"_comment": "ConfigurationDb/MachineDataDb (which carry the dev SQL password) are supplied as ScadaBridge__Database__* whole-key env overrides in docker-env2/docker-compose.yml (dev-only-insecure, mirroring docker/docker-compose.yml and the ApiKeyPepper convention). The same dev password already ships committed for the sibling scadabridge-mssql container (infra/docker-compose.yml MSSQL_SA_PASSWORD) — this is consolidation, not new exposure. Env overrides layer over JSON before the ${secret:} expander runs, so the dev cluster boots with no KEK/secret store. Real/prod config uses ${secret:} tokens in src/.../appsettings.Central.json (T4)."
|
||||
},
|
||||
"Security": {
|
||||
"Ldap": {
|
||||
"Server": "10.100.0.35",
|
||||
"Server": "host.docker.internal",
|
||||
"Port": 3893,
|
||||
"FallbackServers": [
|
||||
"host.docker.internal:3894"
|
||||
],
|
||||
"_comment_FallbackServers": "Redundant local GLAuth pair (scadaproj/infra/glauth-redundant): zb-ldap-primary :3893 + zb-ldap-backup :3894 on the Docker host — mirrors docker/central-node-b/appsettings.Central.json. Replaces the shared 10.100.0.35 GLAuth, whose serviceaccount password was rotated (SEC-36) away from the rig's dev bind creds; env2 hit this directly (every login failing) before this fix.",
|
||||
"Transport": "None",
|
||||
"AllowInsecure": true,
|
||||
"SearchBase": "dc=zb,dc=local",
|
||||
"ServiceAccountDn": "cn=serviceaccount,dc=zb,dc=local",
|
||||
"ServiceAccountPassword": "serviceaccount123"
|
||||
"_comment_ServiceAccountPassword": "Supplied as ScadaBridge__Security__Ldap__ServiceAccountPassword env override in docker-env2/docker-compose.yml (dev-only-insecure)."
|
||||
},
|
||||
"JwtSigningKey": "scadabridge-env2-dev-jwt-signing-key-must-be-at-least-32-characters-long",
|
||||
"Auth": {
|
||||
"DisableLogin": false,
|
||||
"User": "multi-role"
|
||||
},
|
||||
"_comment_JwtSigningKey": "Supplied as ScadaBridge__Security__JwtSigningKey env override in docker-env2/docker-compose.yml (dev-only-insecure).",
|
||||
"JwtExpiryMinutes": 15,
|
||||
"IdleTimeoutMinutes": 30,
|
||||
"RequireHttpsCookie": false,
|
||||
|
||||
@@ -11,6 +11,10 @@ x-secrets-store-env: &secrets-store-env
|
||||
services:
|
||||
central-a:
|
||||
image: scadabridge:latest
|
||||
# An init process (tini) as PID 1, so a crashed dotnet process actually dies
|
||||
# instead of wedging the container at 100% CPU with the restart policy never
|
||||
# firing — mirrors docker/docker-compose.yml's init: true (ScadaBridge#34).
|
||||
init: true
|
||||
# CoordinatedShutdown needs cluster-leave (15s budget) + cluster-exiting +
|
||||
# actor-system-terminate + Serilog flush; the 10s SIGTERM default SIGKILLed
|
||||
# mid-drain, turning every redeploy into the crash path (review 01 [Medium]).
|
||||
@@ -27,6 +31,25 @@ services:
|
||||
# pepper per the "different per environment" guidance; real deployments inject a
|
||||
# true secret out-of-band, never from source control. Both Central nodes share it.
|
||||
ScadaBridge__InboundApi__ApiKeyPepper: "dev-only-insecure-pepper-env2-cluster-0001"
|
||||
# DEV-ONLY local-cluster secrets — NOT real secrets. Relocated out of the mounted
|
||||
# appsettings.Central.json (mirrors docker/docker-compose.yml's G-4 T5 secrets
|
||||
# cleanup) so that app-config file carries no plaintext credentials. Env overrides
|
||||
# layer over JSON BEFORE the ${secret:} pre-host expander runs. The SQL password is
|
||||
# the same value already committed for the sibling scadabridge-mssql container
|
||||
# (infra/docker-compose.yml MSSQL_SA_PASSWORD) and for docker/'s central nodes —
|
||||
# consolidation, not new exposure; env2's Config2/MachineData2 databases live on
|
||||
# that SAME shared mssql container. Real deployments use ${secret:} tokens +
|
||||
# a seeded store.
|
||||
ScadaBridge__Database__ConfigurationDb: "Server=scadabridge-mssql,1433;Database=ScadaBridgeConfig2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
ScadaBridge__Database__MachineDataDb: "Server=scadabridge-mssql,1433;Database=ScadaBridgeMachineData2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
# LDAP bind credential for the redundant local GLAuth pair (scadaproj/infra/glauth-redundant,
|
||||
# host.docker.internal:3893/:3894 — see central-node-a/appsettings.Central.json). Same
|
||||
# value docker/'s central nodes use for the SAME local pair; the shared 10.100.0.35
|
||||
# GLAuth's serviceaccount password was rotated (SEC-36) and is no longer valid.
|
||||
ScadaBridge__Security__Ldap__ServiceAccountPassword: "serviceaccount123"
|
||||
# DEV-ONLY local-cluster secret — NOT a real secret. Distinct from docker/'s JWT key
|
||||
# so sessions cannot cross environments (see docker-env2/README.md).
|
||||
ScadaBridge__Security__JwtSigningKey: "scadabridge-env2-dev-jwt-signing-key-must-be-at-least-32-characters-long"
|
||||
# DEV-ONLY gRPC control-plane preshared key for site-x — NOT a real secret.
|
||||
# Must match ScadaBridge:Communication:GrpcPsk in site-x-node-*/appsettings.Site.json.
|
||||
# Production seeds SB-GRPC-PSK-<siteId> into the secret store instead.
|
||||
@@ -47,6 +70,7 @@ services:
|
||||
|
||||
central-b:
|
||||
image: scadabridge:latest
|
||||
init: true # PID-1 crash wedge, ScadaBridge#34 — see central-a
|
||||
# CoordinatedShutdown needs cluster-leave (15s budget) + cluster-exiting +
|
||||
# actor-system-terminate + Serilog flush; the 10s SIGTERM default SIGKILLed
|
||||
# mid-drain, turning every redeploy into the crash path (review 01 [Medium]).
|
||||
@@ -63,6 +87,25 @@ services:
|
||||
# pepper per the "different per environment" guidance; real deployments inject a
|
||||
# true secret out-of-band, never from source control. Both Central nodes share it.
|
||||
ScadaBridge__InboundApi__ApiKeyPepper: "dev-only-insecure-pepper-env2-cluster-0001"
|
||||
# DEV-ONLY local-cluster secrets — NOT real secrets. Relocated out of the mounted
|
||||
# appsettings.Central.json (mirrors docker/docker-compose.yml's G-4 T5 secrets
|
||||
# cleanup) so that app-config file carries no plaintext credentials. Env overrides
|
||||
# layer over JSON BEFORE the ${secret:} pre-host expander runs. The SQL password is
|
||||
# the same value already committed for the sibling scadabridge-mssql container
|
||||
# (infra/docker-compose.yml MSSQL_SA_PASSWORD) and for docker/'s central nodes —
|
||||
# consolidation, not new exposure; env2's Config2/MachineData2 databases live on
|
||||
# that SAME shared mssql container. Real deployments use ${secret:} tokens +
|
||||
# a seeded store.
|
||||
ScadaBridge__Database__ConfigurationDb: "Server=scadabridge-mssql,1433;Database=ScadaBridgeConfig2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
ScadaBridge__Database__MachineDataDb: "Server=scadabridge-mssql,1433;Database=ScadaBridgeMachineData2;User Id=scadabridge_app;Password=ScadaBridge_Dev1#;TrustServerCertificate=true"
|
||||
# LDAP bind credential for the redundant local GLAuth pair (scadaproj/infra/glauth-redundant,
|
||||
# host.docker.internal:3893/:3894 — see central-node-b/appsettings.Central.json). Same
|
||||
# value docker/'s central nodes use for the SAME local pair; the shared 10.100.0.35
|
||||
# GLAuth's serviceaccount password was rotated (SEC-36) and is no longer valid.
|
||||
ScadaBridge__Security__Ldap__ServiceAccountPassword: "serviceaccount123"
|
||||
# DEV-ONLY local-cluster secret — NOT a real secret. Distinct from docker/'s JWT key
|
||||
# so sessions cannot cross environments (see docker-env2/README.md).
|
||||
ScadaBridge__Security__JwtSigningKey: "scadabridge-env2-dev-jwt-signing-key-must-be-at-least-32-characters-long"
|
||||
# DEV-ONLY gRPC control-plane preshared key for site-x — NOT a real secret.
|
||||
# Must match ScadaBridge:Communication:GrpcPsk in site-x-node-*/appsettings.Site.json.
|
||||
# Production seeds SB-GRPC-PSK-<siteId> into the secret store instead.
|
||||
@@ -83,6 +126,7 @@ services:
|
||||
|
||||
site-x-a:
|
||||
image: scadabridge:latest
|
||||
init: true # PID-1 crash wedge, ScadaBridge#34 — see central-a
|
||||
# CoordinatedShutdown needs cluster-leave (15s budget) + cluster-exiting +
|
||||
# actor-system-terminate + Serilog flush; the 10s SIGTERM default SIGKILLed
|
||||
# mid-drain, turning every redeploy into the crash path (review 01 [Medium]).
|
||||
@@ -111,6 +155,7 @@ services:
|
||||
|
||||
site-x-b:
|
||||
image: scadabridge:latest
|
||||
init: true # PID-1 crash wedge, ScadaBridge#34 — see central-a
|
||||
# CoordinatedShutdown needs cluster-leave (15s budget) + cluster-exiting +
|
||||
# actor-system-terminate + Serilog flush; the 10s SIGTERM default SIGKILLed
|
||||
# mid-drain, turning every redeploy into the crash path (review 01 [Medium]).
|
||||
|
||||
+20
-8
@@ -50,12 +50,25 @@ if [[ ! -f "$CSPROJ" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Backup so we can always restore the comment state on failure. Leaving the
|
||||
# csproj with an active Protobuf item is the one outcome that breaks Docker, so
|
||||
# every exit path restores this copy.
|
||||
# Backup so we can always restore the comment state, however this script ends.
|
||||
# Leaving the csproj with an active Protobuf item is the one outcome that breaks
|
||||
# Docker, so every exit path restores this copy — success, a failed `dotnet
|
||||
# build` (ERR), or Ctrl-C (INT/TERM) mid-build. An EXIT trap covers all of
|
||||
# those (bash runs it on any shell termination, signals included), and the
|
||||
# guard on $BACKUP's existence makes it idempotent: the normal success path
|
||||
# below restores explicitly for prompt feedback, so by the time the trap fires
|
||||
# on a clean exit $BACKUP is already gone and it's a no-op instead of a second
|
||||
# restore/rm.
|
||||
BACKUP="$(mktemp)"
|
||||
cp "$CSPROJ" "$BACKUP"
|
||||
trap 'cp "$BACKUP" "$CSPROJ"; rm -f "$BACKUP"; echo "Restored csproj from backup."' ERR
|
||||
restore_csproj() {
|
||||
if [[ -f "$BACKUP" ]]; then
|
||||
cp "$BACKUP" "$CSPROJ"
|
||||
rm -f "$BACKUP"
|
||||
echo "Restored csproj from backup."
|
||||
fi
|
||||
}
|
||||
trap restore_csproj EXIT
|
||||
|
||||
# 1. Inject an ItemGroup holding just the selected protos, immediately before
|
||||
# the closing </Project>. The documented commented-out block is left alone.
|
||||
@@ -117,10 +130,9 @@ if [[ "$TARGET" == "sitecommand" || "$TARGET" == "all" ]]; then
|
||||
fi
|
||||
|
||||
# 5. Restore the backed-up csproj — i.e. drop the injected ItemGroup — so Docker
|
||||
# builds keep working.
|
||||
cp "$BACKUP" "$CSPROJ"
|
||||
rm -f "$BACKUP"
|
||||
trap - ERR
|
||||
# builds keep working. (Also covered by the EXIT trap above; calling it here
|
||||
# too just gives the success path its "Restored..." feedback before "Done".)
|
||||
restore_csproj
|
||||
|
||||
echo ""
|
||||
echo "Done. Review and commit:"
|
||||
|
||||
Reference in New Issue
Block a user