mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-21 15:19:58 -05:00
Disabling UseConsistentIndentation because it is not properly working for multi-line commands with arguments and array/hashtable objects
293 lines
12 KiB
PowerShell
293 lines
12 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Installs the required certificates for the Icinga Agent including the entire
|
|
signing process either by using the CA-Proxy, the CA-Server directly or
|
|
by manually signing the request on the CA master
|
|
.DESCRIPTION
|
|
Installs the required certificates for the Icinga Agent including the entire
|
|
signing process either by using the CA-Proxy, the CA-Server directly or
|
|
by manually signing the request on the CA master
|
|
.FUNCTIONALITY
|
|
Creates, installs and signs required certificates for the Icinga Agent
|
|
.EXAMPLE
|
|
# Connect to the CA server with a ticket to fully complete the request
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -Endpoint 'icinga2.example.com' -Ticket 'my_secret_ticket';
|
|
.EXAMPLE
|
|
# Connect to the CA server without a ticket, to create the sign request on the master
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -Endpoint 'icinga2.example.com';
|
|
.EXAMPLE
|
|
# Uses the Icinga ca.crt from a local filesystem and prepares the Icinga Agent for receiving connections from the Master/Satellite for signing
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -CACert 'C:\users\public\icinga2\ca.crt';
|
|
.EXAMPLE
|
|
# Uses the Icinga ca.crt from a web resource and prepares the Icinga Agent for receiving connections from the Master/Satellite for signing
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -CACert 'https://example.com/icinga2/ca.crt';
|
|
.PARAMETER Hostname
|
|
The hostname of the local system. Has to match the object name within the Icinga configuration
|
|
.PARAMETER Endpoint
|
|
The address of either the Icinga CA master or a parent node of the Agent to transmit the request to the CA master
|
|
.PARAMETER Port
|
|
The port used for Icinga communication. Uses 5665 as default
|
|
.PARAMETER CACert
|
|
Allows to specify the path to the ca.crt from the Icinga CA master on a local, network or web share to allow certificate generation
|
|
in case the Icinga Agent is not able to connect to it's parent hosts
|
|
.PARAMETER Ticket
|
|
The ticket number for the signing request which is either generated by Icinga 2 or the Icinga Director
|
|
.PARAMETER Force
|
|
Ignores existing certificates and will force the creation, overriding existing certificates
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Install-IcingaAgentCertificates()
|
|
{
|
|
param(
|
|
[string]$Hostname,
|
|
[string]$Endpoint,
|
|
[int]$Port = 5665,
|
|
[string]$CACert,
|
|
[string]$Ticket,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Hostname)) {
|
|
Write-IcingaConsoleError 'Failed to install Icinga Agent certificates. Please provide a hostname';
|
|
return $FALSE;
|
|
}
|
|
|
|
# Default for Icinga 2.8.0 and above
|
|
[string]$NewCertificateDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\var\lib\icinga2\certs\');
|
|
[string]$OldCertificateDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\etc\icinga2\pki\');
|
|
[string]$CertificateDirectory = $NewCertificateDirectory;
|
|
if ((Compare-IcingaVersions -RequiredVersion '2.8.0') -eq $FALSE) {
|
|
# Certificate path for versions older than 2.8.0
|
|
$CertificateDirectory = $OldCertificateDirectory;
|
|
Move-IcingaAgentCertificates -Source $NewCertificateDirectory -Destination $OldCertificateDirectory;
|
|
} else {
|
|
Move-IcingaAgentCertificates -Source $OldCertificateDirectory -Destination $NewCertificateDirectory;
|
|
}
|
|
|
|
if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -Force $Force)) {
|
|
Write-IcingaConsoleNotice ([string]::Format('Generating host certificates for host "{0}"', $Hostname));
|
|
|
|
$arguments = [string]::Format('pki new-cert --cn {0} --key {1}{0}.key --cert {1}{0}.crt',
|
|
$Hostname,
|
|
$CertificateDirectory
|
|
);
|
|
|
|
if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Failed to generate host certificate';
|
|
return $FALSE;
|
|
}
|
|
|
|
# Once we generated new host certificates, we always require to sign them if possible
|
|
$Force = $TRUE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Endpoint) -And [string]::IsNullOrEmpty($CACert)) {
|
|
Write-IcingaConsoleWarning 'Your host certificates were generated successfully. Please either specify an endpoint to connect to or provide the path to a valid ca.crt';
|
|
return $FALSE;
|
|
}
|
|
|
|
if (-Not [string]::IsNullOrEmpty($Endpoint)) {
|
|
if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -TestTrustedParent -Force $Force)) {
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Fetching trusted master certificate from "{0}"', $Endpoint));
|
|
|
|
# Argument --key for save-cert is deprecated starting with Icinga 2.12.0
|
|
if (Compare-IcingaVersions -RequiredVersion '2.12.0') {
|
|
$arguments = [string]::Format('pki save-cert --trustedcert {0}trusted-parent.crt --host {1} --port {2}',
|
|
$CertificateDirectory,
|
|
$Endpoint,
|
|
$Port
|
|
);
|
|
} else {
|
|
$arguments = [string]::Format('pki save-cert --key {0}{1}.key --trustedcert {0}trusted-parent.crt --host {2} --port {3}',
|
|
$CertificateDirectory,
|
|
$Hostname,
|
|
$Endpoint,
|
|
$Port
|
|
);
|
|
}
|
|
|
|
if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) {
|
|
Write-IcingaConsoleError -Message 'Unable to connect to your provided Icinga CA. Please verify the entered configuration is correct.' `
|
|
'If you are not able to connect to your Icinga CA from this machine, you will have to provide the path' `
|
|
'to your Icinga ca.crt and use the CA-Proxy certificate handling.';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -TestCACert -Force $Force)) {
|
|
[string]$PKIRequest = 'pki request --host {0} --port {1} --ticket {4} --key {2}{3}.key --cert {2}{3}.crt --trustedcert {2}trusted-parent.crt --ca {2}ca.crt';
|
|
|
|
if ([string]::IsNullOrEmpty($Ticket)) {
|
|
$PKIRequest = 'pki request --host {0} --port {1} --key {2}{3}.key --cert {2}{3}.crt --trustedcert {2}trusted-parent.crt --ca {2}ca.crt';
|
|
}
|
|
|
|
$arguments = [string]::Format($PKIRequest,
|
|
$Endpoint,
|
|
$Port,
|
|
$CertificateDirectory,
|
|
$Hostname,
|
|
$Ticket
|
|
);
|
|
|
|
if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Failed to sign Icinga certificate';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Ticket)) {
|
|
Write-IcingaConsoleNotice 'Your certificates were generated successfully. Please sign the certificate now on your Icinga CA master. You can lookup open requests with "icinga2 ca list"';
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Icinga certificates successfully installed';
|
|
}
|
|
}
|
|
|
|
return $TRUE;
|
|
} elseif (-Not [string]::IsNullOrEmpty($CACert)) {
|
|
if (-Not (Copy-IcingaAgentCACertificate -CAPath $CACert -Destination $CertificateDirectory)) {
|
|
return $FALSE;
|
|
}
|
|
Write-IcingaConsoleNotice 'Host-Certificates and ca.crt are present. Please start your Icinga Agent now and manually sign your certificate request on your CA master. You can lookup open requests with "icinga2 ca list"';
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Start-IcingaAgentCertificateProcess()
|
|
{
|
|
param(
|
|
$Arguments
|
|
);
|
|
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$Process = Start-IcingaProcess -Executable $Binary -Arguments $Arguments;
|
|
|
|
if ($Process.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to create certificate.{0}Arguments: {1}{0}Error:{2} {3}', "`r`n", $Arguments, $Process.Message, $Process.Error));
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice $Process.Message;
|
|
return $TRUE;
|
|
}
|
|
|
|
function Move-IcingaAgentCertificates()
|
|
{
|
|
param(
|
|
[string]$Source,
|
|
[string]$Destination
|
|
);
|
|
|
|
$SourceDir = Join-Path -Path $Source -ChildPath '\*';
|
|
$TargetDir = Join-Path -Path $Destination -ChildPath '\';
|
|
|
|
Move-Item -Path $SourceDir -Destination $TargetDir;
|
|
}
|
|
|
|
function Test-IcingaAgentCertificates()
|
|
{
|
|
param(
|
|
[string]$CertDirectory,
|
|
[string]$Hostname,
|
|
[switch]$TestCACert,
|
|
[switch]$TestTrustedParent,
|
|
[bool]$Force
|
|
);
|
|
|
|
if ($Force) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($TestCACert) {
|
|
if (Test-Path (Join-Path -Path $CertDirectory -ChildPath 'ca.crt')) {
|
|
Write-IcingaConsoleNotice 'Your ca.crt is present. No generation or fetching required';
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleWarning 'Your ca.crt is not present. Manually copy or fetching from your Icinga CA is required.';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
if ($TestTrustedParent) {
|
|
if (Test-Path (Join-Path -Path $CertDirectory -ChildPath 'trusted-parent.crt')) {
|
|
Write-IcingaConsoleNotice 'Your trusted-parent.crt is present. No fetching or generation required';
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleWarning 'Your trusted master certificate is not present. Fetching from your CA server is required';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
if ((-Not (Test-Path ((Join-Path -Path $CertDirectory -ChildPath $Hostname) + '.key'))) `
|
|
-Or -Not (Test-Path ((Join-Path -Path $CertDirectory -ChildPath $Hostname) + '.crt'))) {
|
|
return $FALSE;
|
|
}
|
|
|
|
[string]$hostCRT = [string]::Format('{0}.crt', $Hostname);
|
|
[string]$hostKEY = [string]::Format('{0}.key', $Hostname);
|
|
[bool]$CertNameInvalid = $FALSE;
|
|
|
|
$certificates = Get-ChildItem -Path $CertDirectory;
|
|
# Now loop each file and match their name with our hostname
|
|
foreach ($cert in $certificates) {
|
|
if ($cert.Name.toLower() -eq $hostCRT.toLower() -Or $cert.Name.toLower() -eq $hostKEY.toLower()) {
|
|
$file = $cert.Name.Replace('.key', '').Replace('.crt', '');
|
|
if (-Not ($file -clike $Hostname)) {
|
|
Write-IcingaConsoleWarning ([string]::Format('Certificate file {0} is not matching the hostname {1}. Certificate generation is required.', $cert.Name, $Hostname));
|
|
$CertNameInvalid = $TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($CertNameInvalid) {
|
|
Remove-Item -Path (Join-Path -Path $CertDirectory -ChildPath $hostCRT) -Force;
|
|
Remove-Item -Path (Join-Path -Path $CertDirectory -ChildPath $hostKEY) -Force;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Icinga host certificates are present and valid. No generation required';
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Copy-IcingaAgentCACertificate()
|
|
{
|
|
param(
|
|
[string]$CAPath,
|
|
[string]$Destination
|
|
);
|
|
|
|
# Copy ca.crt from local path or network share to certificate path
|
|
if ((Test-Path $CAPath)) {
|
|
Copy-Item -Path $CAPath -Destination (Join-Path -Path $Destination -ChildPath 'ca.crt') | Out-Null;
|
|
Write-IcingaConsoleNotice ([string]::Format('Copied ca.crt from "{0}" to "{1}', $CAPath, $Destination));
|
|
} else {
|
|
Set-IcingaTLSVersion;
|
|
# It could also be a web resource
|
|
try {
|
|
$response = Invoke-IcingaWebRequest $CAPath -UseBasicParsing;
|
|
[int]$Index = $response.RawContent.IndexOf("`r`n`r`n") + 4;
|
|
|
|
[string]$CAContent = $response.RawContent.SubString(
|
|
$Index,
|
|
$response.RawContent.Length - $Index
|
|
);
|
|
Write-IcingaFileSecure -File (Join-Path $Destination -ChildPath 'ca.crt') -Value $CAContent;
|
|
Write-IcingaConsoleNotice ([string]::Format('Downloaded ca.crt from "{0}" to "{1}', $CAPath, $Destination))
|
|
} catch {
|
|
Write-IcingaConsoleError 'Failed to load any provided ca.crt resource';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
Export-ModuleMember -Function @('Install-IcingaAgentCertificates');
|