feat(install): historian TCP env + firewall rule
Replace OTOPCUA_HISTORIAN_PIPE/OTOPCUA_ALLOWED_SID with TCP transport env (OTOPCUA_HISTORIAN_TCP_PORT, OTOPCUA_HISTORIAN_BIND, OTOPCUA_HISTORIAN_TLS_ENABLED, OTOPCUA_HISTORIAN_TLS_CERT/PASSWORD) in Install-Services.ps1; add idempotent Windows Firewall inbound rule for the TCP port. Add new params for all TCP/TLS options with cert provisioning guidance. Update Refresh-Services.ps1 Step 4b comment (PipeServer → TcpFrameServer) and add a Step 5 note clarifying that TCP/TLS env is set at install time, not on refresh.
This commit is contained in:
@@ -1,13 +1,16 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Registers the v2 Windows service on a node: OtOpcUaHost (fused binary, .NET 10)
|
Registers the v2 Windows service on a node: OtOpcUaHost (fused binary, .NET 10)
|
||||||
and optionally OtOpcUaWonderwareHistorian (Wonderware historian sidecar, net48 x86).
|
and optionally OtOpcUaWonderwareHistorian (Wonderware historian sidecar, net48 x86
|
||||||
|
— communicates over TCP, optionally TLS, instead of a Windows named pipe).
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
v2 consolidates the legacy OtOpcUa + OtOpcUaAdmin services into a single role-gated
|
v2 consolidates the legacy OtOpcUa + OtOpcUaAdmin services into a single role-gated
|
||||||
OtOpcUaHost binary. The -Roles parameter sets the OTOPCUA_ROLES service env so
|
OtOpcUaHost binary. The -Roles parameter sets the OTOPCUA_ROLES service env so
|
||||||
Program.cs decides what to mount (admin / driver / both). The Wonderware historian
|
Program.cs decides what to mount (admin / driver / both). The Wonderware historian
|
||||||
sidecar logic is unchanged from v1; install it with -InstallWonderwareHistorian.
|
sidecar is installed with -InstallWonderwareHistorian; it listens on a TCP port
|
||||||
|
(default 32569, configurable via -HistorianTcpPort) protected by the shared secret.
|
||||||
|
Optional TLS (-HistorianUseTls) is recommended for production cross-host deployments.
|
||||||
|
|
||||||
Galaxy access flows through the mxaccessgw sibling repo (separate service); see
|
Galaxy access flows through the mxaccessgw sibling repo (separate service); see
|
||||||
docs/v2/Galaxy.ParityRig.md for the gateway setup.
|
docs/v2/Galaxy.ParityRig.md for the gateway setup.
|
||||||
@@ -39,6 +42,30 @@
|
|||||||
Per-process secret passed to the historian sidecar via env var. Generated freshly
|
Per-process secret passed to the historian sidecar via env var. Generated freshly
|
||||||
per install when not supplied.
|
per install when not supplied.
|
||||||
|
|
||||||
|
.PARAMETER HistorianTcpPort
|
||||||
|
TCP port the sidecar listens on (OTOPCUA_HISTORIAN_TCP_PORT). Default 32569. A
|
||||||
|
matching Windows Firewall inbound rule is created automatically.
|
||||||
|
|
||||||
|
.PARAMETER HistorianBind
|
||||||
|
IP address the sidecar binds to (OTOPCUA_HISTORIAN_BIND). Default 0.0.0.0
|
||||||
|
(all interfaces). Set to 127.0.0.1 for loopback-only on same-host deployments.
|
||||||
|
|
||||||
|
.PARAMETER HistorianUseTls
|
||||||
|
When set, enables TLS on the sidecar TCP listener. Supply -HistorianTlsCert with
|
||||||
|
a certificate path or store thumbprint; recommended for cross-host production use.
|
||||||
|
|
||||||
|
.PARAMETER HistorianTlsCert
|
||||||
|
Certificate source for TLS. Either:
|
||||||
|
- Absolute path to a .pfx file (e.g. C:\ProgramData\OtOpcUa\pki\historian.pfx),
|
||||||
|
exported with MachineKeySet so the service account can read the private key; or
|
||||||
|
- A LocalMachine\My store thumbprint (40-hex-char string, no spaces).
|
||||||
|
Do NOT embed a cert path or thumbprint in automation scripts for unattended installs;
|
||||||
|
pass it at call time or from a secrets vault.
|
||||||
|
|
||||||
|
.PARAMETER HistorianTlsCertPassword
|
||||||
|
Password for the .pfx file (if using a pfx path). Leave empty when using a store
|
||||||
|
thumbprint. Never store passwords in scripts or source control.
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
.\Install-Services.ps1 -InstallRoot 'C:\Program Files\OtOpcUa' `
|
.\Install-Services.ps1 -InstallRoot 'C:\Program Files\OtOpcUa' `
|
||||||
-ServiceAccount 'OTOPCUA\svc-otopcua' -Roles 'admin,driver'
|
-ServiceAccount 'OTOPCUA\svc-otopcua' -Roles 'admin,driver'
|
||||||
@@ -57,12 +84,16 @@ param(
|
|||||||
[int]$HttpPort = 9000,
|
[int]$HttpPort = 9000,
|
||||||
|
|
||||||
# Wonderware historian sidecar. Optional; gates the OtOpcUaWonderwareHistorian
|
# Wonderware historian sidecar. Optional; gates the OtOpcUaWonderwareHistorian
|
||||||
# service. Secret + pipe defaults match the server's Historian:Wonderware appsettings.
|
# service. Secret defaults match the server's Historian:Wonderware appsettings.
|
||||||
[switch]$InstallWonderwareHistorian,
|
[switch]$InstallWonderwareHistorian,
|
||||||
[string]$HistorianSharedSecret,
|
[string]$HistorianSharedSecret,
|
||||||
[string]$HistorianPipeName = 'OtOpcUaWonderwareHistorian',
|
|
||||||
[string]$HistorianServer = 'localhost',
|
[string]$HistorianServer = 'localhost',
|
||||||
[int]$HistorianPort = 32568,
|
[int]$HistorianPort = 32568, # SDK port (OTOPCUA_HISTORIAN_PORT) — Wonderware InSQL connection
|
||||||
|
[int]$HistorianTcpPort = 32569, # TCP listen port for the IPC channel (OTOPCUA_HISTORIAN_TCP_PORT)
|
||||||
|
[string]$HistorianBind = '0.0.0.0',
|
||||||
|
[switch]$HistorianUseTls,
|
||||||
|
[string]$HistorianTlsCert,
|
||||||
|
[string]$HistorianTlsCertPassword,
|
||||||
[string[]]$AvevaServiceDependencies = @('NmxSvc', 'aaBootstrap', 'aaGR')
|
[string[]]$AvevaServiceDependencies = @('NmxSvc', 'aaBootstrap', 'aaGR')
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -87,29 +118,43 @@ if ($InstallWonderwareHistorian -and -not (Test-Path "$InstallRoot\WonderwareHis
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Resolve the SID — the IPC ACL needs the SID, not the down-level name.
|
# --- OtOpcUaWonderwareHistorian sidecar (optional, TCP transport) -----------
|
||||||
$sid = if ($ServiceAccount.StartsWith('S-1-')) {
|
|
||||||
$ServiceAccount
|
|
||||||
} else {
|
|
||||||
(New-Object System.Security.Principal.NTAccount $ServiceAccount).Translate([System.Security.Principal.SecurityIdentifier]).Value
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- OtOpcUaWonderwareHistorian sidecar (optional, unchanged from v1) -------
|
|
||||||
$historianDepend = $null
|
$historianDepend = $null
|
||||||
if ($InstallWonderwareHistorian) {
|
if ($InstallWonderwareHistorian) {
|
||||||
|
# Build the TCP/TLS env block.
|
||||||
|
# The Windows named-pipe transport and OTOPCUA_ALLOWED_SID have been retired;
|
||||||
|
# the sidecar now listens on a TCP port protected by the shared secret.
|
||||||
|
# TLS is optional but strongly recommended for cross-host production deployments.
|
||||||
|
#
|
||||||
|
# Cert provisioning for prod (when -HistorianUseTls):
|
||||||
|
# Option A — pfx file: export with -KeyExportPolicy Exportable -KeyStorageFlags MachineKeySet;
|
||||||
|
# place at e.g. C:\ProgramData\OtOpcUa\pki\historian.pfx;
|
||||||
|
# ACL the file so the service account has Read access.
|
||||||
|
# Option B — store thumbprint: import into LocalMachine\My; grant the service account
|
||||||
|
# Read on the private key via certlm.msc → Manage Private Keys.
|
||||||
|
# Either value is passed via -HistorianTlsCert at install time; NEVER hard-code it here.
|
||||||
$historianEnv = @(
|
$historianEnv = @(
|
||||||
"OTOPCUA_HISTORIAN_PIPE=$HistorianPipeName"
|
|
||||||
"OTOPCUA_ALLOWED_SID=$sid"
|
|
||||||
"OTOPCUA_HISTORIAN_SECRET=$HistorianSharedSecret"
|
"OTOPCUA_HISTORIAN_SECRET=$HistorianSharedSecret"
|
||||||
"OTOPCUA_HISTORIAN_ENABLED=true"
|
"OTOPCUA_HISTORIAN_ENABLED=true"
|
||||||
"OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED=true"
|
"OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED=true"
|
||||||
"OTOPCUA_HISTORIAN_SERVER=$HistorianServer"
|
"OTOPCUA_HISTORIAN_SERVER=$HistorianServer"
|
||||||
"OTOPCUA_HISTORIAN_PORT=$HistorianPort"
|
"OTOPCUA_HISTORIAN_PORT=$HistorianPort"
|
||||||
|
"OTOPCUA_HISTORIAN_TCP_PORT=$HistorianTcpPort"
|
||||||
|
"OTOPCUA_HISTORIAN_BIND=$HistorianBind"
|
||||||
)
|
)
|
||||||
|
if ($HistorianUseTls) {
|
||||||
|
$historianEnv += "OTOPCUA_HISTORIAN_TLS_ENABLED=true"
|
||||||
|
$historianEnv += "OTOPCUA_HISTORIAN_TLS_CERT=$HistorianTlsCert"
|
||||||
|
if ($HistorianTlsCertPassword) {
|
||||||
|
$historianEnv += "OTOPCUA_HISTORIAN_TLS_CERT_PASSWORD=$HistorianTlsCertPassword"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$historianEnv += "OTOPCUA_HISTORIAN_TLS_ENABLED=false"
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Installing OtOpcUaWonderwareHistorian..."
|
Write-Host "Installing OtOpcUaWonderwareHistorian..."
|
||||||
& sc.exe create OtOpcUaWonderwareHistorian binPath= "`"$InstallRoot\WonderwareHistorian\OtOpcUa.Driver.Historian.Wonderware.exe`"" `
|
& sc.exe create OtOpcUaWonderwareHistorian binPath= "`"$InstallRoot\WonderwareHistorian\OtOpcUa.Driver.Historian.Wonderware.exe`"" `
|
||||||
DisplayName= 'OtOpcUa Wonderware Historian Sidecar (out-of-process aahClient)' `
|
DisplayName= 'OtOpcUa Wonderware Historian Sidecar (out-of-process aahClient, TCP)' `
|
||||||
start= auto `
|
start= auto `
|
||||||
depend= ($AvevaServiceDependencies -join '/') `
|
depend= ($AvevaServiceDependencies -join '/') `
|
||||||
obj= $ServiceAccount | Out-Null
|
obj= $ServiceAccount | Out-Null
|
||||||
@@ -120,6 +165,11 @@ if ($InstallWonderwareHistorian) {
|
|||||||
|
|
||||||
& sc.exe failure OtOpcUaWonderwareHistorian reset= 86400 actions= restart/5000/restart/30000/restart/60000 | Out-Null
|
& sc.exe failure OtOpcUaWonderwareHistorian reset= 86400 actions= restart/5000/restart/30000/restart/60000 | Out-Null
|
||||||
|
|
||||||
|
# Idempotent Windows Firewall rule for the sidecar TCP port.
|
||||||
|
$fwName = "OtOpcUa Wonderware Historian (TCP $HistorianTcpPort)"
|
||||||
|
Get-NetFirewallRule -DisplayName $fwName -ErrorAction SilentlyContinue | Remove-NetFirewallRule -ErrorAction SilentlyContinue
|
||||||
|
New-NetFirewallRule -DisplayName $fwName -Direction Inbound -Action Allow -Protocol TCP -LocalPort $HistorianTcpPort | Out-Null
|
||||||
|
|
||||||
$historianDepend = 'OtOpcUaWonderwareHistorian'
|
$historianDepend = 'OtOpcUaWonderwareHistorian'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ Run {
|
|||||||
# `dotnet publish` above) silently drops the net48 binding-redirect
|
# `dotnet publish` above) silently drops the net48 binding-redirect
|
||||||
# .exe.config and the transitive runtime DLLs MessagePack needs — most
|
# .exe.config and the transitive runtime DLLs MessagePack needs — most
|
||||||
# notably System.Memory.dll. The sidecar then JIT-load-faults inside
|
# notably System.Memory.dll. The sidecar then JIT-load-faults inside
|
||||||
# PipeServer.RunOneConnectionAsync ("FileNotFoundException: System.Memory,
|
# TcpFrameServer.RunOneConnectionAsync ("FileNotFoundException: System.Memory,
|
||||||
# Version=4.0.1.2") and NSSM crash-loops it (exit 2 every ~2 min, ~120 s of
|
# Version=4.0.1.2") and NSSM crash-loops it (exit 2 every ~2 min, ~120 s of
|
||||||
# retry backoff before it gives up). Fail loudly here so an incomplete deploy
|
# retry backoff before it gives up). Fail loudly here so an incomplete deploy
|
||||||
# is caught at publish time instead of by a production crash-loop.
|
# is caught at publish time instead of by a production crash-loop.
|
||||||
@@ -158,6 +158,11 @@ if (-not $WhatIf) {
|
|||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
# Step 5: Service env block — ensure OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED
|
# Step 5: Service env block — ensure OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED
|
||||||
# is set on the Wonderware historian service (PR C.2 toggle).
|
# is set on the Wonderware historian service (PR C.2 toggle).
|
||||||
|
# Note: the TCP transport env (OTOPCUA_HISTORIAN_TCP_PORT, OTOPCUA_HISTORIAN_BIND,
|
||||||
|
# OTOPCUA_HISTORIAN_TLS_ENABLED, OTOPCUA_HISTORIAN_TLS_CERT) and the Windows
|
||||||
|
# Firewall rule are set once at install time by Install-Services.ps1 and are
|
||||||
|
# not touched here on refresh; re-run Install-Services.ps1 to change them.
|
||||||
|
# OTOPCUA_ALLOWED_SID is no longer used (TCP transport retired the named pipe).
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
if (Test-NssmService 'OtOpcUaWonderwareHistorian') {
|
if (Test-NssmService 'OtOpcUaWonderwareHistorian') {
|
||||||
|
|||||||
Reference in New Issue
Block a user