# Technische Dokumentation: BizTalk Checkmk Pulse ## 1. Ziel und Randbedingungen Die Anwendung ueberwacht BizTalk Server 2020 auf Windows Server 2019 mit Checkmk 2.4. Pro Umgebung (`ACC`, `DEV`, `TST`, `PRD`) wird lokal auf dem BizTalk-Server gesammelt. Das Checkmk-MSSQL-Plugin bleibt fuer die allgemeine SQL-Ueberwachung zustaendig; BizTalk Checkmk Pulse liefert die BizTalk-spezifische Laufzeit- und Berechtigungssicht. Verbindliche Randbedingungen: - Der Checkmk Windows Agent bleibt `LocalSystem`. - `LocalSystem` erhaelt keine BizTalk-/SQL-Gruppenmitgliedschaft. - Ein separates Dienstkonto oder bevorzugt gMSA sammelt minuetlich. - Der Agentpfad fuehrt niemals WMI- oder SQL-Abfragen aus. - Fehler muessen als gueltige Checkmk-`UNKNOWN`-Services sichtbar werden. - Schreiben und Lesen duerfen nie einen halben Snapshot exponieren. - Laufzeitcode benoetigt keine PowerShell und keine BizTalk-DLL-Referenz. - Installation, ACL und Scheduled Task muessen reproduzierbar sein. ## 2. Ausloeser der Architekturanderung Der ACC-Agent-Dump vom 29.07.2026 bewies: ```text Lokaler Prozess: NT AUTHORITY\SYSTEM Netzwerkprincipal: BEW\AV23AGPWBIO1$ Providerfehler: COMException 0x80131904 Innerer Fehler: Login failed for user 'BEW\AV23AGPWBIO1$' ``` Lokales `root\MicrosoftBizTalkServer` war erreichbar. Die datenbankgestuetzten BizTalk-WMI-Klassen scheiterten erst beim Zugriff des Providers auf den getrennten SQL Server. DCOM-, Firewall- oder pauschale WMI-ACL-Aenderungen beheben diesen Befund nicht. Eine Berechtigung des Maschinenkontos haette die Netzwerkrolle allen `LocalSystem`-Diensten des BizTalk-Servers vermittelt. Die jetzt implementierte Producer/Consumer-Trennung beschraenkt sie stattdessen auf ein dediziertes Konto. ## 3. Architektur ```text Privilegierte Zone ┌──────────────────────────────────────────────────────────────┐ │ Task Scheduler: "BizTalk Checkmk Pulse Provider" │ │ Konto: DOMAIN\svc_biztalk_cmk$ (gMSA empfohlen) │ │ Intervall: 1 Minute, IgnoreNew, Laufzeitlimit 5 Minuten │ │ │ │ BizTalkCheckmkPulse.exe --collect │ │ ├─ WMI root\MicrosoftBizTalkServer │ │ ├─ integrierter SQL-Test an MgmtDb/MsgBoxDb │ │ ├─ lokales Windows Application Event Log │ │ ├─ Checkmk-Formatierung │ │ └─ atomare Snapshot-Publikation + Provider-Log │ └──────────────────────────────┬───────────────────────────────┘ │ Datei/ACL v %ProgramData%\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot │ v ┌──────────────────────────────────────────────────────────────┐ │ Unprivilegierter Transportpfad │ │ Checkmk-Agent (LocalSystem) │ │ └─ local\biztalk_checkmk_pulse.cmd │ │ └─ BizTalkCheckmkPulse.exe --consume │ │ ├─ Format/Alter/Maschine/SHA-256 validieren │ │ └─ Payload unveraendert nach STDOUT │ └──────────────────────────────────────────────────────────────┘ ``` Eine gemeinsame EXE implementiert beide Modi. Das reduziert Versionsabweichungen. Die zentrale Config unter `%ProgramFiles%` gilt fuer Provider und Consumer. ### 3.1 Provider-Modus Aufruf: ```cmd "%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --collect ``` Ablauf: 1. Config laden und absolute Runtimepfade validieren. 2. Tageslogs gemaess `LogRetentionDays` bereinigen. 3. exklusives Handle auf `.provider.lock` halten. 4. WMI-, SQL- und Event-Log-Probes ausfuehren. 5. sechs stabile und optionale dynamische Checkmk-Zeilen formatieren. 6. Snapshot in einer eindeutigen Temporaerdatei desselben Verzeichnisses schreiben. 7. `Flush(true)` ausfuehren und Temporaerdatei atomar publizieren. 8. Laufzeit, Zeilen- und Diagnosezahl loggen. Exitcodes: | Code | Bedeutung | | --- | --- | | `0` | Sammlung und Snapshot-Publikation erfolgreich. | | `1` | unerwarteter Providerfehler; aktueller `UNKNOWN`-Snapshot wird versucht. | | `2` | Parallelstart oder Snapshot-I/O-Fehler. | Fachliche WMI-/SQL-Fehler werden strukturiert in den Snapshot geschrieben und muessen nicht zwingend einen Prozessfehler verursachen. So bleibt die genaue Fehlerkategorie in Checkmk sichtbar. ### 3.2 Consumer-Modus Aufruf: ```cmd "%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume ``` Ohne Modusargument ist `--consume` der sichere Default. Der Checkmk-Wrapper setzt es trotzdem explizit. Der Consumer: - oeffnet nur den Snapshot, - begrenzt die Dateigroesse vor dem Einlesen, - validiert striktes UTF-8, - validiert Formatversion und Header, - fordert die lokale Maschinenkennung, - berechnet SHA-256 ueber den exakten Payload, - prueft Zeilenanzahl und Checkmk-Zeilenform, - verwirft Zeitstempel mehr als fuenf Minuten in der Zukunft, - verwirft Snapshots nach `SnapshotMaxAgeSeconds`, - gibt bei Erfolg ausschliesslich den validierten Payload aus. Er gibt immer Exitcode `0` zurueck, damit ein Fehler die komplette Checkmk-Agentsektion nicht zerstoert. Jede Ablehnung erzeugt sechs `UNKNOWN`-Zeilen und einen Eintrag im Consumer-Log. ## 4. Snapshot-Vertrag Version 1: ```text BIZTALK_CHECKMK_PULSE_SNAPSHOT_V1 generatedUtc=2026-07-30T12:34:56.1234567Z machineBase64=QVYyM0FHUFdCSU8x identityBase64=QkVXXHN2Y19iaXp0YWxrX2NtayQ= payloadLines=6 payloadSha256=<64 hex characters> 0 "BizTalk Platform" - ... ... ``` Maschine und Identitaet sind Base64-kodiert, um Zeilenumbrueche und Trennzeichen im Header auszuschliessen. Base64 ist hier keine Verschluesselung. Die SHA-256-Pruefung schuetzt vor unbemerkter Teil-/Fehlschreibung, nicht vor einem lokalen Administrator. ### 4.1 Atomare Publikation Die Temporaerdatei liegt zwingend im Snapshotverzeichnis. Dadurch findet der Ersatz auf demselben Volume statt. Existiert bereits ein Snapshot, wird `File.Replace` verwendet; beim ersten Lauf `File.Move`. Bis zum erfolgreichen Ersatz bleibt der letzte vollstaendige Snapshot erhalten. Seine Alterspruefung verhindert unbegrenztes Weiterreichen alter Daten. ### 4.2 Keine direkte Checkmk-Spooldatei Checkmk kann zwar Dateien aus seinem Spoolverzeichnis direkt anhaengen, prueft deren Inhalt aber laut eigener Dokumentation nicht. Ein fehlerhafter Spool kann nachfolgende Agentsektionen beeinflussen. Deshalb liegt der Provider-Snapshot in einem eigenen Verzeichnis und wird erst durch den validierenden Consumer in die Local-Check-Ausgabe uebernommen. ## 5. Datenquellen ### 5.1 BizTalk WMI Namespace: ```text root\MicrosoftBizTalkServer ``` Pflichtklassen: | Klasse | Zweck | | --- | --- | | `MSBTS_GroupSetting` | Gruppe, Read-Only-/Operator-Gruppe, Management- und Master-MessageBox-Ziel. | | `MSBTS_HostInstance` | lokale Host-Instance-Zustaende. | | `MSBTS_ServiceInstance` | suspendierte Instanzen. | | `MSBTS_ReceiveLocation` | Receive-Location-Zustaende. | | `MSBTS_SendPort` | Send-Port-Zustaende. | | `MSBTS_Orchestration` | Orchestration-Zustaende. | `MSBTS_GroupSetting` wird mit den dokumentierten Properties `MgmtDbServerName`, `MgmtDbName`, `SubscriptionDBServerName`, `SubscriptionDBName`, `BizTalkReadOnlyUserGroup` und `BizTalkOperatorGroup` gelesen. Eine nicht dokumentierte `MSBTS_MessageBoxSetting`-Klasse wird nicht abgefragt. Hostnamen werden clientseitig verglichen. Sonderzeichen und FQDN-/Kurzname gelangen nicht in dynamisch erzeugte WQL-Filter. ### 5.2 SQL-Zugriffsprobe Der Provider oeffnet fuer Management- und Master-MessageBox-Datenbank eine kurze `System.Data.SqlClient`-Verbindung mit integrierter Windows-Authentifizierung, fuehrt `SELECT 1` aus und schliesst sie. Keine BizTalk-Tabelle wird direkt gelesen oder veraendert. Die Ausgabe `execution_identity=` zeigt deshalb das Provider-Konto, nicht mehr `NT AUTHORITY\SYSTEM`. Der Check beweist, dass genau das Scheduled-Task-Konto die Ziele erreichen kann. ### 5.3 Event Log Der Provider liest das lokale Application Log im konfigurierten Zeitfenster und filtert Quellen wie `BizTalk Server`, `XLANG/s`, `ENTSSO`, `BizTalk Server Application` und `BizTalk Server EDI`. ## 6. Berechtigungsmodell ### 6.1 Bevorzugte BizTalk-Rolle BizTalk Server 2020 fuehrte die `BizTalk Server Read Only Users`-Gruppe ein. Sie darf Artefakte, Servicezustand, Message Flow und Trackinginformationen lesen, aber keine administrativen Operationen ausfuehren. SQL-seitig wird sie ueber `BTS_READONLY_USERS` vermittelt. Soll: ```text DOMAIN\svc_biztalk_cmk$ -> konfigurierte BizTalk Server Read Only Users-Domaingruppe -> vorhandener Windows-Gruppenlogin am SQL Server -> BTS_READONLY_USERS in den von BizTalk konfigurierten Datenbanken ``` Die genaue Gruppe ist aus `MSBTS_GroupSetting.BizTalkReadOnlyUserGroup` beziehungsweise der BizTalk-Administration zu lesen. Nicht vom Standardnamen ausgehen. Die Operator-Gruppe (`BTS_OPERATORS`) wird erst geprueft, wenn eine konkret benannte erforderliche WMI-Klasse trotz nachgewiesener Read-Only-Konfiguration und neuem Anmeldetoken abgewiesen wird. Die Erweiterung muss mit Security, BizTalk- und SQL-Administration begruendet werden. Unzulaessig: - Checkmk-Dienstkonto aendern, - Maschinenkonto pauschal berechtigen, - individueller SQL-Login fuer das Provider-Konto, - direkte ad-hoc DB-Rollen, - `db_owner` oder `sysadmin`, - WMI-/DCOM-Vollzugriff als Reaktion auf einen SQL-Loginfehler. ### 6.2 Dateisystem-ACL Der Installer entfernt die Vererbung an den Runtimeverzeichnissen und setzt explizite Eintraege mit sprachneutralen Well-known-SIDs: | Ziel | Collector | SYSTEM | lokale Administratoren | | --- | --- | --- | --- | | Runtime-Root | RX | RX | F | | `data` | Modify | RX | F | | `logs` | Modify | Modify | F | `LocalSystem` kann deshalb den Snapshot lesen, aber im Datenverzeichnis nicht schreiben. Schreibrecht im Logverzeichnis wird benoetigt, um abgelehnte Snapshots aus dem Consumer-Kontext zu protokollieren. ## 7. Scheduled Task Name: ```text BizTalk Checkmk Pulse Provider ``` Sollkonfiguration: | Einstellung | Wert | | --- | --- | | Trigger | einmalig, Wiederholung jede Minute ohne Enddatum | | Programm | `%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe` | | Argument | `--collect` | | Arbeitsverzeichnis | `%ProgramFiles%\BizTalkCheckmkPulse` | | Benutzer | dediziertes Dienstkonto oder gMSA | | Mehrfachinstanzen | `IgnoreNew` | | Laufzeitlimit | 5 Minuten | | StartWhenAvailable | aktiv | | Restart | zweimal im Minutenabstand | Der Task wird mit gespeichertem Dienstkontokennwort beziehungsweise gMSA ausgefuehrt, also unabhaengig von einer interaktiven Anmeldung. ## 8. Installation ### 8.1 Build ```cmd scripts\test-release.cmd scripts\package-release.cmd ``` ### 8.2 gMSA Voraussetzungen: 1. gMSA in AD erstellen und Abrufrecht auf den BizTalk-Server begrenzen. 2. Konto lokal installieren und mit `Test-ADServiceAccount` pruefen. 3. gMSA in die exakt konfigurierte BizTalk-Read-Only-Gruppe aufnehmen. 4. AD-Replikation abwarten. Installation: ```powershell .\Install-BizTalkCheckmkPulse.ps1 ` -CollectorAccount 'BEW\svc_biztalk_cmk$' ` -Gmsa ` -EnvironmentName ACC ``` ### 8.3 regulaeres Dienstkonto ```powershell .\Install-BizTalkCheckmkPulse.ps1 ` -CollectorAccount 'BEW\svc_biztalk_cmk' ` -EnvironmentName ACC ``` Der Installer muss als lokaler Administrator laufen. Er vergibt keine AD-/BizTalk-/SQL-Rechte; diese bleiben getrennte administrative Freigaben. ### 8.4 Checkmk Der installierte Wrapper liegt unter: ```text %ProgramData%\checkmk\agent\local\biztalk_checkmk_pulse.cmd ``` Der Agent darf den Consumer synchron ausfuehren. Er liest nur maximal 1 MiB lokale Daten; ein Checkmk-Async-Cache ist daher nicht notwendig. Falls alte `check_mk.user.yml`-Regeln fuer den bisherigen 300-Sekunden-Cache existieren, sollten sie entfernt werden, damit Checkmk den minuetlich aktualisierten Snapshot nicht zusaetzlich verzoegert. Nach dem Agent-Dump: 1. Service Discovery fuer den BizTalk-Host ausfuehren. 2. sechs stabile Services aufnehmen. 3. Changes aktivieren. 4. Views/Benachrichtigungen nach Umgebung konfigurieren. ## 9. Logging Pfad: ```text %ProgramData%\BizTalkCheckmkPulse\logs\ biztalk-checkmk-pulse-YYYYMMDD.log ``` Jede Zeile enthaelt UTC-Zeit, Level, Komponente, PID, Windows-Identitaet und einzeilige Nachricht. Provider-Erfolge werden pro Lauf geloggt; der Consumer loggt nur abgelehnte Snapshots. Exceptions werden mit Typ, Nachricht, HRESULT-/Providerdetails und Stacktrace einzeilig gespeichert. Logging ist best effort: Ein blockiertes Log darf Checkmk-Ausgabe oder Snapshot-Publikation nicht zerstoeren. Der Provider entfernt beim Start Dateien aelter als `LogRetentionDays`. ## 10. Diagnose und Runbook ### 10.1 Grundpruefung ```powershell Get-ScheduledTaskInfo -TaskName 'BizTalk Checkmk Pulse Provider' Get-Item "$env:ProgramData\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot" Get-Content "$env:ProgramData\BizTalkCheckmkPulse\logs\*.log" -Tail 100 & "$env:ProgramFiles\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume & "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump ``` ### 10.2 Kein Snapshot Pruefen: 1. Task existiert und ist aktiviert. 2. `LastTaskResult` und Provider-Log. 3. Dienstkonto kann sich als Batch anmelden. 4. gMSA ist lokal installiert und abrufbar. 5. Provider besitzt Modify auf `data` und `logs`. 6. EXE/Config sind ausfuehrbar. ### 10.3 Staler Snapshot Der Consumer nennt Alter und Grenzwert. Ursachen: - Task deaktiviert oder Konto/Kennwort ungueltig, - vorheriger Lauf haengt, - WMI-/SQL-Timeouts, - Task Scheduler lief waehrend Wartung nicht, - Snapshot-Publikation wird durch AV/EDR oder ACL blockiert. Nicht einfach `SnapshotMaxAgeSeconds` stark erhoehen. Zuerst den minuetlichen Lauf wiederherstellen. Bei geplanten Wartungen darf Checkmk bewusst `UNKNOWN` anzeigen. ### 10.4 SHA-256-/Formatfehler Snapshot nicht reparieren oder direkt an Checkmk kopieren. Task neu starten, Datentraeger und AV/EDR pruefen. Wiederholt sich der Fehler, Temporaerdateien, NTFS-Ereignisse und Schreibrechte untersuchen. ### 10.5 BizTalk-/SQL-Permission 1. Log zeigt `execution_identity` des Providers. 2. `BizTalkReadOnlyUserGroup` gegen BizTalk-Konfiguration abgleichen. 3. AD-Gruppenmitgliedschaft des Provider-Kontos pruefen. 4. neuen Logontoken durch neuen Tasklauf sicherstellen. 5. SQL-seitig Gruppenlogin und `BTS_READONLY_USERS` read-only pruefen. 6. keine Einzelrechte erteilen. 7. Nur wenn eine spezifische Klasse weiter abgewiesen wird, Read-Only-Umfang mit Microsoft-Dokumentation und BizTalk-Betrieb abgleichen; Operator-Rolle ist eine bewusste Eskalation. ### 10.6 WMI-Schema `InvalidClass` oder `InvalidQuery` wird als `Wmi/Schema` klassifiziert. Berechtigungserhoehung kann eine nicht vorhandene Klasse nicht erzeugen. Installierte BizTalk-Version, WQL und Properties pruefen. ## 11. Konfiguration Alle AppSettings befinden sich in: ```text %ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe.config ``` Runtime: | Key | Default | Bereich | | --- | --- | --- | | `SnapshotPath` | `%ProgramData%\BizTalkCheckmkPulse\data\...` | absolut | | `SnapshotMaxAgeSeconds` | `180` | 60 bis 86400 | | `SnapshotMaxBytes` | `1048576` | 4096 bis 16777216 | | `LogDirectory` | `%ProgramData%\BizTalkCheckmkPulse\logs` | absolut | | `LogRetentionDays` | `30` | 1 bis 365 | BizTalk-Probes: | Key | Default | | --- | --- | | `Server` | `.` | | `QueryTimeoutSeconds` | `25` | | `ProbeSqlConnectivity` | `true` | | `SqlConnectionTimeoutSeconds` | `5` | | `ProbeEventLog` | `true` | | `EventLogLookbackMinutes` | `60` | Alarmierung: | Key | Default | | --- | --- | | `WarnResumableThreshold` | `1` | | `CritNonResumableThreshold` | `1` | | `AlertOnArtifactRuntimeIssues` | `false` | | `EmitPerApplicationSuspensionServices` | `false` | | `EventLogWarnThreshold` | `1` | | `EventLogCritThreshold` | `10` | ## 12. Tests und Abnahmekriterien Automatisiert: - Release-Build .NET Framework 4.7.2, - exakt sechs Self-Test-Services, - unbekannte Quellen werden `UNKNOWN`, - dynamische Anwendungsservices nur bei bekannter Anwendung, - WMI-Queryvertrag nutzt dokumentierte Properties, - eingebetteter SQL-Loginfehler wird `Permission`, - abgewiesener Principal wird extrahiert, - Snapshot-Roundtrip und Ersatz, - SHA-256-Manipulation wird verworfen, - Stale-Snapshot wird verworfen, - Consumer-Fallback enthaelt sechs `UNKNOWN`-Services. Windows-/ACC-Abnahme: 1. `LastTaskResult=0`. 2. Snapshot wird mindestens dreimal minuetlich aktualisiert. 3. Provider-Log nennt das dedizierte Konto. 4. `BizTalk Platform` zeigt `read_only_group=`. 5. `BizTalk SQL Access`: `targets=2`, `available=2`. 6. keine Permission-`UNKNOWN`s. 7. ACL-Test: `LocalSystem` kann Snapshot lesen, nicht schreiben. 8. Task deaktivieren: nach 180 Sekunden sechs stale-`UNKNOWN`s. 9. Task wieder aktivieren: naechster Snapshot stellt Echtzustand her. 10. Agent-Dump und Checkmk Service Discovery erfolgreich. Erst nach ACC-Abnahme erfolgt der gestufte Rollout nach DEV/TST/PRD. ## 13. Deinstallation und Rollback ```powershell .\Uninstall-BizTalkCheckmkPulse.ps1 ``` `-KeepRuntimeData` erhaelt Logs und Snapshot. Das Skript entfernt Task, Wrapper und Programmdateien, aber keine AD-Gruppenmitgliedschaft. Die Berechtigung wird separat nach Change-Verfahren entzogen. Rollback auf die alte direkte `LocalSystem`-Architektur ist nicht empfohlen. Falls kurzfristig notwendig, muss Security die Maschinenkonto-Berechtigung explizit freigeben; der Checkmk-Agentdienst selbst darf nicht auf das Collector-Konto umgestellt werden. ## 14. Transport per certutil Die Source-Uebergabe besteht aus ZIP plus Base64-TXT: ```cmd certutil -decode .zip.b64.txt .zip certutil -hashfile .zip SHA256 tar -xf .zip ``` ZIP und Base64 werden erst nach dem Git-Commit aus genau diesem Commit erzeugt. ## 15. Referenzen - https://learn.microsoft.com/en-us/biztalk/core/managing-biztalk-server-security - https://learn.microsoft.com/en-us/biztalk/core/windows-groups-and-user-accounts-in-biztalk-server - https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-biztalkreadonlyusergroup-property-wmi - https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-wmi - https://docs.checkmk.com/latest/en/agent_windows.html - https://docs.checkmk.com/latest/en/localchecks.html - https://docs.checkmk.com/latest/en/spool_directory.html