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)." } } } } } }