Einleitung
Eine AD- integrierte PKI (Public Key Infrastructure) ist heutzutage innerhalb eines Unternehmens nicht mehr wegzudenken. So sehr eine PKI die Arbeit in der täglichen Administration erleichtert, fällt es dennoch schwer, die vielen Zertifikate allgemein im Überblick zu behalten.
Speziell erläutere ich in diesem Beitrag, die Möglichkeit, die auslaufenden Zertifikate rechtzeitig zu ermitteln und bei Bedarf eine automatische E-Mail zu versenden. Optimalerweise ist der Empfänger solch einer wichtigen E-Mail, stets ein Funktionsverteiler mit mehreren Empfängern. Somit ist gewährleistet, dass rechtzeitig alle betreffenden Administratoren informiert werden!
Voraussetzungen
- Lokal angemeldete Sitzung auf dem betreffenden Windows PKI Server.
- Der Windows PKI Server muss über den Exchange Server E-Mails versenden dürfen (Relay)
- Administrativ geöffnete PowerShell ISE
Prüfen
Zur eigentlichen Ermittlung der ablaufenden Zertifikate, nutzt zuvor die dafür vorgesehenen PowerShell Befehlszeilen:
# Certificate Authority Server $CAserver = Get-CertificationAuthority "FQDN" # servername.domain.tld # Certificate Authority - expiring requests $expDays = 30 $expRequests = $CAserver | Get-IssuedRequest -Filter "NotAfter -ge $(Get-Date)", ` "NotAfter -le $((Get-Date).AddDays($expDays))" $result = $expRequests | Select-Object RequestID, Request.RequesterName, ` CommonName, NotAfter $result
Funktioniert dieser Befehl auf der entsprechenden Windows PKI (CA- Server), dann kann nun mit der Automatisierung begonnen werden. Der Wert $expDays kann natürlich an die eigenen Bedürfnisse angepasst werden. Sollte das Skript zwar funktionieren (keine Fehlermeldungen erzeugen), aber keine Ergebnisse angezeigt werden, dann den Wert $expDays entsprechend erhöhen, z.B. auf 60, 90 oder 365 Tage.
Skript
Wie bereits eingangs erwähnt, ist das Ziel, die zusammengetragenen Informationen automatisiert per E-Mail zu versenden. Damit die Ergebnisse in ansehnlicher Form versendet und dargestellt werden können, eignet sich die Konvertierung der Ergebnisse in das HTML- Format. Anschließend ist noch die E-Mail- Funktionalität herzustellen.
Werden nun die erforderlichen PowerShell Befehlszeilen kombiniert, dann kommt ungefähr das folgende Ergebnis dabei heraus:
<# .SYNOPSIS Detect expiring certificates on a Windows Certificate Authority server. .DESCRIPTION The script detect expiring certificates, convert the result to HTML and send the result via E-Mail. .COMPONENT PSPKI-Module .OUTPUTS E-Mail Report. .NOTES Version: 1.0 Author: André Stuhr Creation Date: 01/20/2022 Purpose/Change: First initial script development #> Clear-Host # Create a SMTP Server Object $mailserver = "FQDN" # servername.domain.tld $port = 587 # or Port 25 $smtp = New-Object System.Net.Mail.SMTPClient $mailserver, $port $smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials # Definition of Certificate Authority Server $CAserver = Get-CertificationAuthority "FQDN" # servername.domain.tld # Certificate Authority - get expiring certification requests and convert to html $expDays = 30 # change it, if needed $expRequests = $CAserver | Get-IssuedRequest -Filter ` "NotAfter -ge $(Get-Date)", ` "NotAfter -le $((Get-Date).AddDays($expDays))" $result = $expRequests | Select-Object ` RequestID, ` Request.RequesterName, ` CommonName, ` NotAfter ` | ConvertTo-Html -Head $style # Send E-Mails, if expiring certificates detected if ($result -gt $expRequests) { exit } else { # E-Mail parameter settings $smtpto = "<Recipient>" $smtpfrom = "Certificate Authority <sender>" # e.g service@domain.tld $subject = "Expiring certificate requests within the next $expDays days" $message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto $message.Subject = $messageSubject $message.IsBodyHTML = $true # HTML parameter settings $style = "<style>BODY{font-family: Arial; font-size: 10pt;}" $style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}" $style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }" $style = $style + "TD{border: 1px solid black; padding: 5px; }" $style = $style + "</style>" # Create the message $mail = New-Object System.Net.Mail.Mailmessage $smtpfrom, $smtpto, $subject, $result $mail.IsBodyHTML=$true # Send the message $smtp.send($mail) }
Die if, else- Bedingung soll sicherstellen, dass E-Mails NUR versendet werden, wenn auch entsprechend Zertifikate im vordefinierten Zeitraum ablaufen. Laufen somit keine E-Mails im vordefinierten Zeitraum ab, wird auch keinerlei E-Mail versendet!
Speichert das Skript lokal in einem geeigneten Verzeichnis ab, der Name der Datei kann hierbei frei gewählt werden! Nun ist es aus der PowerShell ISE heraus bereits möglich, das Skript 1x vollständig ablaufen zu lassen und somit die vollständige Funktionalität testen zu können… treten in der Ausführung Fehler auf, müssen diese anschließend analysiert und das Skript korrigiert werden!
Denkt hierbei bitte unbedingt an die Anpassung der erforderlichen Variablen:
- $mailserver
- $port
- $CAserver
- $expDays
- $smtpto
- $smtpfrom
Optionale Anpassungen von Variablen:
- $expDays
- $subject
- $style
Automatisierung
Ist das Skript lokal gespeichert, kann nun mit der Windows Aufgabenplanung fortgefahren werden. Hierzu erstellt eine neue Aufgabe.
Wie in diesem Beispiel:
Hierfür eignet sich ein Group Managed Service Account (gMSA). Wie solch ein Account grundsätzlich eingerichtet werden kann, habe ich bereits in einem anderen Beitrag berichtet. Nutzt hierzu am besten die Webseitensuche (Suchbegriff= gmsa).
Aktionen setzen
Aktion: | Programm starten |
Programm/Skript: | %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe |
Argumente hinzufügen: | -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -command "&{C:\scripts\ca\Get-ExpiringCertificates.ps1}" |
Ohne diese hinterlegten Informationen, funktioniert die Ausführung der Aufgabe in der Aufgabenplanung nicht erfolgreich. Ändert bitte noch den Pfad und Dateinamen zur Skriptdatei in dem hinterlegten Argument.
Ergebnis (Beispiel)
So oder so ähnlich sieht nach einer erfolgreichen Ausführung der Aufgabe, die eingehende E-Mail aus!
Schlusswort
Nun sollte es eigentlich nicht mehr allzu schwer sein, die ablaufenden Zertifikate zu erkennen und rechtzeitige Maßnahmen einzuleiten. Damit nicht so wie oft, der Ausfall eines Dienstes in der Infrastruktur hingenommen werden muss!
UPDATE 27.05.2022
Inzwischen ist mir die Ausgabe etwas zu dünn und daher habe ich das Skript heute etwas angepasst, an meine veränderten Bedürfnisse. Die Anpassung des Skripts, liest mir nun zusätzlich auch den Zertifikatstyp mit aus! Der Hintergrund liegt darin, dass ich erkennen will, welche „Zertifikatsvorlage“ hinter einem ablaufenden Zertifikat sich verbirgt.
Jedoch ist Vorarbeit notwendig, wenn manuell weitere Zertifikatsvorlagen in der Zertifizierungsstelle erstellt worden sind… denn nur die per Default erstellten Zertifikatsvorlagen werden korrekt ausgewertet und dargestellt. ALLE manuell hinzugefügten Zertifikatsvorlagen werden mit einer eindeutigen Objektkennung ausgegeben und sind somit eher schwer lesbar bzw. nicht zu gebrauchen!
Vorbereitungen
Es ist wichtig, die Objektkennung zu ermitteln. Hierzu startet kurz die certsrv- Konsole und unter den bereits „Ausgestellten Zertifikaten“ ermittelt die entsprechende Zertifikatsvorlage. Ist die Objektkennung ermittelt, reicht es aus, den letzten Abschnitt hinter dem Punkt herzunehmen, um die Auswertung durchzuführen.
Code-Anpassung
$result = $expRequests | Select-Object ` RequestID, ` Request.RequesterName, ` CommonName, ` @{Label="CertificateTemplate";Expression= { if ($_.CertificateTemplate -like '*.5739767') {"Remote Desktop Computer"} elseif ($_.CertificateTemplate -like '*.9109801') {"Webserver 3Y"} elseif ($_.CertificateTemplate -like '*.12911390') {"Webserver 5Y"} else {$_.CertificateTemplate}}},` NotAfter ` | ConvertTo-Html -Head $style
In dem Codebeispiel will ich zeigen, wie es möglich ist, mehr als eine Auswertung durchzuführen, falls eine x- Anzahl an manuell erstellten Zertifikatsvorlagen vorliegen. Sind alle manuell erstellten Zertifikatsvorlagen im Code erfasst, steigt der Code mit der else- Bedingung aus. Die else- Bedingung gibt in diesem Fall den eigentlichen Wert der Default- erstellten Zertifikatsvorlagen aus!
Modifiziertes Skript
<# .SYNOPSIS Detect expiring certificates on a Windows Certificate Authority server. .DESCRIPTION The script detect expiring certificates, convert the result to HTML and send the result via E-Mail. .COMPONENT PSPKI-Module .OUTPUTS E-Mail Report. .NOTES Version: 1.1 Author: André Stuhr Creation Date: 01/20/2022 Purpose/Change: First initial script development Change: 05/27/2022 - Add CertificateTemplate result #> Clear-Host # Create a SMTP Server Object $mailserver = "FQDN" # servername.domain.tld $port = 587 # or Port 25 $smtp = New-Object System.Net.Mail.SMTPClient $mailserver, $port $smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials # Definition of Certificate Authority Server $CAserver = Get-CertificationAuthority "FQDN" # servername.domain.tld # Certificate Authority - get expiring certification requests and convert to html $expDays = 30 # change it, if needed $expRequests = $CAserver | Get-IssuedRequest -Filter ` "NotAfter -ge $(Get-Date)", ` "NotAfter -le $((Get-Date).AddDays($expDays))" $result = $expRequests | Select-Object ` RequestID, ` Request.RequesterName, ` CommonName, ` @{Label="CertificateTemplate";Expression= { if ($_.CertificateTemplate -like '*.5739767') {"Remote Desktop Computer"} elseif ($_.CertificateTemplate -like '*.9109801') {"Webserver 3Y"} elseif ($_.CertificateTemplate -like '*.12911390') {"Webserver 5Y"} else {$_.CertificateTemplate}}},` NotAfter ` | ConvertTo-Html -Head $style # Send E-Mails, if expiring certificates detected if ($result -gt $expRequests) { exit } else { # E-Mail parameter settings $smtpto = "<Recipient>" $smtpfrom = "Certificate Authority <sender>" # e.g service@domain.tld $subject = "Expiring certificate requests within the next $expDays days" $message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto $message.Subject = $messageSubject $message.IsBodyHTML = $true # HTML parameter settings $style = "<style>BODY{font-family: Arial; font-size: 10pt;}" $style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}" $style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }" $style = $style + "TD{border: 1px solid black; padding: 5px; }" $style = $style + "</style>" # Create the message $mail = New-Object System.Net.Mail.Mailmessage $smtpfrom, $smtpto, $subject, $result $mail.IsBodyHTML=$true # Send the message $smtp.send($mail) }