90 lines
3.4 KiB
PowerShell
90 lines
3.4 KiB
PowerShell
#Requires -Version 5.1
|
|
[CmdletBinding(SupportsShouldProcess)]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[ValidatePattern('^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$')]
|
|
[string]$ClientName,
|
|
[string]$OutputDirectory = (Join-Path $PSScriptRoot '..\artifacts\azure-p2s'),
|
|
[securestring]$ClientPfxPassword,
|
|
[string]$RootSubject = 'CN=SGU Azure P2S Root',
|
|
[ValidateRange(1, 10)]
|
|
[int]$ClientValidityYears = 2,
|
|
[switch]$Force
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$resolvedOutputDirectory = [IO.Path]::GetFullPath($OutputDirectory)
|
|
New-Item -ItemType Directory -Path $resolvedOutputDirectory -Force | Out-Null
|
|
$rootCertificatePath = Join-Path $resolvedOutputDirectory 'sgu-azure-p2s-root.cer'
|
|
$clientCertificatePath = Join-Path $resolvedOutputDirectory "sgu-azure-p2s-$ClientName.pfx"
|
|
if ((Test-Path -LiteralPath $clientCertificatePath -PathType Leaf) -and -not $Force) {
|
|
throw "$clientCertificatePath already exists. Use -Force only when you intend to replace that exported client credential."
|
|
}
|
|
|
|
if (-not $ClientPfxPassword) {
|
|
$ClientPfxPassword = Read-Host 'Password that will protect the exported P2S client certificate' -AsSecureString
|
|
}
|
|
|
|
$rootCertificate = Get-ChildItem Cert:\CurrentUser\My |
|
|
Where-Object {
|
|
$_.Subject -eq $RootSubject -and
|
|
$_.HasPrivateKey -and
|
|
$_.NotAfter -gt (Get-Date).AddYears($ClientValidityYears)
|
|
} |
|
|
Sort-Object NotAfter -Descending |
|
|
Select-Object -First 1
|
|
|
|
if (-not $rootCertificate) {
|
|
if (-not $PSCmdlet.ShouldProcess($RootSubject, 'Create a non-exportable Azure P2S root certificate authority')) {
|
|
return
|
|
}
|
|
$rootCertificate = New-SelfSignedCertificate `
|
|
-Type Custom `
|
|
-Subject $RootSubject `
|
|
-CertStoreLocation Cert:\CurrentUser\My `
|
|
-KeyAlgorithm RSA `
|
|
-KeyLength 4096 `
|
|
-HashAlgorithm SHA256 `
|
|
-KeySpec Signature `
|
|
-KeyExportPolicy NonExportable `
|
|
-KeyUsage CertSign,CRLSign,DigitalSignature `
|
|
-NotAfter (Get-Date).AddYears(10) `
|
|
-TextExtension @('2.5.29.19={critical}{text}ca=1&pathlength=1')
|
|
}
|
|
|
|
if (-not $PSCmdlet.ShouldProcess($ClientName, 'Issue and export an Azure P2S machine certificate')) {
|
|
return
|
|
}
|
|
|
|
$clientSubject = "CN=SGU Azure P2S $ClientName"
|
|
$clientCertificate = New-SelfSignedCertificate `
|
|
-Type Custom `
|
|
-Subject $clientSubject `
|
|
-DnsName "sgu-p2s-$ClientName" `
|
|
-Signer $rootCertificate `
|
|
-CertStoreLocation Cert:\CurrentUser\My `
|
|
-KeyAlgorithm RSA `
|
|
-KeyLength 3072 `
|
|
-HashAlgorithm SHA256 `
|
|
-KeySpec Signature `
|
|
-KeyExportPolicy Exportable `
|
|
-KeyUsage DigitalSignature `
|
|
-NotAfter (Get-Date).AddYears($ClientValidityYears) `
|
|
-TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.2')
|
|
|
|
Export-Certificate -Cert $rootCertificate -FilePath $rootCertificatePath -Force | Out-Null
|
|
Export-PfxCertificate -Cert $clientCertificate -FilePath $clientCertificatePath `
|
|
-Password $ClientPfxPassword -ChainOption BuildChain -CryptoAlgorithmOption AES256_SHA256 `
|
|
-Force | Out-Null
|
|
|
|
[pscustomobject]@{
|
|
RootCertificatePath = $rootCertificatePath
|
|
RootCertificateThumbprint = $rootCertificate.Thumbprint
|
|
RootCertificateData = [Convert]::ToBase64String($rootCertificate.RawData)
|
|
ClientName = $ClientName
|
|
ClientCertificatePath = $clientCertificatePath
|
|
ClientCertificateThumbprint = $clientCertificate.Thumbprint
|
|
ClientCertificateExpires = $clientCertificate.NotAfter
|
|
RootPrivateKeyExportable = $false
|
|
}
|