Skip to content

Commit 6a4b067

Browse files
authored
Merge pull request #690 from Icinga:features/adds_api_certificate_renewal
Feature: Adds renewal handling for Icinga for Windows certificate Adds automatic renewal of the `icingaforwindows.pfx` certificate for the REST-Api daemon in case the certificate is not yet present, valid or changed during the runtime of the daemon while also making the `icingaforwindows.pfx` mandatory for all installations, regardless of JEA being used or not
2 parents c7eeab8 + 03e60d4 commit 6a4b067

11 files changed

+71
-28
lines changed

doc/100-General/10-Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
2323
* [#631](https://github.com/Icinga/icinga-powershell-framework/pull/631) Deduplicates `-C try { Use-Icinga ...` boilerplate by adding it to the `PowerShell Base` template and removing it from every single command
2424
* [#679](https://github.com/Icinga/icinga-powershell-framework/pull/679) Adds a new data provider for fetching process information of Windows systems, while sorting all objects based on a process name and their process id
2525
* [#688](https://github.com/Icinga/icinga-powershell-framework/pull/688) Adds new handling to add scheduled tasks in Windows for interacting with Icinga for Windows core functionality as well as an auto renewal task for the Icinga for Windows certificate generation
26+
* [#690](https://github.com/Icinga/icinga-powershell-framework/pull/690) Adds automatic renewal of the `icingaforwindows.pfx` certificate for the REST-Api daemon in case the certificate is not yet present, valid or changed during the runtime of the daemon while also making the `icingaforwindows.pfx` mandatory for all installations, regardless of JEA being used or not
2627

2728
## 1.11.2 (tbd)
2829

lib/core/framework/Invoke-IcingaForWindowsMigration.psm1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ function Invoke-IcingaForWindowsMigration()
9595

9696
# Add a new scheduled task to automatically renew the Icinga for Windows certificate
9797
Register-IcingaWindowsScheduledTaskRenewCertificate -Force;
98+
# Start the task to ensure the certificate is generated
99+
Start-IcingaWindowsScheduledTaskRenewCertificate;
98100

99101
Set-IcingaForWindowsMigration -MigrationVersion (New-IcingaVersionObject -Version '1.12.0');
100102
}

lib/core/installer/Start-IcingaForWindowsInstallation.psm1

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,9 @@ function Start-IcingaForWindowsInstallation()
312312
};
313313
}
314314

315-
# Install Icinga for Windows certificate if both, JEA and REST is installed
316-
if ($InstallJEA -And $InstallRESTApi) {
317-
Install-IcingaForWindowsCertificate;
318-
Restart-IcingaWindowsService;
319-
}
315+
# Always install the Icinga for Windows certificate
316+
Install-IcingaForWindowsCertificate;
317+
Restart-IcingaWindowsService;
320318

321319
# Update configuration and clear swap
322320
$ConfigSwap = Get-IcingaPowerShellConfig -Path 'Framework.Config.Swap';

lib/core/installer/menu/manage/framework/ToogleFrameworkApiChecks.psm1

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ function Invoke-IcingaForWindowsManagementConsoleToggleFrameworkApiChecks()
77
Register-IcingaBackgroundDaemon -Command 'Start-IcingaWindowsRESTApi';
88
Add-IcingaRESTApiCommand -Command 'Invoke-IcingaCheck*' -Endpoint 'apichecks';
99
}
10-
if ([string]::IsNullOrEmpty((Get-IcingaJEAContext)) -eq $FALSE) {
11-
Install-IcingaForWindowsCertificate;
12-
}
1310

11+
Install-IcingaForWindowsCertificate;
1412
Enable-IcingaFrameworkApiChecks;
1513
}
1614

