2020-11-10 05:02:16 -05:00
<#
. 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
#>
2019-09-29 12:25:40 -04:00
function Install-IcingaAgentCertificates ( )
{
param (
[ string ] $Hostname ,
[ string ] $Endpoint ,
[ int ] $Port = 5665 ,
[ string ] $CACert ,
[ string ] $Ticket ,
[ switch ] $Force = $FALSE
) ;
if ( [ string ] :: IsNullOrEmpty ( $Hostname ) ) {
2020-05-30 08:19:34 -04:00
Write-IcingaConsoleError 'Failed to install Icinga Agent certificates. Please provide a hostname' ;
return $FALSE ;
2019-09-29 12:25:40 -04:00
}
# 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 ) ) {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleNotice ( [ string ] :: Format ( 'Generating host certificates for host "{0}"' , $Hostname ) ) ;
2019-09-29 12:25:40 -04:00
$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 ) {
2020-05-30 08:19:34 -04:00
Write-IcingaConsoleError 'Failed to generate host certificate' ;
return $FALSE ;
2019-09-29 12:25:40 -04:00
}
2020-11-12 09:46:05 -05:00
# Once we generated new host certificates, we always require to sign them if possible
$Force = $TRUE ;
2019-09-29 12:25:40 -04:00
}
if ( [ string ] :: IsNullOrEmpty ( $Endpoint ) -And [ string ] :: IsNullOrEmpty ( $CACert ) ) {
2021-08-19 11:19:26 -04:00
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' ;
2020-05-30 08:19:34 -04:00
return $FALSE ;
2019-09-29 12:25:40 -04:00
}
if ( -Not [ string ] :: IsNullOrEmpty ( $Endpoint ) ) {
if ( -Not ( Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -TestTrustedParent -Force $Force ) ) {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleNotice ( [ string ] :: Format ( 'Fetching trusted master certificate from "{0}"' , $Endpoint ) ) ;
2019-09-29 12:25:40 -04:00
2020-04-28 07:48:15 -04:00
# Argument --key for save-cert is deprecated starting with Icinga 2.12.0
if ( Compare-IcingaVersions -RequiredVersion '2.12.0' ) {
2020-04-28 08:04:34 -04:00
$arguments = [ string ] :: Format ( 'pki save-cert --trustedcert {0}trusted-parent.crt --host {1} --port {2}' ,
2020-04-28 07:48:15 -04:00
$CertificateDirectory ,
2020-04-28 08:04:34 -04:00
$Endpoint ,
$Port
2020-04-28 07:48:15 -04:00
) ;
} else {
2020-04-28 08:04:34 -04:00
$arguments = [ string ] :: Format ( 'pki save-cert --key {0}{1}.key --trustedcert {0}trusted-parent.crt --host {2} --port {3}' ,
2020-04-28 07:48:15 -04:00
$CertificateDirectory ,
$Hostname ,
2020-04-28 08:04:34 -04:00
$Endpoint ,
$Port
2020-04-28 07:48:15 -04:00
) ;
}
2019-09-29 12:25:40 -04:00
if ( ( Start-IcingaAgentCertificateProcess -Arguments $arguments ) -eq $FALSE ) {
2022-01-14 16:18:59 -05:00
Write-IcingaConsoleError -Message 'Unable to connect to your provided Icinga CA. Please verify the entered configuration is correct.' `
2020-08-04 08:48:32 -04:00
'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.' ;
2020-05-30 08:19:34 -04:00
return $FALSE ;
2019-09-29 12:25:40 -04:00
}
}
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 ) {
2020-05-30 08:19:34 -04:00
Write-IcingaConsoleError 'Failed to sign Icinga certificate' ;
return $FALSE ;
2019-09-29 12:25:40 -04:00
}
if ( [ string ] :: IsNullOrEmpty ( $Ticket ) ) {
2020-05-13 10:53:15 -04:00
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"' ;
2019-09-29 12:25:40 -04:00
} else {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleNotice 'Icinga certificates successfully installed' ;
2019-09-29 12:25:40 -04:00
}
}
return $TRUE ;
} elseif ( -Not [ string ] :: IsNullOrEmpty ( $CACert ) ) {
2022-01-14 16:18:59 -05:00
if ( -Not ( Copy-IcingaAgentCACertificate -CAPath $CACert -Destination $CertificateDirectory ) ) {
2019-09-29 12:25:40 -04:00
return $FALSE ;
}
2020-05-13 10:53:15 -04:00
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"' ;
2019-09-29 12:25:40 -04:00
}
return $TRUE ;
}
function Start-IcingaAgentCertificateProcess ( )
{
param (
$Arguments
) ;
$Binary = Get-IcingaAgentBinary ;
$Process = Start-IcingaProcess -Executable $Binary -Arguments $Arguments ;
if ( $Process . ExitCode -ne 0 ) {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleError ( [ string ] :: Format ( 'Failed to create certificate.{0}Arguments: {1}{0}Error:{2} {3}' , " `r `n " , $Arguments , $Process . Message , $Process . Error ) ) ;
2019-09-29 12:25:40 -04:00
return $FALSE ;
}
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleNotice $Process . Message ;
2019-09-29 12:25:40 -04:00
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' ) ) {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleNotice 'Your ca.crt is present. No generation or fetching required' ;
2019-09-29 12:25:40 -04:00
return $TRUE ;
} else {
2022-01-14 16:18:59 -05:00
Write-IcingaConsoleWarning 'Your ca.crt is not present. Manually copy or fetching from your Icinga CA is required.' ;
2019-09-29 12:25:40 -04:00
return $FALSE ;
}
}
if ( $TestTrustedParent ) {
if ( Test-Path ( Join-Path -Path $CertDirectory -ChildPath 'trusted-parent.crt' ) ) {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleNotice 'Your trusted-parent.crt is present. No fetching or generation required' ;
2019-09-29 12:25:40 -04:00
return $TRUE ;
} else {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleWarning 'Your trusted master certificate is not present. Fetching from your CA server is required' ;
2019-09-29 12:25:40 -04:00
return $FALSE ;
}
}
if ( ( -Not ( Test-Path ( ( Join-Path -Path $CertDirectory -ChildPath $Hostname ) + '.key' ) ) ) `
2020-08-04 08:48:32 -04:00
-Or -Not ( Test-Path ( ( Join-Path -Path $CertDirectory -ChildPath $Hostname ) + '.crt' ) ) ) {
2019-09-29 12:25:40 -04:00
return $FALSE ;
}
2020-11-12 09:46:05 -05:00
[ string ] $hostCRT = [ string ] :: Format ( '{0}.crt' , $Hostname ) ;
[ string ] $hostKEY = [ string ] :: Format ( '{0}.key' , $Hostname ) ;
[ bool ] $CertNameInvalid = $FALSE ;
2019-09-29 12:25:40 -04:00
$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 ) ) {
2020-05-13 10:53:15 -04:00
Write-IcingaConsoleWarning ( [ string ] :: Format ( 'Certificate file {0} is not matching the hostname {1}. Certificate generation is required.' , $cert . Name , $Hostname ) ) ;
2020-11-12 09:46:05 -05:00
$CertNameInvalid = $TRUE ;
break ;
2019-09-29 12:25:40 -04:00
}
}
}
2020-11-12 09:46:05 -05:00
if ( $CertNameInvalid ) {
Remove-Item -Path ( Join-Path -Path $CertDirectory -ChildPath $hostCRT ) -Force ;
Remove-Item -Path ( Join-Path -Path $CertDirectory -ChildPath $hostKEY ) -Force ;
return $FALSE ;
}
2020-05-22 07:42:23 -04:00
Write-IcingaConsoleNotice 'Icinga host certificates are present and valid. No generation required' ;
2019-09-29 12:25:40 -04:00
return $TRUE ;
}
function Copy-IcingaAgentCACertificate ( )
{
param (
[ string ] $CAPath ,
2022-01-14 16:18:59 -05:00
[ string ] $Destination
2019-09-29 12:25:40 -04:00
) ;
# Copy ca.crt from local path or network share to certificate path
if ( ( Test-Path $CAPath ) ) {
2022-01-14 16:18:59 -05:00
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 ) ) ;
2019-09-29 12:25:40 -04:00
} else {
2020-07-31 04:20:53 -04:00
Set-IcingaTLSVersion ;
2022-01-14 16:18:59 -05:00
# It could also be a web resource
2019-09-29 12:25:40 -04:00
try {
2020-11-19 10:59:31 -05:00
$response = Invoke-IcingaWebRequest $CAPath -UseBasicParsing ;
2019-09-29 12:25:40 -04:00
[ int ] $Index = $response . RawContent . IndexOf ( " `r `n `r `n " ) + 4 ;
[ string ] $CAContent = $response . RawContent . SubString (
$Index ,
$response . RawContent . Length - $Index
) ;
2022-01-14 16:18:59 -05:00
Write-IcingaFileSecure -File ( Join-Path $Destination -ChildPath 'ca.crt' ) -Value $CAContent ;
Write-IcingaConsoleNotice ( [ string ] :: Format ( 'Downloaded ca.crt from "{0}" to "{1}' , $CAPath , $Destination ) )
2019-09-29 12:25:40 -04:00
} catch {
2022-01-14 16:18:59 -05:00
Write-IcingaConsoleError 'Failed to load any provided ca.crt resource' ;
2019-09-29 12:25:40 -04:00
return $FALSE ;
}
}
return $TRUE ;
}
Export-ModuleMember -Function @ ( 'Install-IcingaAgentCertificates' ) ;