proxy-pool/scripts/generate-local-controlplane-certs.ps1

139 lines
6.0 KiB
PowerShell

param(
[string]$OutputDirectory = (Join-Path (Split-Path -Parent $PSScriptRoot) "deploy/.control-plane-tls")
)
$ErrorActionPreference = "Stop"
if ([string]::IsNullOrWhiteSpace($OutputDirectory)) {
throw "OutputDirectory is required"
}
if (Test-Path -LiteralPath $OutputDirectory) {
$existing = @(Get-ChildItem -Force -LiteralPath $OutputDirectory)
if ($existing.Count -gt 0) {
throw "OutputDirectory must be empty: $OutputDirectory"
}
}
else {
New-Item -ItemType Directory -Path $OutputDirectory | Out-Null
}
function ConvertTo-Pem {
param(
[string]$Label,
[byte[]]$Bytes
)
$base64 = [Convert]::ToBase64String($Bytes, [Base64FormattingOptions]::InsertLineBreaks)
return "-----BEGIN $Label-----`n$base64`n-----END $Label-----`n"
}
function Write-PemFile {
param(
[string]$Path,
[string]$Label,
[byte[]]$Bytes
)
[IO.File]::WriteAllText($Path, (ConvertTo-Pem -Label $Label -Bytes $Bytes), [Text.Encoding]::ASCII)
}
function New-CertificateRequest {
param(
[string]$CommonName,
[System.Security.Cryptography.RSA]$Key,
[bool]$IsCertificateAuthority,
[string]$ExtendedKeyUsage,
[string]$SubjectAlternativeName
)
$request = [System.Security.Cryptography.X509Certificates.CertificateRequest]::new(
"CN=$CommonName",
$Key,
[System.Security.Cryptography.HashAlgorithmName]::SHA256,
[System.Security.Cryptography.RSASignaturePadding]::Pkcs1
)
$request.CertificateExtensions.Add([System.Security.Cryptography.X509Certificates.X509BasicConstraintsExtension]::new(
$IsCertificateAuthority, $false, 0, $true
))
if ($IsCertificateAuthority) {
$request.CertificateExtensions.Add([System.Security.Cryptography.X509Certificates.X509KeyUsageExtension]::new(
[System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::KeyCertSign -bor
[System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::CrlSign,
$true
))
return $request
}
$request.CertificateExtensions.Add([System.Security.Cryptography.X509Certificates.X509KeyUsageExtension]::new(
[System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::DigitalSignature -bor
[System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::KeyEncipherment,
$true
))
$usage = [System.Security.Cryptography.OidCollection]::new()
if ($ExtendedKeyUsage -eq "serverAuth") {
$null = $usage.Add([System.Security.Cryptography.Oid]::new("1.3.6.1.5.5.7.3.1"))
}
else {
$null = $usage.Add([System.Security.Cryptography.Oid]::new("1.3.6.1.5.5.7.3.2"))
}
$request.CertificateExtensions.Add([System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension]::new($usage, $true))
$san = [System.Security.Cryptography.X509Certificates.SubjectAlternativeNameBuilder]::new()
if ($SubjectAlternativeName.StartsWith("DNS:")) {
$san.AddDnsName($SubjectAlternativeName.Substring(4))
}
else {
$san.AddUri([Uri]$SubjectAlternativeName.Substring(4))
}
$request.CertificateExtensions.Add($san.Build())
return $request
}
function New-LeafCertificate {
param(
[string]$Name,
[string]$CommonName,
[string]$ExtendedKeyUsage,
[string]$SubjectAlternativeName
)
$directory = Join-Path $OutputDirectory $Name
New-Item -ItemType Directory -Path $directory | Out-Null
$key = [System.Security.Cryptography.RSA]::Create(2048)
try {
$request = New-CertificateRequest -CommonName $CommonName -Key $key -IsCertificateAuthority $false -ExtendedKeyUsage $ExtendedKeyUsage -SubjectAlternativeName $SubjectAlternativeName
$serial = [byte[]]::new(16)
[System.Security.Cryptography.RandomNumberGenerator]::Fill($serial)
$certificate = $request.Create($caCertificate, $notBefore, $notAfter, $serial)
try {
Write-PemFile -Path (Join-Path $directory "tls.crt") -Label "CERTIFICATE" -Bytes $certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
Write-PemFile -Path (Join-Path $directory "tls.key") -Label "PRIVATE KEY" -Bytes $key.ExportPkcs8PrivateKey()
}
finally {
$certificate.Dispose()
}
}
finally {
$key.Dispose()
}
Copy-Item -LiteralPath $caCertificatePath -Destination (Join-Path $directory "ca.crt")
}
$notBefore = [DateTimeOffset]::UtcNow.AddMinutes(-5)
$notAfter = $notBefore.AddDays(7)
$caKey = [System.Security.Cryptography.RSA]::Create(2048)
$caRequest = New-CertificateRequest -CommonName "proxy-pool-local-control-plane-ca" -Key $caKey -IsCertificateAuthority $true -ExtendedKeyUsage "" -SubjectAlternativeName ""
$caCertificate = $caRequest.CreateSelfSigned($notBefore, $notAfter)
$caCertificatePath = Join-Path $OutputDirectory "ca.crt"
Write-PemFile -Path $caCertificatePath -Label "CERTIFICATE" -Bytes $caCertificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
Write-PemFile -Path (Join-Path $OutputDirectory "ca.key") -Label "PRIVATE KEY" -Bytes $caKey.ExportPkcs8PrivateKey()
New-LeafCertificate -Name "controller" -CommonName "proxy-pool-controller" -ExtendedKeyUsage "serverAuth" -SubjectAlternativeName "DNS:controller"
New-LeafCertificate -Name "gateway-a" -CommonName "proxy-pool-gateway-a" -ExtendedKeyUsage "clientAuth" -SubjectAlternativeName "URI:spiffe://proxy-pool.local/development/worker/gateway-a"
New-LeafCertificate -Name "gateway-b" -CommonName "proxy-pool-gateway-b" -ExtendedKeyUsage "clientAuth" -SubjectAlternativeName "URI:spiffe://proxy-pool.local/development/worker/gateway-b"
New-LeafCertificate -Name "checker-a" -CommonName "proxy-pool-checker-a" -ExtendedKeyUsage "clientAuth" -SubjectAlternativeName "URI:spiffe://proxy-pool.local/development/checker/checker-a"
$caCertificate.Dispose()
$caKey.Dispose()
Write-Host "Generated local control-plane certificates in $OutputDirectory"