lib/core/jea/Install-IcingaJeaProfile.psm1

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ function Install-IcingaJEAProfile()
2626
Write-IcingaJEAProfile -RebuildFramework:$RebuildFramework -AllowScriptBlocks:$AllowScriptBlocks;
2727
Write-IcingaConsoleNotice 'Registering Icinga for Windows JEA profile'
2828
Register-IcingaJEAProfile -IcingaUser $IcingaUser -TestEnv:$TestEnv -ConstrainedLanguage:$ConstrainedLanguage;
29-
30-
if ((Get-IcingaBackgroundDaemons).ContainsKey('Start-IcingaWindowsRESTApi')) {
31-
Install-IcingaForWindowsCertificate;
32-
}
29+
Install-IcingaForWindowsCertificate;
3330
}
3431

3532
Set-Alias -Name 'Update-IcingaJEAProfile' -Value 'Install-IcingaJEAProfile';

lib/core/wintasks/daemon/Register-TaskRenewCertificate.psm1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function Register-IcingaWindowsScheduledTaskRenewCertificate()
2020
$TaskPrincipal = New-ScheduledTaskPrincipal -GroupId 'S-1-5-32-544' -RunLevel 'Highest';
2121
$TaskSettings = New-ScheduledTaskSettingsSet -DontStopIfGoingOnBatteries -AllowStartIfOnBatteries -StartWhenAvailable;
2222

23-
Register-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -Force -Principal $TaskPrincipal -Action $TaskAction -Trigger $TaskTrigger -Settings $TaskSettings;
23+
Register-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -Force -Principal $TaskPrincipal -Action $TaskAction -Trigger $TaskTrigger -Settings $TaskSettings | Out-Null;
2424

25-
Write-IcingaConsoleWarning -Message 'The task "{0}" has been successfully registered at location "{1}".' -Objects $TaskName, $TaskPath;
25+
Write-IcingaConsoleNotice -Message 'The task "{0}" has been successfully registered at location "{1}".' -Objects $TaskName, $TaskPath;
2626
}

lib/daemon/Start-IcingaPowerShellDaemon.psm1

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ function Start-IcingaForWindowsDaemon()
3939
Add-IcingaThreadPool -Name 'MainPool' -MaxInstances 20;
4040
$Global:Icinga.Public.Add('SSLCertificate', $Certificate);
4141

