ps/Modules/Alkami.DevOps.Certificates/Public/Import-PodFromSecretServer.ps1
2023-05-30 22:51:22 -07:00

184 lines
9.2 KiB
PowerShell

function Import-PodFromSecretServer {
<#
.SYNOPSIS
Import Pod Certificates from Secret Server.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
$PodName,
[Parameter(Mandatory = $false, ParameterSetName = "credentials")]
[string]$SecretServerUrl ="https://alkami.secretservercloud.com",
[Parameter(Mandatory = $false, ParameterSetName = "credentials")]
$SecretServerUserName,
[Parameter(Mandatory = $false, ParameterSetName = "credentials")]
$SecretServerPassword,
[Parameter(Mandatory = $false)]
[ValidateSet("Web", "App")]
$ServerType,
[Parameter(Mandatory = $false, HelpMessage = "ADGroups that need permission to these certificates")]
[string[]]$ADGroups,
[Parameter(Mandatory = $false)]
$TempDirectory = "c:\temp\importTempDir",
[Parameter(Mandatory = $false)]
[string]$CertRoot = "Cert:\LocalMachine\",
[Parameter(Mandatory = $false)]
[switch]$UsePassword,
[Parameter(Mandatory = $false)]
[ValidateSet("Production", "Staging")]
[string]$EnvironmentType
)
begin {
Import-AWSModule # SSM
New-Item -Path $TempDirectory -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
switch ($EnvironmentType) {
"Production" {$RootFolderName = "Production-CertApi"}
"Staging" {$RootFolderName = "Staging-CertApi"}
}
# Get all parmeters which weren't supplied.
if(!$EnvironmentType)
{
$EnvironmentType = Get-AppSetting Environment.Type
}
if(!$PodName)
{
$PodName = Get-AppSetting Environment.Name
}
if(!$ServerType)
{
$ServerType = Get-AppSetting Environment.Server
}
if((!$SecretServerUserName -or !$SecretServerPassword))
{
if(Test-IsAws)
{
if(!$SecretServerUserName) {
$SecretServerUserName = (Get-SSMParameter -Name "secret_server_api_username" -WithDecryption $true).Value
}
if(!$SecretServerPassword) {
$SecretServerPassword = (Get-SSMParameter -Name "secret_server_api_password" -WithDecryption $true).Value
}
}
else {
Write-Error "Secret credentials must be manually provided if this is run on a non-AWS machine. They cannot be retrieved from SSM."
}
}
$secretServer = [SecretServerConnection]::new($SecretServerUrl, $SecretServerUserName, $SecretServerPassword)
$UseTwoFactor = $false
$secretServer.Authenticate($UseTwoFactor)
$NameOfCertificateField = "pfx-file"
$NameOfPasswordField = "Import Password"
Add-Type -Assembly System.IO.Compression.FileSystem
}
process {
$startTime = Get-Date
Write-Debug "Getting folder info"
$environmentFolderId = $secretServer.GetFolderIdByName($RootFolderName)
$podFolderId = $secretServer.GetFolderIdByName($PodName, $environmentFolderId)
$subFolderId = $secretServer.GetFolderIdByName($ServerType, $podFolderId) # Should be at an App/Mic/Web folder by this point. These folder names aren't unique, hence getting the environment folder id above.
$storeFolders = $secretServer.GetChildFolders($subFolderId)
$timeElapsed = New-TimeSpan -Start $startTime -End (Get-Date)
Write-Debug "Folder info retreived - $timeElapsed"
foreach ($storeFolder in $storeFolders) {
if ($storeFolder.FolderName -eq "CertificateAuthority") {$sanitizedStore = "CA"} else {$sanitizedStore = $storeFolder.FolderName} # Powershell's Paths don't match the X509 enum. So here we do a poor man's lookup. If we ever need more stores than just the CA, this needs to be expanded to something more robust and clean.
$TempStoreDirectory = Join-Path $TempDirectory $storeFolder.FolderName
$installedCerts = (Get-Cert -StoreName $sanitizedStore).thumbprint # Get certs in the current store.
Write-Debug "Getting Secrets and downloading certificate chain"
$secretInfoList = $secretServer.GetSecretByFolderId($storeFolder.id)
$secretInfoList | Where-Object {$installedCerts -notcontains $_.name.split("-")[-1]}
foreach ($secretInfo in $secretInfoList) {
$secret = $secretServer.GetSecretById($secretInfo.id)
# Don't import expired certs
$certExpirationDate = $secret.items | Where-Object {$_.fieldName -eq "ExperationDate"}
if ((Get-Date $certExpirationDate.itemValue) -gt (Get-Date)) {
if ($installedCerts) { #Don't die if there are no certs
$secretThumbprint = $secret.items | Where-Object {$_.fieldName -eq "Thumbprint"} | Select-Object -ExpandProperty itemValue
if ($installedCerts.Contains($secretThumbprint)) {
Write-Verbose "Certificate with thumbprint $secretThumbprint already installed"
continue
}
}
if ($UsePassword) {
$TempPassword = $secret.items | Where-Object {$_.fieldName -eq $NameOfPasswordField} | Select-Object -ExpandProperty itemValue
$Password = ConvertTo-SecureString $TempPassword -AsPlainText -Force
}
$folder = Join-Path $TempStoreDirectory $secret.Name
Remove-Item $folder -Force -ea SilentlyContinue -Recurse
New-Item $folder -ItemType Directory -Force -ea SilentlyContinue | Out-Null
$zipFolder = $folder, "$($secret.Name).zip" -join "\"
if ($secretServer.DownloadFile($secret.Id, $NameOfCertificateField, $zipFolder)) {
$timeElapsed = New-TimeSpan -Start $startTime -End (Get-Date)
Write-Debug "downloaded... - $timeElapsed"
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipFolder, $folder)
Write-Debug "unzipping complete - $timeElapsed"
$certificateFiles = Get-ChildItem $folder -Include "*.cer", "*.pfx" -Recurse
$certList = [System.Collections.Arraylist]::new()
foreach ($file in $certificateFiles) {
$certStore = if ($file.Directory.Name -Match $file.BaseName) {$sanitizedStore}else {$file.Directory.Name}
[void]$certList.Add(([PSObject]@{
file = $file
certStore = Join-path $CertRoot $certStore
}))
}
foreach ($cert in $certList) {
if ($cert.file.extension -eq ".cer") {
try {
Import-Certificate -FilePath $cert.file.FullName -CertStoreLocation $cert.certStore | Out-null
}
catch {
Write-Warning "Failed to import Cert with filename $($cert.file.FullName)"
Write-Warning -Message "Error: $($_.Exception.ErrorRecord)"
Write-Warning -Message "Stack Trace: $($_.Exception.StackTrace)"
}
}
else {
try {
$installedCert = Import-PfxCertificate -FilePath $cert.file.FullName -CertStoreLocation $cert.certStore -Exportable -Password $Password
foreach ($ADGroup in $ADGroups.Split("{,}")) {
Write-Host "Setting Permissions"
Set-CertPermissions -certThumprint $installedCert.Thumbprint -user $ADGroup | Out-Null
}
}
catch [System.ComponentModel.Win32Exception] {
Write-Warning "Failed to import Cert with filename $($cert.file.FullName)"
Write-Warning -Message "Error: $($_.Exception.Message)"
Write-Warning -Message "Stack Trace: $($_.Exception.StackTrace)"
}
catch {
Write-Warning "Failed to import Cert with filename $($cert.file.FullName)"
Write-Warning -Message "Error: $($_.Exception.ErrorRecord)"
Write-Warning -Message "Stack Trace: $($_.Exception.StackTrace)"
}
}
}
}
else {
Write-Warning -Message "File could not be downloaded for certificate with thumbprint $($secretThumbprint)."
}
}
}
}
}
}