Skip to content

Commit

Permalink
Adds new command to test the functionality of Icinga for Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
LordHepipud committed Mar 25, 2024
1 parent 751e17f commit cd4bc7a
Show file tree
Hide file tree
Showing 32 changed files with 442 additions and 59 deletions.
1 change: 1 addition & 0 deletions doc/100-General/10-Changelog.md
Expand Up @@ -36,6 +36,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
* [#694](https://github.com/Icinga/icinga-powershell-framework/pull/694) Adds support for check objects not being added to summary header
* [#695](https://github.com/Icinga/icinga-powershell-framework/pull/695) Adds security hardening to JEA profiles by always prohibit certain cmdlets
* [#700](https://github.com/Icinga/icinga-powershell-framework/pull/700) Adds feature to support using pipes and multi lines for plugin documentation
* [#701](https://github.com/Icinga/icinga-powershell-framework/pull/701) Adds new command `Test-IcingaForWindows`to check the current environment health by also improving internal handlings on how service information are fetched, preventing a lock on those

## 1.11.1 (2023-11-07)

Expand Down
1 change: 1 addition & 0 deletions doc/300-Knowledge-Base.md
Expand Up @@ -25,3 +25,4 @@ For this reason you will find a list of Icinga knowledge base entries below. Ent
| [IWKB000015](knowledgebase/IWKB000015.md) | Got JSON, but not an object, from IfW API on host 'localhost' port '5668': "Exception while calling \\"Fill\\" with 1 arguments: \\"Invalid syntax near \\"`<Argument>:`\\".\\"" |
| [IWKB000016](knowledgebase/IWKB000016.md) | Checks using Performance Counter fail with various messages like `Exception of type 'System.OutOfMemoryException' was thrown` or `Icinga Invalid Configuration Error was thrown: PerfCounterCategoryMissing: Category "Memory" not found` |
| [IWKB000017](knowledgebase/IWKB000017.md) | Icinga throws exception during plugin execution after uninstalling SCOM or other vendor software using PowerShell modules |
| [IWKB000018](knowledgebase/IWKB000018.md) | Icinga for Windows services throws event id 1500 with error `Exception while calling AuthenticateAsServer: The credentials supplied to the package were not recognized` |
33 changes: 33 additions & 0 deletions doc/knowledgebase/IWKB000018.md
@@ -0,0 +1,33 @@
# Icinga Knowledge Base - IWKB000018

## Short Message

Icinga for Windows services throws event id 1500 with error `Exception while calling AuthenticateAsServer: The credentials supplied to the package were not recognized`

## Example Exception

Icinga for Windows throws an error with event id 1500:

```
Failed to securely establish a communication between this server and the client
A client connection could not be established to this server. This issue is mostly caused by using Self-Signed/Icinga 2 Agent certificates for the server and the client not trusting the certificate. To resolve this issue, either use trusted certificates signed by your trusted CA or setup the client to accept untrusted certificates
Icinga for Windows exception report:
Exception Message:
Exception calling "AuthenticateAsServer" with "4" argument(s): "The credentials supplied to the package were not recognized"
Command Origin:
Internal
...
```

## Reason

This message happens in case the user assigned to run the Icinga for Windows has no sufficient permissions to access the `icingaforwindows.pfx` certificate file or has no permissions to read the private key from the certificate file.

## Solution

To resolve this issue, you will either have to use [JEA-Profiles](../130-JEA/01-JEA-Profiles.md) or use a different user having enough permissions to access private key to the file. In general, only `LocalSystem` or `Administrators` have access to this key, which is why we highly recommend the use of JEA.
8 changes: 8 additions & 0 deletions icinga-powershell-framework.psm1
Expand Up @@ -58,6 +58,14 @@ function Use-Icinga()

if ($LibOnly -eq $FALSE -And $Daemon -eq $FALSE) {
Register-IcingaEventLog;

if ($Minimal -eq $FALSE -And (Test-IcingaFunction -Name 'Invoke-IcingaWindowsScheduledTask')) {

if (Test-IcingaFunction -Name 'Invoke-IcingaWindowsScheduledTask') {
# Use scheduled tasks to fetch our current service configuration for faster load times afterwards
Set-IcingaServiceEnvironment;
}
}
}
}

Expand Down
21 changes: 14 additions & 7 deletions jobs/GetWindowsService.ps1
Expand Up @@ -9,16 +9,23 @@ Use-Icinga -Minimal;
[hashtable]$ServiceData = @{
'Status' = '';
'Present' = $FALSE;
'Name' = 'Unknown';
'DisplayName' = 'Unknown';
'Name' = $ServiceName;
'DisplayName' = $ServiceName;
'User' = 'Unknown';
'ServicePath' = '';
};

try {
$SvcData = Get-Service "$ServiceName" -ErrorAction Stop;
$ServiceData.Status = [string]$SvcData.Status;
$ServiceData.Name = $SvcData.Name;
$ServiceData.DisplayName = $SvcData.DisplayName;
$ServiceData.Present = $TRUE;
$SvcData = Get-IcingaServices "$ServiceName" -ErrorAction Stop;

if ($null -ne $SvcData) {
$ServiceData.Status = [string]$SvcData."$ServiceName".configuration.Status.value;
$ServiceData.User = [string]$SvcData."$ServiceName".configuration.ServiceUser;
$ServiceData.ServicePath = [string]$SvcData."$ServiceName".configuration.ServicePath;
$ServiceData.Name = $SvcData."$ServiceName".metadata.ServiceName;
$ServiceData.DisplayName = $SvcData."$ServiceName".metadata.DisplayName;
$ServiceData.Present = $TRUE;
}
} catch {
$ErrMsg = [string]::Format('Failed to get data for service "{0}": {1}', $ServiceName, $_.Exception.Message);
}
Expand Down
14 changes: 8 additions & 6 deletions lib/core/framework/Install-IcingaForWindowsService.psm1
Expand Up @@ -28,7 +28,7 @@ function Install-IcingaForWindowsService()
{
param(
$Path,
$User,
$User = 'NT Authority\NetworkService',
[SecureString]$Password
);

Expand All @@ -38,14 +38,13 @@ function Install-IcingaForWindowsService()
}

$UpdateFile = [string]::Format('{0}.update', $Path);

$ServiceStatus = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue).Status;
$IfWService = $Global:Icinga.Protected.Environment.'PowerShell Service';

if ((Test-Path $UpdateFile)) {

Write-IcingaConsoleNotice 'Updating Icinga PowerShell Service binary';

if ($ServiceStatus -eq 'Running') {
if ($IfWService.Status -eq 'Running') {
Write-IcingaConsoleNotice 'Stopping Icinga PowerShell service';
Stop-IcingaWindowsService;
Start-Sleep -Seconds 1;
Expand All @@ -68,8 +67,10 @@ function Install-IcingaForWindowsService()
(Get-IcingaPowerShellModuleFile)
);

if ($null -eq $ServiceStatus) {
if ($IfWService.Present -eq $FALSE) {
$ServiceCreation = Start-IcingaProcess -Executable 'sc.exe' -Arguments ([string]::Format('create icingapowershell binPath= "{0}" DisplayName= "Icinga PowerShell Service" start= auto', $Path));
$Global:Icinga.Protected.Environment.'PowerShell Service'.Present = $TRUE;
$Global:Icinga.Protected.Environment.'PowerShell Service'.User = $User;

if ($ServiceCreation.ExitCode -ne 0) {
throw ([string]::Format('Failed to install Icinga PowerShell Service: {0}{1}', $ServiceCreation.Message, $ServiceCreation.Error));
Expand All @@ -90,8 +91,9 @@ function Install-IcingaForWindowsService()
Restart-IcingaForWindows;
Start-Sleep -Seconds 1;
Stop-IcingaWindowsService;
Start-Sleep -Seconds 1;

if ($ServiceStatus -eq 'Running') {
if ($IfWService.Status -eq 'Running') {
Write-IcingaConsoleNotice 'Starting Icinga PowerShell service';
Start-IcingaService 'icingapowershell';
Start-Sleep -Seconds 1;
Expand Down
6 changes: 6 additions & 0 deletions lib/core/framework/New-IcingaEnvironmentVariable.psm1
Expand Up @@ -69,5 +69,11 @@ function New-IcingaEnvironmentVariable()
$Global:Icinga.Protected.Add('Minimal', $FALSE);
$Global:Icinga.Protected.Add('ThreadName', '');
$Global:Icinga.Protected.Add('GarbageCollector', @{ });
$Global:Icinga.Protected.Add(
'Environment', @{
'Icinga Service' = $null;
'PowerShell Service' = $null;
}
);
}
}
6 changes: 4 additions & 2 deletions lib/core/framework/Test-IcingaForWindowsService.psm1
Expand Up @@ -4,8 +4,10 @@ function Test-IcingaForWindowsService()
[switch]$ResolveProblems = $FALSE
);

Set-IcingaServiceEnvironment;

$ServiceData = Get-IcingaForWindowsServiceData;
$ServiceConfig = (Get-IcingaServices -Service 'icingapowershell').icingapowershell.configuration;
$ServiceConfig = $Global:Icinga.Protected.Environment.'PowerShell Service';
[bool]$Passed = $TRUE;

if ($null -eq $ServiceConfig) {
Expand All @@ -18,7 +20,7 @@ function Test-IcingaForWindowsService()
$ServiceData.FullPath,
(Get-IcingaPowerShellModuleFile)
);
[string]$ServicePath = $ServiceConfig.ServicePath.SubString(0, $ServiceConfig.ServicePath.IndexOf(' "'));
[string]$ServicePath = $ServiceConfig.ServicePath.SubString(0, $ServiceConfig.ServicePath.IndexOf(' "'));

if ($ServicePath.Contains('"')) {
Write-IcingaTestOutput -Severity 'Passed' -Message 'Your service installation is not affected by IWKB000009';
Expand Down
1 change: 1 addition & 0 deletions lib/core/framework/Uninstall-IcingaForWindows.psm1
Expand Up @@ -45,6 +45,7 @@ function Uninstall-IcingaForWindows()
}
}

Set-IcingaServiceEnvironment;
Set-IcingaPSLocation;

Write-IcingaConsoleNotice 'Uninstalling Icinga for Windows from this host';
Expand Down
3 changes: 3 additions & 0 deletions lib/core/framework/Uninstall-IcingaForWindowsService.psm1
Expand Up @@ -22,6 +22,8 @@ function Uninstall-IcingaForWindowsService()
[switch]$RemoveFiles = $FALSE
);

Set-IcingaServiceEnvironment;

$ServiceData = Get-IcingaForWindowsServiceData;

Stop-IcingaWindowsService;
Expand All @@ -32,6 +34,7 @@ function Uninstall-IcingaForWindowsService()
switch ($ServiceCreation.ExitCode) {
0 {
Write-IcingaConsoleNotice 'Icinga PowerShell Service was successfully removed';
$Global:Icinga.Protected.Environment.'PowerShell Service'.Present = $FALSE;
}
1060 {
Write-IcingaConsoleWarning 'The Icinga PowerShell Service is not installed';
Expand Down
Expand Up @@ -18,12 +18,7 @@ function Get-IcingaAgentInstallation()
}
}

$IcingaService = Get-IcingaServices -Service 'icinga2';
$ServiceUser = 'NT AUTHORITY\NetworkService';

if ($null -ne $IcingaService) {
$ServiceUser = $IcingaService.icinga2.configuration.ServiceUser;
}
$ServiceUser = Get-IcingaServiceUser;

if ($null -eq $IcingaData) {
return @{
Expand Down
28 changes: 17 additions & 11 deletions lib/core/icingaagent/getters/Get-IcingaServiceUser.psm1
@@ -1,18 +1,24 @@
function Get-IcingaServiceUser()
{
$Services = Get-IcingaServices -Service 'icinga2';
if ($null -eq $Services) {
$Services = Get-IcingaServices -Service 'icingapowershell';
if ($null -eq $Services) {
return $null;
}
}
$IcingaService = $Global:Icinga.Protected.Environment.'Icinga Service';
$IfWService = $Global:Icinga.Protected.Environment.'PowerShell Service';
# Default User
$ServiceUser = 'NT Authority\NetworkService';

$Services = $Services.GetEnumerator() | Select-Object -First 1;
$ServiceUser = ($Services.Value.configuration.ServiceUser).Replace('.\', '');
if ($null -eq $IcingaService -Or $null -eq $IfWService) {
Set-IcingaServiceEnvironment;
}

if ($ServiceUser -eq 'LocalSystem') {
$ServiceUser = 'NT Authority\SYSTEM';
if ($IcingaService.Present) {
$ServiceUser = $IcingaService.User.Replace('.\', '');
if ($ServiceUser -eq 'LocalSystem') {
return 'NT Authority\SYSTEM';
}
} elseif ($IfWService.Present) {
$ServiceUser = $IfWService.User.Replace('.\', '');
if ($ServiceUser -eq 'LocalSystem') {
return 'NT Authority\SYSTEM';
}
}

return $ServiceUser;
Expand Down
2 changes: 2 additions & 0 deletions lib/core/icingaagent/installer/Uninstall-IcingaAgent.psm1
Expand Up @@ -39,6 +39,8 @@ function Uninstall-IcingaAgent()
return $FALSE;
}

$Global:Icinga.Protected.Environment.'Icinga Service'.Present = $FALSE;

if ($RemoveDataFolder) {
Write-IcingaConsoleNotice -Message 'Removing Icinga Agent directory: "{0}"' -Objects $IcingaProgramData;
if ((Remove-ItemSecure -Path $IcingaProgramData -Recurse -Force) -eq $FALSE) {
Expand Down
8 changes: 4 additions & 4 deletions lib/core/icingaagent/misc/Clear-IcingaAgentApiDirectory.psm1
Expand Up @@ -28,20 +28,20 @@ function Clear-IcingaAgentApiDirectory()
[switch]$Force = $FALSE
);

$IcingaService = (Get-IcingaServices -Service icinga2).icinga2;
$IcingaService = $Global:Icinga.Protected.Environment.'Icinga Service';
$ApiDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\var\lib\icinga2\api\');

if ((Test-Path $ApiDirectory) -eq $FALSE) {
Write-IcingaConsoleError 'The Icinga Agent API directory is not present on this system. Please check if the Icinga Agent is installed';
return;
}

if ($IcingaService.configuration.Status.raw -eq 4 -And $Force -eq $FALSE) {
if ($IcingaService.Status -eq 'Running' -And $Force -eq $FALSE) {
Write-IcingaConsoleError 'The API directory can not be deleted while the Icinga Agent is running. Use the "-Force" argument to stop the service, flush the directory and restart the service again.';
return;
}

if ($IcingaService.configuration.Status.raw -eq 4) {
if ($IcingaService.Status -eq 'Running') {
Stop-IcingaService icinga2;
Start-Sleep -Seconds 1;
}
Expand All @@ -50,7 +50,7 @@ function Clear-IcingaAgentApiDirectory()
Remove-ItemSecure -Path (Join-Path -Path $ApiDirectory -ChildPath '*') -Recurse -Force | Out-Null;
Start-Sleep -Seconds 1;

if ($IcingaService.configuration.Status.raw -eq 4) {
if ($IcingaService.Status -eq 'Running') {
Start-IcingaService icinga2;
}
}
8 changes: 5 additions & 3 deletions lib/core/icingaagent/repair/Repair-IcingaService.psm1
Expand Up @@ -21,7 +21,7 @@ function Repair-IcingaService()
[string]$RootFolder = ''
);

if ($null -ne (Get-Service 'icinga2' -ErrorAction SilentlyContinue)) {
if ($Global:Icinga.Protected.Environment.'Icinga Service'.Present) {
Write-IcingaConsoleNotice -Message 'The Icinga Agent service is already installed. If you received the error "The specified service has been marked for deletion", please have a look at https://icinga.com/docs/icinga-for-windows/latest/doc/knowledgebase/IWKB000011/'
return;
}
Expand Down Expand Up @@ -64,12 +64,14 @@ function Repair-IcingaService()

if ($IcingaService.ExitCode -ne 0) {
Write-IcingaConsoleError `
-Message 'Failed to install Icinga Agent service: {0}{1}' `
-Objects $IcingaService.Message, $IcingaService.Error;
-Message 'Failed to install Icinga Agent service: {0}{1}' `
-Objects $IcingaService.Message, $IcingaService.Error;

return;
}

$Global:Icinga.Protected.Environment.'Icinga Service'.Present = $TRUE;

$IcingaData = Get-IcingaAgentInstallation;
$ConfigUser = Get-IcingaPowerShellConfig -Path 'Framework.Icinga.ServiceUser';
$ServiceUser = $IcingaData.User;
Expand Down
4 changes: 4 additions & 0 deletions lib/core/icingaagent/setters/Set-IcingaAcl.psm1
Expand Up @@ -11,6 +11,10 @@ function Set-IcingaAcl()
return;
}

if ($IcingaUser.ToLower() -eq 'nt authority\system' -Or $IcingaUser.ToLower() -like '*localsystem') {
return;
}

$DirectoryAcl = (Get-Item -Path $Directory).GetAccessControl('Access');
$DirectoryAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$IcingaUser,
Expand Down
39 changes: 34 additions & 5 deletions lib/core/icingaagent/setters/Set-IcingaAgentServiceUser.psm1
@@ -1,19 +1,37 @@
function Set-IcingaServiceUser()
{
param (
[string]$User,
[string]$User = 'NT Authority\NetworkService',
[securestring]$Password,
[string]$Service = 'icinga2',
[switch]$SetPermission
[switch]$SetPermission = $FALSE
);

if ([string]::IsNullOrEmpty($User)) {
Write-IcingaConsoleError -Message 'Please specify a username to modify the service user';
return $FALSE;
}

if ($null -eq (Get-Service $Service -ErrorAction SilentlyContinue)) {
return $FALSE;
switch ($Service.ToLower()) {
'icinga2' {
if ($Global:Icinga.Protected.Environment.'Icinga Service'.Present -eq $FALSE) {
Write-IcingaConsoleDebug -Message 'Trying to update user for service "icinga2" while the service is not installed yet';
return $FALSE;
}
break;
};
'icingapowershell' {
if ($Global:Icinga.Protected.Environment.'PowerShell Service'.Present -eq $FALSE) {
Write-IcingaConsoleDebug -Message 'Trying to update user for service "icingapowershell" while the service is not installed yet';
return $FALSE;
}
break;
};
default {
if ($null -eq (Get-Service $Service -ErrorAction SilentlyContinue)) {
return $FALSE;
}
};
}

if ($User.Contains('@')) {
Expand All @@ -35,9 +53,20 @@ function Set-IcingaServiceUser()

if ($Output.ExitCode -eq 0) {

switch ($Service.ToLower()) {
'icinga2' {
$Global:Icinga.Protected.Environment.'Icinga Service'.User = $User;
break;
};
'icingapowershell' {
$Global:Icinga.Protected.Environment.'PowerShell Service'.User = $User;
break;
};
}

if ($SetPermission) {
Set-IcingaAgentServicePermission | Out-Null;
Set-IcingaUserPermissions;
Set-IcingaUserPermissions -IcingaUser $User;
}

Write-IcingaConsoleNotice 'Service User "{0}" for service "{1}" successfully updated' -Objects $User, $Service;
Expand Down

0 comments on commit cd4bc7a

Please sign in to comment.