71 lines
2.9 KiB
PowerShell
71 lines
2.9 KiB
PowerShell
<#
|
|||
|
|
.SYNOPSIS
|
||
|
|
Exports the PESCO internal CA certificates from this PC's Windows certificate stores
|
||
|
|
to a PEM bundle and copies it to docker-1 for the Packet Station stacks.
|
||
|
|
|
||
|
|
.DESCRIPTION
|
||
|
|
Run on a domain-joined PC. It reads the LocalMachine and CurrentUser Root and CA stores,
|
||
|
|
keeps every unexpired certificate whose subject matches -SubjectMatch (default PESCO),
|
||
|
|
writes them as one PEM file with a comment line per certificate, and copies the file to
|
||
|
|
the remote path with scp. The file holds public certificates only; nothing secret.
|
||
|
|
|
||
|
|
The stacks point LDAP_CA_BUNDLE and SMTP_CA_BUNDLE at this file. MFILES_CA_BUNDLE stays
|
||
|
|
unset because M-Files uses a public certificate.
|
||
|
|
|
||
|
|
.EXAMPLE
|
||
|
|
.\scripts\Export-PescoCaBundle.ps1
|
||
|
|
Writes the bundle and copies it to [email protected]:~/packetstation/test/ca/pesco-ca.pem
|
||
|
|
|
||
|
|
.EXAMPLE
|
||
|
|
.\scripts\Export-PescoCaBundle.ps1 -Remote '[email protected]:/etc/packetstation/ca/pesco-ca.pem'
|
||
|
|
|
||
|
|
.EXAMPLE
|
||
|
|
.\scripts\Export-PescoCaBundle.ps1 -NoCopy -OutFile C:\temp\pesco-ca.pem
|
||
|
|
#>
|
||
|
|
[CmdletBinding()]
|
||
|
|
param(
|
||
|
|
# Regex matched against each certificate subject.
|
||
|
|
[string]$SubjectMatch = 'PESCO',
|
||
|
|
# Local PEM file to write.
|
||
|
|
[string]$OutFile = (Join-Path $env:TEMP 'pesco-ca.pem'),
|
||
|
|
# scp destination. Needs an SSH key that works without a prompt.
|
||
|
|
[string]$Remote = '[email protected]:~/packetstation/test/ca/pesco-ca.pem',
|
||
|
|
# Write the file only; do not copy it.
|
||
|
|
[switch]$NoCopy
|
||
|
|
)
|
||
|
|
|
||
|
|
$ErrorActionPreference = 'Stop'
|
||
|
|
$now = Get-Date
|
||
|
|
|
||
|
|
$stores = 'Cert:\LocalMachine\Root', 'Cert:\LocalMachine\CA', 'Cert:\CurrentUser\Root', 'Cert:\CurrentUser\CA'
|
||
|
|
$certs = Get-ChildItem $stores |
|
||
|
|
Where-Object { $_.Subject -match $SubjectMatch -and $_.NotAfter -gt $now } |
|
||
|
|
Sort-Object Thumbprint -Unique
|
||
|
|
|
||
|
|
if (-not $certs) {
|
||
|
|
throw "No unexpired certificate with subject matching '$SubjectMatch' in the Root or CA stores."
|
||
|
|
}
|
||
|
|
|
||
|
|
$sb = New-Object System.Text.StringBuilder
|
||
|
|
foreach ($c in $certs) {
|
||
|
|
$sig = $c.SignatureAlgorithm.FriendlyName
|
||
|
|
[void]$sb.AppendLine("# $($c.Subject) | issued by $($c.Issuer) | expires $($c.NotAfter.ToString('yyyy-MM-dd')) | $sig")
|
||
|
|
[void]$sb.AppendLine('-----BEGIN CERTIFICATE-----')
|
||
|
|
[void]$sb.AppendLine([Convert]::ToBase64String($c.RawData, 'InsertLineBreaks'))
|
||
|
|
[void]$sb.AppendLine('-----END CERTIFICATE-----')
|
||
|
|
Write-Host (" {0} expires {1} {2}" -f $c.Subject, $c.NotAfter.ToString('yyyy-MM-dd'), $sig)
|
||
|
|
if ($sig -match 'sha1') {
|
||
|
|
Write-Warning "$($c.Subject) is SHA-1 signed. OpenSSL 3 refuses SHA-1 chains at its default security level; see docs/DEPLOY.md."
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# LF line endings so the file is clean on Linux.
|
||
|
|
[IO.File]::WriteAllText($OutFile, $sb.ToString().Replace("`r`n", "`n"))
|
||
|
|
Write-Host "Wrote $OutFile ($($certs.Count) certificates)"
|
||
|
|
|
||
|
|
if ($NoCopy) { return }
|
||
|
|
|
||
|
|
& scp -o BatchMode=yes $OutFile $Remote
|
||
|
|
if ($LASTEXITCODE -ne 0) { throw "scp to $Remote failed (exit $LASTEXITCODE)" }
|
||
|
|
Write-Host "Copied to $Remote"
|