Public/New-InfisicalSecret.ps1
|
# New-InfisicalSecret.ps1 # Creates a new secret in Infisical. # Called by: User directly. # Dependencies: InfisicalSession class, InfisicalSecret class, Invoke-InfisicalApi, Get-InfisicalSession, ConvertTo-InfisicalBody function New-InfisicalSecret { <# .SYNOPSIS Creates a new secret in Infisical. .DESCRIPTION Creates a secret with the specified name and value in the Infisical secrets manager. Accepts SecureString values by default to prevent plaintext in memory. A secondary -PlainTextValue parameter is available for convenience but issues a warning. .PARAMETER Name The name (key) of the secret to create. .PARAMETER Value The secret value as a SecureString. .PARAMETER PlainTextValue The secret value as a plain string. Issues a warning because the plaintext string remains in managed memory. Prefer -Value with SecureString. .PARAMETER Environment The environment slug. Overrides the session default if specified. .PARAMETER SecretPath The Infisical folder path. Defaults to "/". .PARAMETER ProjectId The project/workspace ID. Overrides the session default if specified. .PARAMETER Comment An optional note or comment for the secret. .PARAMETER SkipMultilineEncoding Skip encoding for multiline secret values. .PARAMETER TagIds An array of tag IDs to attach to the secret. .PARAMETER Metadata A hashtable of key-value metadata pairs to attach to the secret. .PARAMETER ReminderRepeatDays Interval for secret rotation reminders, measured in days. .PARAMETER ReminderNote A note to include in rotation reminder notification emails. .PARAMETER Type The secret type: 'shared' (default) or 'personal'. .PARAMETER Force If the secret already exists, update it instead of failing. Enables idempotent create-or-update semantics for CI/CD scripts. .PARAMETER PassThru Return the created InfisicalSecret object. .EXAMPLE $value = Read-Host -AsSecureString -Prompt 'Secret value' New-InfisicalSecret -Name 'DATABASE_URL' -Value $value Creates a new secret with a SecureString value. .EXAMPLE New-InfisicalSecret 'API_KEY' -PlainTextValue 'sk-test-123' -PassThru Creates a secret with a plaintext value (with warning) and returns the created object. .EXAMPLE New-InfisicalSecret 'DATABASE_URL' -Value $secureValue -Force Creates the secret if it does not exist, or updates it if it already exists. .OUTPUTS [InfisicalSecret] when -PassThru is specified; otherwise, no output. .NOTES Use SecureString values whenever possible. The -PlainTextValue parameter is provided for convenience in non-interactive scenarios but the plaintext string will remain in managed memory until garbage collected. .LINK Set-InfisicalSecret .LINK Get-InfisicalSecret .LINK Remove-InfisicalSecret #> [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'SecureValue')] [OutputType([InfisicalSecret])] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter(Mandatory, Position = 1, ParameterSetName = 'SecureValue')] [ValidateNotNull()] [System.Security.SecureString] $Value, [Parameter(Mandatory, ParameterSetName = 'PlainTextValue')] [ValidateNotNullOrEmpty()] [string] $PlainTextValue, [Parameter()] [string] $Environment, [Parameter()] [Alias('Path')] [string] $SecretPath = '/', [Parameter()] [string] $ProjectId, [Parameter()] [string] $Comment, [Parameter()] [switch] $SkipMultilineEncoding, [Parameter()] [string[]] $TagIds, [Parameter()] [hashtable] $Metadata, [Parameter()] [ValidateRange(1, 365)] [int] $ReminderRepeatDays, [Parameter()] [ValidateLength(0, 1024)] [string] $ReminderNote, [Parameter()] [ValidateSet('shared', 'personal')] [string] $Type, [Parameter()] [switch] $Force, [Parameter()] [switch] $PassThru ) $session = Get-InfisicalSession # Handle PlainTextValue — warn and convert to SecureString if ($PSCmdlet.ParameterSetName -eq 'PlainTextValue') { Write-Warning 'New-InfisicalSecret: Using -PlainTextValue. The plaintext string remains in managed memory. Prefer -Value with SecureString for better security.' $Value = [System.Security.SecureString]::new() foreach ($char in $PlainTextValue.ToCharArray()) { $Value.AppendChar($char) } $Value.MakeReadOnly() } $resolvedEnvironment = if ([string]::IsNullOrEmpty($Environment)) { $session.DefaultEnvironment } else { $Environment } if ($PSCmdlet.ShouldProcess("Creating secret '$Name' in path '$SecretPath' (environment: $resolvedEnvironment)")) { $bodyParams = @{ Session = $session Environment = $Environment SecretPath = $SecretPath ProjectId = $ProjectId SecretValue = $Value Comment = $Comment SkipMultilineEncoding = $SkipMultilineEncoding } if ($null -ne $TagIds -and $TagIds.Count -gt 0) { $bodyParams['TagIds'] = $TagIds } if ($null -ne $Metadata -and $Metadata.Count -gt 0) { $bodyParams['SecretMetadata'] = $Metadata } if ($PSBoundParameters.ContainsKey('ReminderRepeatDays')) { $bodyParams['ReminderRepeatDays'] = $ReminderRepeatDays } if (-not [string]::IsNullOrEmpty($ReminderNote)) { $bodyParams['ReminderNote'] = $ReminderNote } if (-not [string]::IsNullOrEmpty($Type)) { $bodyParams['Type'] = $Type } $body = ConvertTo-InfisicalBody @bodyParams $encodedName = [System.Uri]::EscapeDataString($Name) $response = $null $usedUpdate = $false try { $response = Invoke-InfisicalApi -Method POST -Endpoint "/api/v4/secrets/$encodedName" -Body $body -Session $session } catch { if ($Force.IsPresent) { # Secret likely already exists — fall back to update Write-Verbose "New-InfisicalSecret: Create failed, updating existing secret '$Name' (-Force)." $setParams = @{ Name = $Name Value = $Value SecretPath = $SecretPath Confirm = $false } if (-not [string]::IsNullOrEmpty($Environment)) { $setParams['Environment'] = $Environment } if (-not [string]::IsNullOrEmpty($ProjectId)) { $setParams['ProjectId'] = $ProjectId } if (-not [string]::IsNullOrEmpty($Comment)) { $setParams['Comment'] = $Comment } if ($SkipMultilineEncoding.IsPresent) { $setParams['SkipMultilineEncoding'] = $true } if ($null -ne $TagIds -and $TagIds.Count -gt 0) { $setParams['TagIds'] = $TagIds } if ($null -ne $Metadata -and $Metadata.Count -gt 0) { $setParams['Metadata'] = $Metadata } if ($PSBoundParameters.ContainsKey('ReminderRepeatDays')) { $setParams['ReminderRepeatDays'] = $ReminderRepeatDays } if (-not [string]::IsNullOrEmpty($ReminderNote)) { $setParams['ReminderNote'] = $ReminderNote } if (-not [string]::IsNullOrEmpty($Type)) { $setParams['Type'] = $Type } if ($PassThru.IsPresent) { $setParams['PassThru'] = $true } $result = Set-InfisicalSecret @setParams $usedUpdate = $true if ($PassThru.IsPresent) { return $result } return } throw } if (-not $usedUpdate -and $PassThru.IsPresent -and $null -ne $response -and $null -ne $response.secret) { $resolvedProjectId = if ([string]::IsNullOrEmpty($ProjectId)) { $session.ProjectId } else { $ProjectId } return ConvertTo-InfisicalSecret -SecretData $response.secret -Environment $resolvedEnvironment -ProjectId $resolvedProjectId -FallbackPath $SecretPath } } } |