From 0001d7b86155d507e6dce51a90fd3d7e72868db3 Mon Sep 17 00:00:00 2001 From: Johannes Rest Date: Wed, 29 Jul 2026 13:21:22 +0200 Subject: [PATCH] Diagnose BizTalk WMI SQL permissions --- Dokumentation.md | 19 +++- README.md | 66 +++++++++-- docs/ACC-WMI-SQL-Berechtigung.txt | 106 ++++++++++++++++++ docs/CheckmkServices.md | 6 +- docs/ExampleOutput.md | 9 +- docs/Integration.md | 41 +++++-- .../CheckmkLocalFormatter.cs | 1 + src/BizTalkCheckmkPulse/Models.cs | 1 + .../SqlConnectivityProbe.cs | 33 +++++- src/BizTalkCheckmkPulse/WmiBizTalkProbe.cs | 85 +++++++++++++- tests/BizTalkCheckmkPulse.Tests/Program.cs | 67 ++++++++++- 11 files changed, 396 insertions(+), 38 deletions(-) create mode 100644 docs/ACC-WMI-SQL-Berechtigung.txt diff --git a/Dokumentation.md b/Dokumentation.md index 9712426..6a905c4 100644 --- a/Dokumentation.md +++ b/Dokumentation.md @@ -164,6 +164,8 @@ DOMAIN\BIZTALKSERVER$ Dieses Konto besitzt nicht automatisch BizTalk- oder SQL-Berechtigungen. Daraus kann die Situation entstehen, dass die Verbindung zum lokalen WMI-Namespace erfolgreich ist, einzelne SQL-gestuetzte WMI-Klassen aber `Access denied`, `UnauthorizedAccessException` oder `UNKNOWN` liefern. +Der ACC-Test vom 29.07.2026 bestaetigt genau diesen Pfad: Auf `AV23AGPWBIO1` ist WMI erreichbar, aber der Provider meldet `COMException 0x80131904` mit `Login failed for user 'BEW\AV23AGPWBIO1$'`. Die `UNKNOWN`-Services fuer Plattform, Host Instances, Runtime Artifacts und Suspensions sowie die fehlende SQL-Zielermittlung sind Folgefehler. DCOM-, Firewall- oder WMI-ACL-Erweiterungen beheben diesen konkreten SQL-Loginfehler nicht. Der Event-Log-Check arbeitet bereits und seine Fehler/Warnungen sind separat zu bewerten. + ### Pruefung und Freigabe Der direkte Programmstart in einer administrativen Shell laeuft unter dem angemeldeten Benutzer und ist deshalb kein ausreichender Berechtigungstest. Verbindlich ist die Ausfuehrung durch den Checkmk Agent Controller als `LocalSystem`: @@ -175,11 +177,11 @@ Der direkte Programmstart in einer administrativen Shell laeuft unter dem angeme Bei Zugriffsfehlern gilt folgendes Least-Privilege-Vorgehen: -1. Computerkonto des BizTalk-Servers ermitteln, normalerweise `DOMAIN\BIZTALKSERVER$`. -2. Die bei der BizTalk-Konfiguration verwendete Operator-Gruppe feststellen. -3. Das Computerkonto in `BizTalk Server Operators` beziehungsweise die kundenspezifisch benannte Operator-Gruppe aufnehmen. -4. Kerberos-Tickets des Systemkontos erneuern oder den Server im Wartungsfenster neu starten. -5. Den Agent-Dump wiederholen. +1. Die exakt konfigurierte Operator-Gruppe in der BizTalk Administration Console unter `BizTalk Group` > `Properties` > `General` feststellen. +2. Das Computerobjekt des BizTalk-Servers durch einen AD-Administrator in genau diese Gruppe aufnehmen. Fuer ACC ist dies `AV23AGPWBIO1` beziehungsweise `BEW\AV23AGPWBIO1$`. +3. Keine direkten SQL-Logins, BizTalk-Datenbankrollen oder `sysadmin`-Rechte fuer das Maschinenkonto anlegen. +4. AD-Replikation abwarten und den Server im Wartungsfenster neu starten; alternativ Maschinen-Tickets mit `klist purge -li 0x3e7` und den Checkmk-Dienst erneuern. +5. Den Agent-Dump wiederholen und `operator_group`, zwei SQL-Ziele sowie das Verschwinden der Berechtigungs-`UNKNOWN`s kontrollieren. 6. Nur fuer weiterhin abgelehnte, konkret identifizierte WMI-Klassen mit BizTalk- und SQL-Administration pruefen, ob Administratorrechte erforderlich sind. Die Operator-Rolle ist fuer grundlegendes Monitoring und Zustandsabfragen vorgesehen. Direkte manuelle Aenderungen an den Rollen der BizTalk-SQL-Datenbanken sind zu vermeiden; die durch BizTalk konfigurierte Windows-Gruppe ist die vorgesehene Berechtigungsgrenze. @@ -198,7 +200,7 @@ WMI-Verbindungsaufbau und jede erforderliche WMI-Klasse werden separat bewertet. | Diagnose | Bedeutung | Ausgegebene Massnahme | | --- | --- | --- | -| `Wmi/Permission` | Namespace oder BizTalk-WMI-Klasse verweigert den Zugriff. | Namespace-ACL bei Verbindungsfehlern beziehungsweise BizTalk-Operator-Gruppe bei Klassenfehlern pruefen. | +| `Wmi/Permission` | Namespace, BizTalk-WMI-Klasse oder deren eingebetteter SQL-Zugriff verweigert den Zugriff. | Namespace-ACL nur bei Verbindungsfehlern; bei `Login failed for user` das genannte Maschinenkonto der BizTalk-Operator-Gruppe zuordnen. | | `Wmi/Connectivity` | WMI-/RPC-Ziel nicht erreichbar. | WMI-Dienst, Provider und bei Remote-WMI zusaetzlich DNS/RPC/Firewall pruefen. | | `Wmi/Timeout` | WMI-Abfrage ueberschreitet `QueryTimeoutSeconds`. | WMI-, BizTalk- und SQL-Auslastung untersuchen, bevor der Timeout erhoeht wird. | | `Wmi/Configuration` | BizTalk-WMI-Namespace fehlt oder Plattformdaten sind unvollstaendig. | Provider, Namespace und BizTalk-Konfiguration pruefen. | @@ -218,7 +220,12 @@ Quellen: - https://docs.checkmk.com/latest/en/localchecks.html - https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights - https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-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/access-control-for-administrative-roles +- https://learn.microsoft.com/en-us/biztalk/core/how-to-modify-group-properties - https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer +- https://learn.microsoft.com/en-us/powershell/module/activedirectory/add-adgroupmember +- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/klist - https://learn.microsoft.com/en-us/windows/win32/wmisdk/access-to-wmi-namespaces ## Resilienz diff --git a/README.md b/README.md index 4a111bc..6625992 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Wenn `EnvironmentName=ACC`, `DEV`, `TST` oder `PRD` gesetzt wird, wird der Name Details zu Statuslogik und Metriken stehen in [docs/CheckmkServices.md](docs/CheckmkServices.md). Beispielausgaben stehen in [docs/ExampleOutput.md](docs/ExampleOutput.md). +Die konkrete ACC-Freigabeanleitung steht als Textdatei in [docs/ACC-WMI-SQL-Berechtigung.txt](docs/ACC-WMI-SQL-Berechtigung.txt). ## Build @@ -196,6 +197,19 @@ DOMAIN\BIZTALKSERVER$ Die weitreichenden lokalen Rechte von `LocalSystem` ergeben nicht automatisch Berechtigungen auf dem entfernten SQL Server. Deshalb kann die Verbindung zum lokalen WMI-Namespace funktionieren, waehrend einzelne SQL-gestuetzte BizTalk-WMI-Abfragen mit `Access denied`, `UnauthorizedAccessException` oder `UNKNOWN` fehlschlagen. +### Einordnung des ACC-Befunds vom 29.07.2026 + +Der Agent-Dump von `AV23AGPWBIO1` zeigt den entscheidenden inneren Providerfehler: + +```text +COMException HRESULT=0x80131904 +Internal error from OLEDB provider: 'Login failed for user 'BEW\AV23AGPWBIO1$'.' +``` + +Damit ist der lokale Namespace `root\MicrosoftBizTalkServer` bereits erreichbar. Der BizTalk-WMI-Provider kann aber seine SQL-gestuetzten Abfragen nicht ausfuehren, weil SQL Server das Computerkonto `BEW\AV23AGPWBIO1$` ablehnt. Zusaetzliche DCOM-, Firewall- oder WMI-Namespace-Rechte sind fuer diesen konkreten Fehler nicht die richtige Massnahme. Die `UNKNOWN`-Zustaende bei Platform, Host Instances, Runtime Artifacts und Suspended Instances sowie `targets=0` bei SQL Access sind Folgewirkungen derselben fehlenden Berechtigung. + +`BizTalk Event Log` funktioniert unabhaengig von diesem SQL-Zugriff. Die dort sichtbaren zwei Fehler und sechs Warnungen sind echte Ereignisse im betrachteten Zeitfenster und nach Behebung der Berechtigung separat zu untersuchen. + ### Test im echten Checkmk-Kontext Ein manueller Aufruf von `BizTalkCheckmkPulse.exe` oder des Wrappers verwendet das Konto der angemeldeten Person. Ein erfolgreicher manueller Test beweist daher nicht, dass die Ausfuehrung durch Checkmk als `LocalSystem` ebenfalls funktioniert. @@ -204,7 +218,7 @@ Der verbindliche Test erfolgt ueber den Agent Controller: ```powershell & "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump | - Select-String -Pattern "BizTalk|Access denied|Unauthorized|UNKNOWN" -Context 0,1 + Select-String -Pattern "BizTalk|Login failed|Access denied|Unauthorized|UNKNOWN" -Context 0,1 ``` Erwartet werden die sechs stabilen `BizTalk ...` Services mit plausiblen Daten. Insbesondere `BizTalk Platform` und `BizTalk SQL Access` duerfen nicht wegen eines WMI-, SQL- oder Berechtigungsfehlers `UNKNOWN` sein. @@ -215,6 +229,8 @@ Das Programm prueft Berechtigungen aktiv: - Fehler werden als `Permission`, `Connectivity`, `Timeout`, `Configuration`, `Schema` oder `Provider` klassifiziert. - `BizTalk SQL Access` oeffnet mit integrierter Windows-Authentifizierung eine Verbindung zur ermittelten Management- und Master-MessageBox-Datenbank und fuehrt `SELECT 1` aus. - Die Service-Ausgabe nennt Ausfuehrungsidentitaet, erwartete Netzwerkidentitaet, betroffene Komponente, technische Ursache und konkrete Massnahme. +- Ein im BizTalk-WMI-Provider eingebettetes `Login failed for user` wird als `Wmi/Permission` klassifiziert; das tatsaechlich abgewiesene Konto wird in die Diagnose und in `BizTalk SQL Access` uebernommen. +- Nach erfolgreicher Plattformabfrage zeigt `BizTalk Platform` mit `operator_group=` die von BizTalk konfigurierte Operator-Gruppe. - Fehlgeschlagene Pflichtabfragen werden nie als leerer, erfolgreicher Datenbestand gewertet. Der betroffene Service wird `UNKNOWN`. `Sql/Configuration` weist je nach Detailtext entweder auf eine unvollstaendige WMI-Zielermittlung oder auf TLS-, Zertifikats-, SPN-/SSPI-Probleme hin. Die Diagnose empfiehlt bewusst nicht, SQL-Verschluesselung pauschal abzuschalten. @@ -237,12 +253,41 @@ local: ### Vorgehen bei Berechtigungsfehlern -1. Pruefen, unter welchem Computerkonto der BizTalk-Server im Netzwerk auftritt, normalerweise `DOMAIN\BIZTALKSERVER$`. -2. Die fuer die BizTalk-Gruppe konfigurierte Windows-Gruppe `BizTalk Server Operators` ermitteln. Der tatsaechliche Gruppenname kann bei der BizTalk-Konfiguration angepasst worden sein. -3. Das Computerkonto des BizTalk-Servers in diese Operator-Gruppe aufnehmen. -4. Kerberos-Tickets des Systemkontos erneuern oder den BizTalk-Server in einem Wartungsfenster neu starten. -5. Den Test mit `cmk-agent-ctl.exe dump` wiederholen. -6. Nur wenn konkrete WMI-Klassen weiterhin abgelehnt werden, gemeinsam mit BizTalk- und SQL-Administration pruefen, ob diese Abfrage `BizTalk Server Administrators` benoetigt. +1. Den Agent-Dienst und sein Startkonto kontrollieren: + + ```powershell + Get-CimInstance Win32_Service | + Where-Object { $_.Name -match 'check|cmk' -or $_.DisplayName -match 'checkmk' } | + Select-Object Name, DisplayName, State, StartName + ``` + +2. Die exakt konfigurierte Operator-Gruppe in der BizTalk Administration Console unter `BizTalk Group` > `Properties` > `General` > `BizTalk Operators Group` ablesen. Nicht blind vom Standardnamen ausgehen. Alternativ kann ein bereits berechtigtes Konto abfragen: + + ```powershell + Get-CimInstance -Namespace root/MicrosoftBizTalkServer -ClassName MSBTS_GroupSetting | + Select-Object Name, BizTalkOperatorGroup, MgmtDbServerName, MgmtDbName + ``` + +3. Ein AD-Administrator nimmt das Computerobjekt in genau diese Gruppe auf. Fuer ACC ist das Computerobjekt `AV23AGPWBIO1`, dessen Netzwerkprincipal `BEW\AV23AGPWBIO1$` ist: + + ```powershell + Import-Module ActiveDirectory + $computer = Get-ADComputer -Identity 'AV23AGPWBIO1' + Add-ADGroupMember -Identity '' -Members $computer -WhatIf + ``` + + Nach Kontrolle der aufgeloesten Ziele wird derselbe Befehl ohne `-WhatIf` ausgefuehrt. Anschliessend die Mitgliedschaft mit `Get-ADPrincipalGroupMembership -Identity 'AV23AGPWBIO1'` pruefen. + +4. AD-Replikation abwarten. Die sicherste Aktivierung ist ein Neustart des BizTalk-Servers im Wartungsfenster. Ohne Neustart kann ein Administrator die Maschinen-Tickets mit `klist purge -li 0x3e7` verwerfen und danach den zuvor ermittelten Checkmk-Agent-Dienst neu starten. + +5. Den Test im echten Agent-Kontext wiederholen: + + ```powershell + & "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump | + Select-String -Pattern "BizTalk|Login failed|Wmi/Permission|Sql/Permission|UNKNOWN" -Context 0,1 + ``` + +6. Erwartet werden Platform und SQL Access mit vollstaendiger Zielermittlung, zwei erreichbaren Datenbankzielen und keine berechtigungsbedingten `UNKNOWN`-Services. Erst wenn eine konkret benannte Klasse danach weiter scheitert, wird deren Rollenanforderung mit BizTalk- und SQL-Administration untersucht. Die Operator-Rolle ist fuer grundlegende Administration und Monitoring vorgesehen und kann Zustands- und Message-Flow-Informationen lesen, ohne BizTalk-Konfiguration oder Nachrichteninhalte einzusehen. Das Plugin fuehrt ausschliesslich Leseabfragen aus. Direkte manuelle Aenderungen an BizTalk-SQL-Datenbankrollen sollten nicht vorgenommen werden; die von BizTalk konfigurierte Windows-Gruppe ist die vorgesehene Berechtigungsgrenze. @@ -255,7 +300,7 @@ Entscheidungsmatrix: | Service meldet `Wmi/Schema` beziehungsweise `InvalidClass`/`InvalidQuery` | WMI-Klasse und Properties gegen das BizTalk-Schema pruefen. Keine Berechtigungen erweitern. | | `BizTalk SQL Access` meldet `Sql/Permission` | Computerkonto `DOMAIN\BIZTALKSERVER$` in die konfigurierte BizTalk-Operator-Gruppe aufnehmen, Kerberos erneuern und erneut testen. Keine direkten BizTalk-DB-Rollen vergeben. | | `BizTalk SQL Access` meldet `Sql/Connectivity` oder `Sql/Timeout` | Server-/Instanzname, DNS, SQL-Dienst, TCP-Protokoll, Port und Firewall aus Sicht des BizTalk-Servers pruefen. | -| Nur SQL-gestuetzte BizTalk-Klassen liefern `Access denied` oder `UNKNOWN` | Computerkonto `DOMAIN\BIZTALKSERVER$` zunaechst in `BizTalk Server Operators` aufnehmen. | +| SQL-gestuetzte BizTalk-Klassen liefern `0x80131904`, `Login failed for user` oder `UNKNOWN` | Das in der Meldung genannte Computerkonto in die exakt konfigurierte BizTalk-Operator-Gruppe aufnehmen. | | `BizTalk Event Log` ist `UNKNOWN` | Zugriff auf das lokale Application Log pruefen; `LocalSystem` kann es normalerweise lesen. | | Fehler bleibt trotz Operator-Rolle bestehen | Betroffene WMI-Klasse und BizTalk-/SQL-Rollenzuordnung mit den Fachadministratoren untersuchen. | @@ -284,8 +329,13 @@ Empfohlene Alarmierung: - Microsoft BizTalk WMI `MSBTS_ServiceInstance`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-wmi - Microsoft BizTalk WMI `ServiceStatus`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-servicestatus-property-wmi - Microsoft BizTalk WMI `MSBTS_GroupSetting`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-wmi +- Microsoft BizTalk Windows-Gruppen und SQL-Rollen: https://learn.microsoft.com/en-us/biztalk/core/windows-groups-and-user-accounts-in-biztalk-server +- Microsoft BizTalk administrative Rollen: https://learn.microsoft.com/en-us/biztalk/core/access-control-for-administrative-roles +- Microsoft BizTalk Gruppen-Eigenschaften: https://learn.microsoft.com/en-us/biztalk/core/how-to-modify-group-properties - Microsoft BizTalk WMI Core Server Classes: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/core-server-classes - Microsoft BizTalk Mindestberechtigungen: https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights - Microsoft BizTalk Access Control: https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-security - Microsoft LocalSystem und Computerkonten: https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer +- Microsoft `Add-ADGroupMember`: https://learn.microsoft.com/en-us/powershell/module/activedirectory/add-adgroupmember +- Microsoft `klist`: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/klist - Microsoft WMI Namespace Security: https://learn.microsoft.com/en-us/windows/win32/wmisdk/access-to-wmi-namespaces diff --git a/docs/ACC-WMI-SQL-Berechtigung.txt b/docs/ACC-WMI-SQL-Berechtigung.txt new file mode 100644 index 0000000..9b11f03 --- /dev/null +++ b/docs/ACC-WMI-SQL-Berechtigung.txt @@ -0,0 +1,106 @@ +BizTalk Checkmk Pulse - ACC Berechtigungsfreigabe +Stand: 29.07.2026 + +BEFUND +====== + +Host: AV23AGPWBIO1 +Lokale Identitaet: NT AUTHORITY\SYSTEM (LocalSystem) +Netzwerkidentitaet: BEW\AV23AGPWBIO1$ +Fehler: COMException HRESULT=0x80131904 +Innerer Fehler: Login failed for user 'BEW\AV23AGPWBIO1$' + +Der lokale BizTalk-WMI-Namespace ist erreichbar. Der BizTalk-WMI-Provider wird +aber bei seinem SQL-Zugriff als Maschinenkonto abgewiesen. Deshalb sind +Platform, Host Instances, Runtime Artifacts und Suspended Instances UNKNOWN. +BizTalk SQL Access kann ohne MSBTS_GroupSetting keine Ziele ermitteln. + +Keine DCOM-, Firewall- oder WMI-Namespace-Rechte erweitern. Keinen direkten +SQL-Login, keine manuellen BizTalk-Datenbankrollen und kein sysadmin fuer das +Maschinenkonto anlegen. + +FREIGABE +======== + +1. Exakte Operator-Gruppe ermitteln + +In der BizTalk Administration Console: + + BizTalk Group > Properties > General > BizTalk Operators Group + +Nicht ungeprueft den Standardnamen verwenden. Mit einem bereits berechtigten +Konto ist alternativ folgende Abfrage moeglich: + + Get-CimInstance -Namespace root/MicrosoftBizTalkServer ` + -ClassName MSBTS_GroupSetting | + Select-Object Name, BizTalkOperatorGroup, MgmtDbServerName, MgmtDbName + +2. Computerobjekt durch einen AD-Administrator aufnehmen + + Import-Module ActiveDirectory + $computer = Get-ADComputer -Identity 'AV23AGPWBIO1' + Add-ADGroupMember ` + -Identity '' ` + -Members $computer ` + -WhatIf + +Ziele kontrollieren und danach denselben Add-ADGroupMember-Befehl ohne +-WhatIf ausfuehren. + +Mitgliedschaft pruefen: + + Get-ADPrincipalGroupMembership -Identity 'AV23AGPWBIO1' | + Select-Object Name, SamAccountName + +3. Neue Gruppenzugehoerigkeit aktivieren + +AD-Replikation abwarten. Bevorzugt den BizTalk-Server in einem Wartungsfenster +neu starten. Alternativ in einer administrativen Shell: + + klist purge -li 0x3e7 + +Danach den zuvor eindeutig ermittelten Checkmk-Agent-Dienst neu starten. Falls +die neue Mitgliedschaft nicht wirksam wird, den Server neu starten. + +4. Im echten Checkmk-Kontext verifizieren + + & "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump | + Select-String ` + -Pattern "BizTalk|Login failed|Wmi/Permission|Sql/Permission|UNKNOWN" ` + -Context 0,1 + +Erwartetes Ergebnis: + +- BizTalk Platform ist OK und zeigt operator_group=. +- BizTalk SQL Access zeigt targets=2, available=2, + discovery_complete=True. +- Host Instances, Runtime Artifacts und Suspended Instances sind nicht mehr + wegen WMI-/SQL-Berechtigungen UNKNOWN. +- Kein Login failed fuer BEW\AV23AGPWBIO1$. + +Der separate Event-Log-Service zeigte im Screenshot zwei Fehler und sechs +Warnungen. Diese Ereignisse bleiben nach der Berechtigungsfreigabe fachlich zu +pruefen. + +SICHERHEIT +========== + +Die Gruppenmitgliedschaft des Computerobjekts steht allen Diensten zur +Verfuegung, die auf AV23AGPWBIO1 als LocalSystem laufen und auf +Netzwerkressourcen zugreifen. Mit Security und BizTalk-Betrieb abstimmen. + +Ist dies nicht akzeptabel, ist ein separater Collector unter einem dedizierten +gMSA-/Dienstkonto mit BizTalk-Operator-Rechten die sauberere Architektur. Nicht +allein fuer dieses Plugin die Identitaet des gesamten Checkmk-Agent-Dienstes +aendern. + +QUELLEN +======= + +https://learn.microsoft.com/en-us/windows/win32/services/localsystem-account +https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer +https://learn.microsoft.com/en-us/biztalk/core/windows-groups-and-user-accounts-in-biztalk-server +https://learn.microsoft.com/en-us/biztalk/core/access-control-for-administrative-roles +https://learn.microsoft.com/en-us/biztalk/core/how-to-modify-group-properties +https://learn.microsoft.com/en-us/powershell/module/activedirectory/add-adgroupmember +https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/klist diff --git a/docs/CheckmkServices.md b/docs/CheckmkServices.md index 5a6e86c..61873fa 100644 --- a/docs/CheckmkServices.md +++ b/docs/CheckmkServices.md @@ -13,7 +13,7 @@ Die Ausgabe ist so gebaut, dass sie auch mit Checkmk 2.4.0p4 kompatibel bleibt: Zweck: - Prueft, ob der BizTalk-WMI-Namespace erreichbar ist. -- Zeigt Server, Gruppe, Management-DB und Master-MessageBox-DB aus `MSBTS_GroupSetting`. +- Zeigt Server, Gruppe, konfigurierte BizTalk-Operator-Gruppe, Management-DB und Master-MessageBox-DB aus `MSBTS_GroupSetting`. Status: @@ -53,7 +53,9 @@ Fehlerkategorien: | `Sql/Connectivity` | DNS, SQL-Dienst, Instanz, TCP-Port oder Firewall nicht erreichbar. | | `Sql/Timeout` | Verbindungsaufbau oder Testabfrage ueberschreitet das konfigurierte Zeitlimit. | | `Sql/Provider` | Sonstiger von SQL Server oder SqlClient gemeldeter Providerfehler. | -| `Sql/Configuration` | WMI-Ziele unvollstaendig oder TLS-, Zertifikats-, SPN-/SSPI-Konfiguration fehlerhaft. | +| `Sql/Configuration` | WMI-Ziele aus einem Nicht-Berechtigungsgrund unvollstaendig oder TLS-, Zertifikats-, SPN-/SSPI-Konfiguration fehlerhaft. | + +Ist die Zielermittlung wegen eines eingebetteten SQL-Loginfehlers des BizTalk-WMI-Providers unvollstaendig, wird die Folgediagnose als `Sql/Permission` statt als `Sql/Configuration` ausgegeben. Metriken: diff --git a/docs/ExampleOutput.md b/docs/ExampleOutput.md index 9c445a5..1bfbd7f 100644 --- a/docs/ExampleOutput.md +++ b/docs/ExampleOutput.md @@ -14,7 +14,7 @@ ## Gesunder BizTalk-Server ```text -0 "BizTalk Platform" - BizTalk WMI and platform data reachable, server=BIZTALK01, group=BizTalkMgmtDb, mgmt_db=SQL01\BizTalkMgmtDb, msgbox_db=SQL01\BizTalkMsgBoxDb +0 "BizTalk Platform" - BizTalk WMI and platform data reachable, server=BIZTALK01, group=BizTalkMgmtDb, operator_group=CONTOSO\BizTalk Server Operators, mgmt_db=SQL01\BizTalkMgmtDb, msgbox_db=SQL01\BizTalkMsgBoxDb 0 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=2;;;0|biztalk_sql_targets_failed=0;;1;0 SQL access targets=2, available=2, discovery_complete=True, execution_identity=NT AUTHORITY\SYSTEM, network_identity=\BIZTALK01$; databases=Management=SQL01\BizTalkMgmtDb:OK, MasterMessageBox=SQL01\BizTalkMsgBoxDb:OK 0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0|biztalk_suspended_resumable=0;1;;0|biztalk_suspended_nonresumable=0;;1;0 No suspended BizTalk service instances found. 0 "BizTalk Host Instances" biztalk_host_instances_total=4;;;0|biztalk_host_instances_started=4;;;0|biztalk_host_instances_stopped=0;;1;0|biztalk_host_instances_pending=0;1;;0|biztalk_host_instances_unknown=0;;1;0 Host instances total=4, started=4, stopped=0, pending=0, unknown=0 @@ -40,6 +40,13 @@ 3 "BizTalk Suspended Instances" - Suspendierte Instanzen konnten nicht verlaesslich gelesen werden. Ein leerer Datenbestand wird nicht als OK gewertet.; diagnostics: Wmi/Permission [MSBTS_ServiceInstance]: Zugriff auf MSBTS_ServiceInstance wurde im LocalSystem-Kontext verweigert. Massnahme: Agent-Dump pruefen und Computerkonto \BIZTALK01$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen. Technik: UnauthorizedAccessException HRESULT=0x80070005: Access is denied ``` +## SQL-Loginfehler innerhalb des BizTalk-WMI-Providers + +```text +3 "BizTalk Platform" - BizTalk-Plattformdaten konnten nicht vollstaendig gelesen werden.; diagnostics: Wmi/Permission [MSBTS_GroupSetting]: BizTalk-WMI-Provider konnte den SQL-Zugriff fuer BEW\AV23AGPWBIO1$ nicht anmelden. Massnahme: Computerkonto BEW\AV23AGPWBIO1$ der in der BizTalk-Gruppe konfigurierten BizTalk-Operator-Gruppe zuordnen; keine direkten SQL-Logins oder Datenbankrollen vergeben. Technik: COMException HRESULT=0x80131904: Internal error from OLEDB provider: 'Login failed for user 'BEW\AV23AGPWBIO1$'.' +3 "BizTalk SQL Access" biztalk_sql_targets_total=0;;;0|biztalk_sql_targets_available=0;;;0|biztalk_sql_targets_failed=0;;1;0 SQL access targets=0, available=0, discovery_complete=False, execution_identity=NT AUTHORITY\SYSTEM, network_identity=BEW\AV23AGPWBIO1$; diagnostics: Sql/Permission [BizTalk database discovery]: SQL-Zielermittlung ist unvollstaendig, weil der BizTalk-WMI-Provider beim SQL-Zugriff abgewiesen wurde. +``` + ## WMI-Schemafehler ```text diff --git a/docs/Integration.md b/docs/Integration.md index aa6a16f..c0debb5 100644 --- a/docs/Integration.md +++ b/docs/Integration.md @@ -86,13 +86,24 @@ DOMAIN\BIZTALKSERVER$ Lokale Administratorrechte von `LocalSystem` gelten nicht automatisch auf dem entfernten SQL Server. Daher koennen SQL-gestuetzte WMI-Abfragen fehlschlagen, obwohl der lokale WMI-Namespace grundsaetzlich erreichbar ist. +### Konkreter ACC-Befund + +Auf `AV23AGPWBIO1` meldet der Provider `COMException HRESULT=0x80131904` und als inneren SQL-Fehler `Login failed for user 'BEW\AV23AGPWBIO1$'`. Das beweist zugleich: + +- der Check laeuft als `NT AUTHORITY\SYSTEM` +- der lokale BizTalk-WMI-Namespace ist erreichbar +- der Netzwerkzugriff erfolgt als Maschinenkonto `BEW\AV23AGPWBIO1$` +- dieses Konto besitzt noch nicht die durch BizTalk vermittelte SQL-Berechtigung + +Die vielen `UNKNOWN`-Services sind Folgewirkungen desselben Fehlers. WMI-Namespace-ACL, DCOM und Firewall muessen fuer diesen Befund nicht erweitert werden. Die zwei Fehler und sechs Warnungen in `BizTalk Event Log` sind davon unabhaengig und separat auszuwerten. + ### Verbindlicher Funktionstest Der direkte Start des Wrappers in einer administrativen Eingabeaufforderung ist nur ein Vorabtest, weil er mit dem angemeldeten Benutzer laeuft. Fuer die Berechtigungspruefung ist die Ausgabe unter dem echten Checkmk-Kontext massgeblich: ```powershell & "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump | - Select-String -Pattern "BizTalk|Access denied|Unauthorized|UNKNOWN" -Context 0,1 + Select-String -Pattern "BizTalk|Login failed|Access denied|Unauthorized|UNKNOWN" -Context 0,1 ``` Die Ausgabe muss die sechs stabilen `BizTalk ...` Services mit plausiblen Daten enthalten. `Access denied`, `UnauthorizedAccessException`, `Sql/Permission` und ein berechtigungsbedingtes `UNKNOWN` weisen auf eine fehlende Rollenzuordnung hin. @@ -115,12 +126,21 @@ Alternativ koennen die Checkmk-Kollegen in der Agent Bakery die Regeln `Set exec ### Least-Privilege-Vorgehen -1. Das verwendete Computerkonto feststellen, normalerweise `DOMAIN\BIZTALKSERVER$`. -2. Die bei der BizTalk-Konfiguration hinterlegte Operator-Gruppe ermitteln. Sie kann anders als `BizTalk Server Operators` benannt sein. -3. Das Computerkonto in diese Operator-Gruppe aufnehmen. -4. Kerberos-Tickets des Systemkontos erneuern oder den Server in einem Wartungsfenster neu starten. -5. `cmk-agent-ctl.exe dump` erneut ausfuehren. -6. Nur bei weiterhin abgelehnten, konkret identifizierten WMI-Klassen mit BizTalk- und SQL-Administration klaeren, ob `BizTalk Server Administrators` erforderlich ist. +1. Dienstkonto mit `Get-CimInstance Win32_Service` kontrollieren; der ACC-Dump bestaetigt bereits `NT AUTHORITY\SYSTEM`. +2. In der BizTalk Administration Console unter `BizTalk Group` > `Properties` > `General` den Wert `BizTalk Operators Group` ablesen. Alternativ kann ein berechtigtes Konto `MSBTS_GroupSetting.BizTalkOperatorGroup` abfragen. +3. Ein AD-Administrator fuegt das Computerobjekt `AV23AGPWBIO1` genau dieser Gruppe hinzu: + + ```powershell + Import-Module ActiveDirectory + $computer = Get-ADComputer -Identity 'AV23AGPWBIO1' + Add-ADGroupMember -Identity '' -Members $computer -WhatIf + ``` + + Erst nach Kontrolle ohne `-WhatIf` ausfuehren. Keine direkten SQL-Logins, Datenbankrollen oder `sysadmin`-Rechte fuer `BEW\AV23AGPWBIO1$` anlegen. + +4. AD-Replikation abwarten und den Server im Wartungsfenster neu starten. Alternativ Maschinen-Tickets in einer administrativen Shell mit `klist purge -li 0x3e7` verwerfen und den Checkmk-Agent-Dienst neu starten. +5. Agent-Dump erneut ausfuehren. Erwartet werden `operator_group=<...>`, `targets=2`, `available=2`, `discovery_complete=True` und keine berechtigungsbedingten `UNKNOWN`-Services. +6. Nur bei weiterhin abgelehnten, konkret identifizierten WMI-Klassen mit BizTalk- und SQL-Administration klaeren, ob erweiterte Rechte erforderlich sind. Die BizTalk-Operator-Rolle ist fuer grundlegende Administration und Monitoring vorgesehen. Sie kann Zustands- und Message-Flow-Informationen lesen, darf aber keine Konfiguration oder Nachrichteninhalte einsehen. Das entspricht dem lesenden Funktionsumfang dieses Plugins. Keine direkten SQL-Rollen in den BizTalk-Datenbanken hinzufuegen; die von BizTalk konfigurierte Windows-Gruppe soll die Berechtigungen vermitteln. @@ -134,7 +154,7 @@ Entscheidungsmatrix: | `BizTalk SQL Access` meldet `Sql/Permission` | Maschinenkonto in die konfigurierte BizTalk-Operator-Gruppe aufnehmen, Kerberos erneuern und Agent-Dump wiederholen. | | `BizTalk SQL Access` meldet `Sql/Connectivity` | SQL-Server-/Instanzname, DNS, Dienst, TCP-Port und Firewall pruefen. | | `BizTalk SQL Access` meldet `Sql/Timeout` | SQL-/Netzwerkauslastung untersuchen; Timeout nur nach Ursachenanalyse anpassen. | -| Verbindung funktioniert, einzelne SQL-gestuetzte Klassen melden Zugriffsfehler | `DOMAIN\BIZTALKSERVER$` zunaechst in die konfigurierte BizTalk-Operator-Gruppe aufnehmen. | +| SQL-gestuetzte Klassen melden `0x80131904` oder `Login failed for user` | Das exakt genannte Computerkonto in die konfigurierte BizTalk-Operator-Gruppe aufnehmen. | | Nur `BizTalk Event Log` ist `UNKNOWN` | Lokalen Zugriff auf das Application Event Log pruefen. | | Fehler bleibt nach Operator-Zuweisung bestehen | Exakte WMI-Klasse anhand der Service-Ausgabe bestimmen und deren BizTalk-/SQL-Rollenanforderung pruefen. | @@ -151,8 +171,13 @@ Quellen: - BizTalk Minimum Security User Rights: https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights - BizTalk Access Control and Data Security: https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-security - BizTalk `MSBTS_GroupSetting`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-wmi +- BizTalk Windows-Gruppen und SQL-Rollen: https://learn.microsoft.com/en-us/biztalk/core/windows-groups-and-user-accounts-in-biztalk-server +- BizTalk administrative Rollen: https://learn.microsoft.com/en-us/biztalk/core/access-control-for-administrative-roles +- BizTalk Gruppen-Eigenschaften: https://learn.microsoft.com/en-us/biztalk/core/how-to-modify-group-properties - BizTalk WMI Core Server Classes: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/core-server-classes - Microsoft LocalSystem und Computerkonten: https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer +- Microsoft `Add-ADGroupMember`: https://learn.microsoft.com/en-us/powershell/module/activedirectory/add-adgroupmember +- Microsoft `klist`: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/klist - Microsoft WMI Namespace Security: https://learn.microsoft.com/en-us/windows/win32/wmisdk/access-to-wmi-namespaces ## Empfohlene Host-Struktur diff --git a/src/BizTalkCheckmkPulse/CheckmkLocalFormatter.cs b/src/BizTalkCheckmkPulse/CheckmkLocalFormatter.cs index bd87166..bfec38c 100644 --- a/src/BizTalkCheckmkPulse/CheckmkLocalFormatter.cs +++ b/src/BizTalkCheckmkPulse/CheckmkLocalFormatter.cs @@ -96,6 +96,7 @@ namespace BizTalkCheckmkPulse detail.Append(available ? "BizTalk WMI and platform data reachable" : "BizTalk WMI or required platform data not readable"); detail.Append(", server=").Append(EmptyAsUnknown(result.Platform.ServerName)); AppendOptional(detail, "group", result.Platform.GroupName); + AppendOptional(detail, "operator_group", result.Platform.OperatorGroup); AppendOptional(detail, "mgmt_db", JoinDb(result.Platform.ManagementDbServer, result.Platform.ManagementDbName)); AppendOptional(detail, "msgbox_db", JoinDb(result.Platform.MessageBoxDbServer, result.Platform.MessageBoxDbName)); diff --git a/src/BizTalkCheckmkPulse/Models.cs b/src/BizTalkCheckmkPulse/Models.cs index 3833d43..46ddde0 100644 --- a/src/BizTalkCheckmkPulse/Models.cs +++ b/src/BizTalkCheckmkPulse/Models.cs @@ -124,6 +124,7 @@ namespace BizTalkCheckmkPulse public bool RuntimeArtifactsDataAvailable { get; set; } public string ServerName { get; set; } public string GroupName { get; set; } + public string OperatorGroup { get; set; } public string ManagementDbServer { get; set; } public string ManagementDbName { get; set; } public string MessageBoxDbServer { get; set; } diff --git a/src/BizTalkCheckmkPulse/SqlConnectivityProbe.cs b/src/BizTalkCheckmkPulse/SqlConnectivityProbe.cs index d3f7f9b..49dbf07 100644 --- a/src/BizTalkCheckmkPulse/SqlConnectivityProbe.cs +++ b/src/BizTalkCheckmkPulse/SqlConnectivityProbe.cs @@ -39,14 +39,25 @@ namespace BizTalkCheckmkPulse if (!result.Platform.PlatformDataAvailable) { + var wmiPermissionFailure = result.Diagnostics.Any(x => + x.Area == DiagnosticArea.Wmi + && x.Category == DiagnosticCategory.Permission + && x.Required + && string.Equals(x.Component, "MSBTS_GroupSetting", StringComparison.OrdinalIgnoreCase)); result.Diagnostics.Add(new ProbeDiagnostic { Area = DiagnosticArea.Sql, - Category = DiagnosticCategory.Configuration, + Category = wmiPermissionFailure + ? DiagnosticCategory.Permission + : DiagnosticCategory.Configuration, Component = "BizTalk database discovery", Required = true, - Summary = "SQL-Zielermittlung ist unvollstaendig, weil nicht alle erforderlichen BizTalk-Plattformklassen gelesen wurden.", - Action = "Zuerst den Service 'BizTalk Platform' und MSBTS_GroupSetting pruefen. Danach den Agent-Dump erneut ausfuehren." + Summary = wmiPermissionFailure + ? "SQL-Zielermittlung ist unvollstaendig, weil der BizTalk-WMI-Provider beim SQL-Zugriff abgewiesen wurde." + : "SQL-Zielermittlung ist unvollstaendig, weil nicht alle erforderlichen BizTalk-Plattformklassen gelesen wurden.", + Action = wmiPermissionFailure + ? "Zuerst die Wmi/Permission-Diagnose und die Mitgliedschaft des Computerkontos in der konfigurierten BizTalk-Operator-Gruppe beheben." + : "Zuerst den Service 'BizTalk Platform' und MSBTS_GroupSetting pruefen. Danach den Agent-Dump erneut ausfuehren." }); } @@ -75,9 +86,19 @@ namespace BizTalkCheckmkPulse var isLocalSystem = identity != null && identity.User != null && identity.User.IsWellKnown(WellKnownSidType.LocalSystemSid); - result.NetworkIdentityHint = isLocalSystem - ? "\\" + Environment.MachineName + "$" - : result.ExecutionIdentity; + if (isLocalSystem) + { + if (string.IsNullOrWhiteSpace(result.NetworkIdentityHint) + || string.Equals(result.NetworkIdentityHint, "unknown", StringComparison.OrdinalIgnoreCase) + || result.NetworkIdentityHint.StartsWith("\\", StringComparison.OrdinalIgnoreCase)) + { + result.NetworkIdentityHint = "\\" + Environment.MachineName + "$"; + } + } + else + { + result.NetworkIdentityHint = result.ExecutionIdentity; + } } } catch (Exception ex) diff --git a/src/BizTalkCheckmkPulse/WmiBizTalkProbe.cs b/src/BizTalkCheckmkPulse/WmiBizTalkProbe.cs index ea0675a..7e04342 100644 --- a/src/BizTalkCheckmkPulse/WmiBizTalkProbe.cs +++ b/src/BizTalkCheckmkPulse/WmiBizTalkProbe.cs @@ -25,7 +25,7 @@ namespace BizTalkCheckmkPulse private const int OrchestrationStarted = 4; private const int EAccessDenied = unchecked((int)0x80070005); internal const string GroupSettingQuery = - "SELECT Name, MgmtDbServerName, MgmtDbName, SubscriptionDBServerName, SubscriptionDBName FROM MSBTS_GroupSetting"; + "SELECT Name, BizTalkOperatorGroup, MgmtDbServerName, MgmtDbName, SubscriptionDBServerName, SubscriptionDBName FROM MSBTS_GroupSetting"; private readonly MonitoringOptions _options; /// @@ -105,6 +105,7 @@ namespace BizTalkCheckmkPulse groupFound = true; result.Platform.GroupName = FirstNonEmpty(WmiHelpers.GetString(item, "Name"), WmiHelpers.GetString(item, "MgmtDbName")); + result.Platform.OperatorGroup = WmiHelpers.GetString(item, "BizTalkOperatorGroup"); result.Platform.ManagementDbServer = WmiHelpers.GetString(item, "MgmtDbServerName"); result.Platform.ManagementDbName = WmiHelpers.GetString(item, "MgmtDbName"); result.Platform.MessageBoxDbServer = WmiHelpers.GetString(item, "SubscriptionDBServerName"); @@ -502,6 +503,12 @@ namespace BizTalkCheckmkPulse TimeSpan? duration) { var category = ClassifyWmiException(exception); + var sqlLoginPrincipal = ExtractSqlLoginPrincipal(exception.Message); + if (!string.IsNullOrWhiteSpace(sqlLoginPrincipal)) + { + result.NetworkIdentityHint = sqlLoginPrincipal; + } + var technicalDetails = exception.GetType().Name + " HRESULT=0x" + exception.HResult.ToString("X8") + ": " + exception.Message; @@ -521,8 +528,8 @@ namespace BizTalkCheckmkPulse Category = category, Component = component, Required = required, - Summary = BuildWmiSummary(category, component, connectionFailure), - Action = BuildWmiAction(category, connectionFailure), + Summary = BuildWmiSummary(category, component, connectionFailure, sqlLoginPrincipal), + Action = BuildWmiAction(category, connectionFailure, sqlLoginPrincipal), TechnicalDetails = technicalDetails }); } @@ -551,7 +558,7 @@ namespace BizTalkCheckmkPulse /// /// Zu klassifizierende Exception. /// Handlungsorientierte Diagnosekategorie. - private static DiagnosticCategory ClassifyWmiException(Exception exception) + internal static DiagnosticCategory ClassifyWmiException(Exception exception) { var managementException = exception as ManagementException; var comException = exception as COMException; @@ -583,6 +590,15 @@ namespace BizTalkCheckmkPulse } var message = exception.Message ?? string.Empty; + if (ContainsAny( + message, + "Login failed for user", + "Cannot open database", + "not associated with a trusted SQL Server connection")) + { + return DiagnosticCategory.Permission; + } + if (ContainsAny(message, "timed out", "timeout", "Zeitlimit")) { return DiagnosticCategory.Timeout; @@ -596,6 +612,45 @@ namespace BizTalkCheckmkPulse return DiagnosticCategory.Provider; } + /// + /// Extrahiert das von SQL Server abgewiesene Konto aus der Provider-Fehlermeldung. + /// + /// WMI-/OLEDB-Fehlermeldung. + /// Abgewiesenes Konto oder eine leere Zeichenfolge. + internal static string ExtractSqlLoginPrincipal(string message) + { + const string marker = "Login failed for user"; + if (string.IsNullOrWhiteSpace(message)) + { + return string.Empty; + } + + var markerIndex = message.IndexOf(marker, StringComparison.OrdinalIgnoreCase); + if (markerIndex < 0) + { + return string.Empty; + } + + var valueStart = markerIndex + marker.Length; + while (valueStart < message.Length + && (char.IsWhiteSpace(message[valueStart]) || message[valueStart] == ':')) + { + valueStart++; + } + + if (valueStart >= message.Length + || (message[valueStart] != '\'' && message[valueStart] != '"')) + { + return string.Empty; + } + + var quote = message[valueStart]; + var valueEnd = message.IndexOf(quote, valueStart + 1); + return valueEnd > valueStart + 1 + ? message.Substring(valueStart + 1, valueEnd - valueStart - 1).Trim() + : string.Empty; + } + /// /// Erstellt eine kurze Fehlerursache fuer einen WMI-Fehler. /// @@ -603,11 +658,20 @@ namespace BizTalkCheckmkPulse /// Betroffene Komponente. /// Kennzeichen fuer den Namespace-Verbindungsaufbau. /// Menschenlesbare Fehlerzusammenfassung. - private static string BuildWmiSummary(DiagnosticCategory category, string component, bool connectionFailure) + private static string BuildWmiSummary( + DiagnosticCategory category, + string component, + bool connectionFailure, + string sqlLoginPrincipal) { switch (category) { case DiagnosticCategory.Permission: + if (!string.IsNullOrWhiteSpace(sqlLoginPrincipal)) + { + return "BizTalk-WMI-Provider konnte den SQL-Zugriff fuer " + sqlLoginPrincipal + " nicht anmelden."; + } + return "Zugriff auf " + component + " wurde im LocalSystem-Kontext verweigert."; case DiagnosticCategory.Configuration: return connectionFailure @@ -630,11 +694,20 @@ namespace BizTalkCheckmkPulse /// Klassifizierte Fehlerart. /// Kennzeichen fuer den Namespace-Verbindungsaufbau. /// Empfohlener Diagnoseschritt. - private static string BuildWmiAction(DiagnosticCategory category, bool connectionFailure) + private static string BuildWmiAction( + DiagnosticCategory category, + bool connectionFailure, + string sqlLoginPrincipal) { switch (category) { case DiagnosticCategory.Permission: + if (!string.IsNullOrWhiteSpace(sqlLoginPrincipal)) + { + return "Computerkonto " + sqlLoginPrincipal + + " der in der BizTalk-Gruppe konfigurierten BizTalk-Operator-Gruppe zuordnen; keine direkten SQL-Logins oder Datenbankrollen vergeben."; + } + return connectionFailure ? "Namespace-ACL fuer root\\MicrosoftBizTalkServer gezielt pruefen. LocalSystem benoetigt lokalen Lesezugriff; keine pauschalen WMI-Rechte vergeben." : "Agent-Dump pruefen und Computerkonto \\" + Environment.MachineName + "$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen."; diff --git a/tests/BizTalkCheckmkPulse.Tests/Program.cs b/tests/BizTalkCheckmkPulse.Tests/Program.cs index 4daa469..c3ecb23 100644 --- a/tests/BizTalkCheckmkPulse.Tests/Program.cs +++ b/tests/BizTalkCheckmkPulse.Tests/Program.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; namespace BizTalkCheckmkPulse.Tests { internal static class Program { private static readonly List Failures = new List(); + private static int ExecutedTests; private static int Main() { @@ -16,10 +18,13 @@ namespace BizTalkCheckmkPulse.Tests Run("KnownApplicationCreatesService", KnownApplicationCreatesService); Run("ServerNamesAreComparedWithoutWql", ServerNamesAreComparedWithoutWql); Run("GroupSettingQueryUsesDocumentedSchema", GroupSettingQueryUsesDocumentedSchema); + Run("ProviderSqlLoginFailureIsPermission", ProviderSqlLoginFailureIsPermission); + Run("RejectedSqlPrincipalIsExtracted", RejectedSqlPrincipalIsExtracted); + Run("PlatformPermissionPropagatesToSqlDiscovery", PlatformPermissionPropagatesToSqlDiscovery); if (Failures.Count == 0) { - Console.WriteLine("PASS: 6 tests"); + Console.WriteLine("PASS: " + ExecutedTests + " tests"); return 0; } @@ -75,11 +80,54 @@ namespace BizTalkCheckmkPulse.Tests { var query = WmiBizTalkProbe.GroupSettingQuery; Assert(query.Contains("FROM MSBTS_GroupSetting"), "MSBTS_GroupSetting query missing"); + Assert(query.Contains("BizTalkOperatorGroup"), "configured operator group property missing"); Assert(query.Contains("SubscriptionDBServerName"), "master MessageBox server property missing"); Assert(query.Contains("SubscriptionDBName"), "master MessageBox database property missing"); Assert(query.IndexOf("MessageBoxSetting", StringComparison.OrdinalIgnoreCase) < 0, "unsupported MessageBoxSetting class present"); } + private static void ProviderSqlLoginFailureIsPermission() + { + var exception = new COMException( + "Internal error from OLEDB provider: 'Login failed for user 'BEW\\AV23AGPWBIO1$'.'", + unchecked((int)0x80131904)); + AssertEqual( + DiagnosticCategory.Permission, + WmiBizTalkProbe.ClassifyWmiException(exception), + "provider SQL login classification"); + } + + private static void RejectedSqlPrincipalIsExtracted() + { + var message = "Internal error from OLEDB provider: 'Login failed for user 'BEW\\AV23AGPWBIO1$'.'"; + AssertEqual( + "BEW\\AV23AGPWBIO1$", + WmiBizTalkProbe.ExtractSqlLoginPrincipal(message), + "rejected SQL principal"); + } + + private static void PlatformPermissionPropagatesToSqlDiscovery() + { + var result = new ProbeResult(); + result.Diagnostics.Add(new ProbeDiagnostic + { + Area = DiagnosticArea.Wmi, + Category = DiagnosticCategory.Permission, + Component = "MSBTS_GroupSetting", + Required = true + }); + + new SqlConnectivityProbe(new MonitoringOptions()).Query(result); + + var discovery = result.Diagnostics.Single(x => + x.Area == DiagnosticArea.Sql + && x.Component == "BizTalk database discovery"); + AssertEqual( + DiagnosticCategory.Permission, + discovery.Category, + "SQL discovery classification"); + } + private static ProbeResult CreateSuspensionResult(string applicationName) { var result = new ProbeResult(); @@ -95,6 +143,7 @@ namespace BizTalkCheckmkPulse.Tests private static void Run(string name, Action test) { + ExecutedTests++; try { test(); @@ -120,5 +169,21 @@ namespace BizTalkCheckmkPulse.Tests throw new InvalidOperationException(label + ": expected " + expected + ", actual " + actual); } } + + private static void AssertEqual(DiagnosticCategory expected, DiagnosticCategory actual, string label) + { + if (expected != actual) + { + throw new InvalidOperationException(label + ": expected " + expected + ", actual " + actual); + } + } + + private static void AssertEqual(string expected, string actual, string label) + { + if (!string.Equals(expected, actual, StringComparison.Ordinal)) + { + throw new InvalidOperationException(label + ": expected " + expected + ", actual " + actual); + } + } } }