42-
4342
New-IcingaThreadInstance -Name "Main" -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') -Command 'Add-IcingaForWindowsDaemon' -Start;
4443
} else {
4544
Write-IcingaDebugMessage -Message 'Starting Icinga for Windows service inside JEA context' -Objects $RunAsService, $JEARestart, $JeaProfile;

lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,20 @@ function New-IcingaForWindowsRESTApi()
5454

5555
Write-IcingaDebugMessage -Message ($Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints | Out-String);
5656

57-
if ($Global:Icinga.Protected.JEAContext) {
58-
if ($Global:Icinga.Public.ContainsKey('SSLCertificate') -eq $FALSE -Or $null -eq $Global:Icinga.Public.SSLCertificate) {
59-
Write-IcingaEventMessage -EventId 2001 -Namespace 'RESTApi';
60-
return;
57+
while ($TRUE) {
58+
if ($null -eq $Global:Icinga.Public.SSLCertificate) {
59+
$Global:Icinga.Public.SSLCertificate = (Get-IcingaForWindowsCertificate);
60+
} else {
61+
break;
6162
}
6263

63-
$Certificate = $Global:Icinga.Public.SSLCertificate;
64-
} else {
65-
$Certificate = Get-IcingaSSLCertForSocket -CertFile $CertFile -CertThumbprint $CertThumbprint;
64+
# Wait 5 minutes and try again
65+
Write-IcingaEventMessage -EventId 2002 -Namespace 'RESTApi';
66+
Start-Sleep -Seconds (60 * 5);
6667
}
6768

68-
if ($null -eq $Certificate) {
69-
Write-IcingaEventMessage -EventId 2000 -Namespace 'RESTApi';
70-
return;
71-
}
69+
# Create a background thread to renew the certificate on a regular basis
70+
Start-IcingaForWindowsCertificateThreadTask;
7271

7372
$Socket = New-IcingaTCPSocket -Address $Address -Port $Port -Start;
7473

@@ -82,7 +81,7 @@ function New-IcingaForWindowsRESTApi()
8281

8382
$Connection = Open-IcingaTCPClientConnection `
8483
-Client (New-IcingaTCPClient -Socket $Socket) `
85-
-Certificate $Certificate;
84+
-Certificate $Global:Icinga.Public.SSLCertificate;
8685

8786
if ($Connection.Client -eq $null -Or $Connection.Stream -eq $null) {
8887
Close-IcingaTCPConnection -Connection $Connection;

lib/daemons/RestAPI/eventlog/Register-IcingaEventLogMessagesRESTApi.psm1

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,27 @@ function Register-IcingaEventLogMessagesRESTApi()
1111
2001 = @{
1212
'EntryType' = 'Error';
1313
'Message' = 'Failed to start REST-Api daemon in JEA context';
14-
'Details' = 'Icinga for Windows is being used inside a JEA context as service with the REST-Api daemon. To establish a secure TLS socket, it is required to create certificates in advance for the socket to bind on with "Install-IcingaForWindowsCertificate". The REST-Api daemon will now exit.';
14+
'Details' = 'Icinga for Windows is being used inside a JEA context as service with the REST-Api daemon. To establish a secure TLS socket, it is required to create certificates in advance for the socket to bind on with "Start-IcingaWindowsScheduledTaskRenewCertificate". The REST-Api daemon will now exit.';
1515
'EventId' = 2001;
1616
};
17+
2002 = @{
18+
'EntryType' = 'Warning';
19+
'Message' = 'Icinga for Windows certificate not ready';
20+
'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.';
21+
'EventId' = 2002;
22+
};
23+
2003 = @{
24+
'EntryType' = 'Warning';
25+
'Message' = 'Icinga for Windows certificate was not found';
26+
'Details' = 'The Icinga for Windows "icingaforwindows.pfx" file was not found on the system while the REST-Api is running. Please ensure the certificate is created shortly, as the daemon will no longer work once it will be restarted or the certificate is due for renewal. Please run "Start-IcingaWindowsScheduledTaskRenewCertificate" to re-create the certificate on your machine.'
27+
'EventId' = 2003;
28+
};
29+
2004 = @{
30+
'EntryType' = 'Information';
31+
'Message' = 'Icinga for Windows certificate was renewed';
32+
'Details' = 'The Icinga for Windows certificate has been modified and was updated inside the Icinga for Windows REST-Api daemon.'
33+
'EventId' = 2004;
34+
};
1735
2050 = @{
1836
'EntryType' = 'Error';
1937
'Message' = 'Failed to parse received REST-Api call';
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function New-IcingaForWindowsCertificateThreadTaskInstance()
2+
{
3+
$IcingaHostname = Get-IcingaHostname -ReadConstants;
4+
5+
while ($TRUE) {
6+
# Check every 10 minutes if our certificate is present and update it in case it is
7+
# missing or updates have happened
8+
$NewIcingaForWindowsCertificate = Get-IcingaForWindowsCertificate;
9+
10+
if ($null -ne $NewIcingaForWindowsCertificate) {
11+
if ($NewIcingaForWindowsCertificate.Issuer.ToLower() -eq ([string]::Format('cn={0}', $IcingaHostname).ToLower())) {
12+
Write-IcingaEventMessage -EventId 1506 -Namespace 'Framework';
13+
} else {
14+
if ($Global:Icinga.Public.SSLCertificate.GetCertHashString() -ne $NewIcingaForWindowsCertificate.GetCertHashString()) {
15+
$Global:Icinga.Public.SSLCertificate = $NewIcingaForWindowsCertificate;
16+
Write-IcingaEventMessage -EventId 2004 -Namespace 'RESTApi';
17+
}
18+
}
19+
}
20+
21+
Start-Sleep -Seconds (60 * 10);
22+
}
23+
}

0 commit comments

Comments
 (0)