diff --git a/doc/100-General/10-Changelog.md b/doc/100-General/10-Changelog.md index c1e9e32..6218f7f 100644 --- a/doc/100-General/10-Changelog.md +++ b/doc/100-General/10-Changelog.md @@ -13,10 +13,13 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic ## 1.12.1 (tbd) +[Issues and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/33) + ### Bugfixes * [#707](https://github.com/Icinga/icinga-powershell-framework/pull/707) Fixes size of the `Icinga for Windows` eventlog by setting it to `20MiB`, allowing to store more events before they are overwritten * [#710](https://github.com/Icinga/icinga-powershell-framework/pull/710) Fixes various console errors while running Icinga for Windows outside of an administrative shell +* [#713](https://github.com/Icinga/icinga-powershell-framework/pull/713) Fixes Icinga for Windows REST-Api which fails during certificate auth handling while running as `NT Authority\NetworkService` * [#714](https://github.com/Icinga/icinga-powershell-framework/pull/714) Fixes missing service environment information during initial setup of Icinga for Windows v1.12 on some systems * [#715](https://github.com/Icinga/icinga-powershell-framework/pull/715) Fixes internal scheduled task handling and certificate renewal task by setting the user to `LocalSystem` instead of any administrative user or group, ensuring compatibility with all Windows versions as well as managing by using WinRM and SSH * [#716](https://github.com/Icinga/icinga-powershell-framework/pull/716) Fixes Icinga for Windows certificate creation while using WinRM or SSH for remote connections diff --git a/lib/daemon/Start-IcingaPowerShellDaemon.psm1 b/lib/daemon/Start-IcingaPowerShellDaemon.psm1 index d5f12e1..5c3f749 100644 --- a/lib/daemon/Start-IcingaPowerShellDaemon.psm1 +++ b/lib/daemon/Start-IcingaPowerShellDaemon.psm1 @@ -22,7 +22,6 @@ function Start-IcingaForWindowsDaemon() [string]$MainServicePidFile = (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'service.pid'); [string]$JeaPidFile = (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'jea.pid'); [string]$JeaProfile = Get-IcingaPowerShellConfig -Path 'Framework.JEAProfile'; - [Security.Cryptography.X509Certificates.X509Certificate2]$Certificate = Get-IcingaForWindowsCertificate; [string]$JeaPid = ''; if (Test-IcingaJEAServiceRunning) { @@ -37,7 +36,14 @@ function Start-IcingaForWindowsDaemon() # Todo: Add config for active background tasks. Set it to 20 for the moment Add-IcingaThreadPool -Name 'MainPool' -MaxInstances 20; - $Global:Icinga.Public.Add('SSLCertificate', $Certificate); + $Global:Icinga.Public.Add( + 'SSL', + @{ + 'Certificate' = $null; + 'CertFile' = $null; + 'CertThumbprint' = $null; + } + ); New-IcingaThreadInstance -Name "Main" -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') -Command 'Add-IcingaForWindowsDaemon' -Start; } else { @@ -47,13 +53,21 @@ function Start-IcingaForWindowsDaemon() try { Use-Icinga -Daemon; - Write-IcingaFileSecure -File ($args[1]) -Value $PID; + Write-IcingaFileSecure -File ($args[0]) -Value $PID; $Global:Icinga.Protected.JEAContext = $TRUE; $Global:Icinga.Protected.RunAsDaemon = $TRUE; # Todo: Add config for active background tasks. Set it to 20 for the moment Add-IcingaThreadPool -Name 'MainPool' -MaxInstances 20; - $Global:Icinga.Public.Add('SSLCertificate', $args[0]); + + $Global:Icinga.Public.Add( + 'SSL', + @{ + 'Certificate' = $null; + 'CertFile' = $null; + 'CertThumbprint' = $null; + } + ); New-IcingaThreadInstance -Name "Main" -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') -Command 'Add-IcingaForWindowsDaemon' -Start; @@ -63,7 +77,7 @@ function Start-IcingaForWindowsDaemon() } catch { Write-IcingaEventMessage -EventId 1600 -Namespace 'Framework' -ExceptionObject $_; } - } -Args $Certificate, $JeaPidFile; + } -Args $JeaPidFile; } if ($JEARestart) { diff --git a/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 b/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 index dde51c8..14a3a34 100644 --- a/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 +++ b/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 @@ -54,15 +54,29 @@ function New-IcingaForWindowsRESTApi() Write-IcingaDebugMessage -Message ($Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints | Out-String); + $Global:Icinga.Public.SSL.CertFile = $CertFile; + $Global:Icinga.Public.SSL.CertThumbprint = $CertThumbprint; + while ($TRUE) { - if ($null -eq $Global:Icinga.Public.SSLCertificate) { - $Global:Icinga.Public.SSLCertificate = (Get-IcingaForWindowsCertificate); - } else { + if ($null -eq $Global:Icinga.Public.SSL.Certificate) { + # In case we are not inside a JEA context, use the SSLCertForSocket function to create the certificate file on the fly + # while maintaining the new wait feature. This fix is required, as the NetworkService user has no permssion + # to read the icingaforwindows.pfx file with the private key + if ([string]::IsNullOrEmpty((Get-IcingaJEAContext))) { + $Global:Icinga.Public.SSL.Certificate = Get-IcingaSSLCertForSocket ` + -CertFile $Global:Icinga.Public.SSL.CertFile ` + -CertThumbprint $Global:Icinga.Public.SSL.CertThumbprint; + } else { + $Global:Icinga.Public.SSL.Certificate = Get-IcingaForWindowsCertificate; + } + } + + if ($null -ne $Global:Icinga.Public.SSL.Certificate) { break; } # Wait 5 minutes and try again - Write-IcingaEventMessage -EventId 2002 -Namespace 'RESTApi'; + Write-IcingaEventMessage -EventId 2002 -Namespace 'RESTApi' -Objects ($Global:Icinga.Public.SSL.Certificate | Out-String), $Global:Icinga.Public.SSL.CertFile, $Global:Icinga.Public.SSL.CertThumbprint; Start-Sleep -Seconds (60 * 5); } @@ -81,7 +95,7 @@ function New-IcingaForWindowsRESTApi() $Connection = Open-IcingaTCPClientConnection ` -Client (New-IcingaTCPClient -Socket $Socket) ` - -Certificate $Global:Icinga.Public.SSLCertificate; + -Certificate $Global:Icinga.Public.SSL.Certificate; if ($Connection.Client -eq $null -Or $Connection.Stream -eq $null) { Close-IcingaTCPConnection -Connection $Connection; diff --git a/lib/daemons/RestAPI/eventlog/Register-IcingaEventLogMessagesRESTApi.psm1 b/lib/daemons/RestAPI/eventlog/Register-IcingaEventLogMessagesRESTApi.psm1 index 7dc1744..9cde199 100644 --- a/lib/daemons/RestAPI/eventlog/Register-IcingaEventLogMessagesRESTApi.psm1 +++ b/lib/daemons/RestAPI/eventlog/Register-IcingaEventLogMessagesRESTApi.psm1 @@ -17,7 +17,7 @@ function Register-IcingaEventLogMessagesRESTApi() 2002 = @{ 'EntryType' = 'Warning'; 'Message' = 'Icinga for Windows certificate not ready'; - 'Details' = 'The Icinga for Windows REST-Api was not able to fetch the icingaforwindows.pfx certificate file. You can manually enforce the certificate creation by using the command "Start-IcingaWindowsScheduledTaskRenewCertificate". Once successful, this message should disappear and the REST-Api start. If the error persist, ensure your Icinga Agent certificate is configured properly and signed by your Icinga CA. This check is queued every 5 minutes and should vanish once everything works fine.'; + 'Details' = 'The Icinga for Windows REST-Api was not able to fetch the Icinga Agent or icingaforwindows.pfx certificate file. You can manually enforce the certificate creation of the icingaforwindows.pfx by using the command "Start-IcingaWindowsScheduledTaskRenewCertificate". Once successful, this message should disappear and the REST-Api start in case you are running inside a JEA-Context. If you are not using JEA, the Icinga Agent certificate has to be present and signed by the Icinga CA. You can test if a certificate is present by using "Get-IcingaSSLCertForSocket". This should return a certificate object with the subject "CN=", while "" should match your hostname or object name in Icinga. This check is queued every 5 minutes and should vanish once everything works fine.'; 'EventId' = 2002; }; 2003 = @{ diff --git a/lib/daemons/RestAPI/threads/New-IcingaForWindowsCertificateThreadTaskInstance.psm1 b/lib/daemons/RestAPI/threads/New-IcingaForWindowsCertificateThreadTaskInstance.psm1 index 665995e..58428ad 100644 --- a/lib/daemons/RestAPI/threads/New-IcingaForWindowsCertificateThreadTaskInstance.psm1 +++ b/lib/daemons/RestAPI/threads/New-IcingaForWindowsCertificateThreadTaskInstance.psm1 @@ -5,14 +5,24 @@ function New-IcingaForWindowsCertificateThreadTaskInstance() while ($TRUE) { # Check every 10 minutes if our certificate is present and update it in case it is # missing or updates have happened - $NewIcingaForWindowsCertificate = Get-IcingaForWindowsCertificate; + + # In case we are not inside a JEA context, use the SSLCertForSocket function to create the certificate file on the fly + # while maintaining the new wait feature. This fix is required, as the NetworkService user has no permssion + # to read the icingaforwindows.pfx file with the private key + if ([string]::IsNullOrEmpty((Get-IcingaJEAContext))) { + $NewIcingaForWindowsCertificate = Get-IcingaSSLCertForSocket ` + -CertFile $Global:Icinga.Public.SSL.CertFile ` + -CertThumbprint $Global:Icinga.Public.SSL.CertThumbprint; + } else { + $NewIcingaForWindowsCertificate = Get-IcingaForWindowsCertificate; + } if ($null -ne $NewIcingaForWindowsCertificate) { if ($NewIcingaForWindowsCertificate.Issuer.ToLower() -eq ([string]::Format('cn={0}', $IcingaHostname).ToLower())) { Write-IcingaEventMessage -EventId 1506 -Namespace 'Framework'; } else { - if ($Global:Icinga.Public.SSLCertificate.GetCertHashString() -ne $NewIcingaForWindowsCertificate.GetCertHashString()) { - $Global:Icinga.Public.SSLCertificate = $NewIcingaForWindowsCertificate; + if ($Global:Icinga.Public.SSL.Certificate.GetCertHashString() -ne $NewIcingaForWindowsCertificate.GetCertHashString()) { + $Global:Icinga.Public.SSL.Certificate = $NewIcingaForWindowsCertificate; Write-IcingaEventMessage -EventId 2004 -Namespace 'RESTApi'; } }