Providers/Authentik/Private/Export-AuthentikCredential.ps1
|
function Export-AuthentikCredential { <# .SYNOPSIS Writes the service account credential record, with the token protected .DESCRIPTION The record names the instance, the account and where its token is. The token itself goes to one of two places, and the record is the authority on which: into a SecretStore vault under -UseSecretStore, which is encrypted and portable, or into the record DPAPI-protected, which is encrypted on Windows only. A record written before the vault was proven usable would name a secret that was never stored, so the vault is initialised first and the record last. Written as UTF-8 bytes rather than through Set-Content, which on Windows PowerShell prepends a byte order mark that a strict JSON reader rejects. The folder is restricted to the current user before the file exists in it, and the file again afterwards. .PARAMETER Path Where to write the record. .PARAMETER BaseUrl The instance the account belongs to. .PARAMETER Username The service account's username. .PARAMETER UserPk The service account's primary key. .PARAMETER Token The API token to store. .PARAMETER UseSecretStore Keep the token in a SecretStore vault rather than in the record. .PARAMETER VaultName The vault to use with -UseSecretStore. .PARAMETER VaultPassword The vault's password, when it is not the module default. .OUTPUTS PSCustomObject with Path, Protection, VaultName and SecretName. .EXAMPLE PS> Export-AuthentikCredential -Path $path -BaseUrl $url -Username $name -UserPk $pk -Token $token -Confirm:$false DESCRIPTION: Writes the record with the token DPAPI-protected OUTPUT: Path and Protection 'DPAPI' USE CASE: The end of New-AuthentikServiceApp .NOTES Author: Jeffrey Stuhr Blog: https://www.techbyjeff.net LinkedIn: https://www.linkedin.com/in/jeffrey-stuhr-034214aa/ #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', 'Token', Justification = 'The token arrives from the API as a string and is protected here before it touches disk.')] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$BaseUrl, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Username, [Parameter(Mandatory = $true)] [int]$UserPk, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Token, [Parameter()] [switch]$UseSecretStore, [Parameter()] [ValidateNotNullOrEmpty()] [string]$VaultName = 'AuthentikEnvironment', [Parameter()] [System.Security.SecureString]$VaultPassword ) if (-not $PSCmdlet.ShouldProcess($Path, 'Write the service account credential record')) { return $null } $folder = Split-Path -Path $Path -Parent if ($folder -and -not (Test-Path -LiteralPath $folder)) { $null = New-Item -ItemType Directory -Path $folder -Force $null = Protect-TestFile -Path $folder -Confirm:$false } $payload = [ordered]@{ schemaVersion = 1 baseUrl = $BaseUrl username = $Username userPk = $UserPk createdUtc = [DateTime]::UtcNow.ToString('o') } $secretName = $null if ($UseSecretStore) { $secretName = 'AuthentikEnvironment-{0}-{1}' -f ([uri]$BaseUrl).Host, $Username $vault = Initialize-TestSecretVault -VaultName $VaultName -VaultPassword $VaultPassword -Install if (-not $vault -or -not $vault.Available) { throw "Vault '$VaultName' is not usable, so the token was not stored." } Set-TestVaultSecret -VaultName $VaultName -SecretName $secretName -PlainText $Token $payload['protection'] = 'SecretStore' $payload['vaultName'] = $VaultName $payload['secretName'] = $secretName } else { $protected = Protect-TestSecret -PlainText $Token $payload['protection'] = $protected.Method $payload['tokenProtected'] = $protected.Value } $json = $payload | ConvertTo-Json -Depth 5 [System.IO.File]::WriteAllBytes($Path, [System.Text.Encoding]::UTF8.GetBytes($json)) $null = Protect-TestFile -Path $Path -Confirm:$false return [PSCustomObject]@{ Path = $Path Protection = $payload['protection'] VaultName = $(if ($UseSecretStore) { $VaultName } else { $null }) SecretName = $secretName } } |