diff --git a/step-templates/cyberark-conjur-retrieve-secrets.json b/step-templates/cyberark-conjur-retrieve-secrets.json index aabd06a2..195a07ef 100644 --- a/step-templates/cyberark-conjur-retrieve-secrets.json +++ b/step-templates/cyberark-conjur-retrieve-secrets.json @@ -3,14 +3,14 @@ "Name": "CyberArk Conjur - Retrieve Secrets", "Description": "This step retrieves one or more secrets from [CyberArk Conjur](https://www.conjur.org/) and creates [sensitive output variables](https://octopus.com/docs/projects/variables/output-variables#sensitive-output-variables) for each value retrieved. These values can be used in other steps in your deployment or runbook process.\n\nThis step differs from the [CyberArk Conjur - Retrieve a Secret](https://library.octopus.com/step-templates/eafe9740-1008-4375-9e82-0d193109b669/actiontemplate-cyberark-conjur-retrieve-a-secret) step template as it offers the ability to retrieve multiple secrets (with optional version) and performs a batched call where possible - see below for further details.\n\n---\n\n**Retrieval Behavior:**\n\n- If any of the Conjur Variables have a version specified to retrieve, then the step template will retrieve **all** of the secrets individually using the [Conjur REST API - Secret Retrieve](https://docs.conjur.org/Latest/en/Content/Developer/Conjur_API_Retrieve_Secret.htm) endpoint.\n- If none of the Conjur Variables have a version specified (i.e. retrieve the latest version) then the step template will retrieve the secrets using the [Conjur REST API - Batch Retrieval](https://docs.conjur.org/Latest/en/Content/Developer/Conjur_API_Batch_Retrieve.htm) endpoint.\n\n*Hint:* If performance is important to you, don't include specific versions of Conjur Variables. It’s faster to fetch secrets in a batch than to fetch them one at a time.\n\n---\n\n**Required:** \n- PowerShell **5.1** or higher.\n- A set of credentials with permissions to retrieve secrets from CyberArk Conjur.\n- Access to the Conjur instance from the Worker or target where this step executes.\n\nNotes:\n\n- Tested on Conjur **v1.13.2** / API **v5.2.0**.\n- Tested on Octopus **2021.2**.\n- Tested on both Windows Server 2019 and Ubuntu 20.04.", "ActionType": "Octopus.Script", - "Version": 1, + "Version": 2, "CommunityActionTemplateId": null, "Packages": [], "Properties": { "Octopus.Action.Script.ScriptSource": "Inline", "Octopus.Action.Script.Syntax": "PowerShell", - "Octopus.Action.Script.ScriptBody": "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n$ErrorActionPreference = 'Stop'\n\n# Variables\n$ConjurUrl = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.Url\"]\n$ConjurAccount = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.Account\"]\n$ConjurLogin = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.Login\"]\n$ConjurApiKey = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.ApiKey\"]\n$ConjurSecretVariables = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.SecretVariables\"]\n$PrintVariableNames = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.PrintVariableNames\"]\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($ConjurUrl)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.Url not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurAccount)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.Account not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurLogin)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.Login not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurApiKey)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.ApiKey not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurSecretVariables)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.SecretVariables not specified\"\n}\n\n### Helper functions\n\n# This function creates a URI and prevents Urls that have been Url encoded from being re-encoded.\n# Typically this happens on Windows (dynamic) workers in Octopus, and not PS Core.\n# Helpful background - https://stackoverflow.com/questions/25596564/percent-encoded-slash-is-decoded-before-the-request-dispatch\n# Function based from https://github.com/IISResetMe/PSdotNETRuntimeHacks/blob/trunk/Set-DontUnescapePathDotsAndSlashes.ps1\nfunction New-DontUnescapePathDotsAndSlashes-Uri {\n param(\n [Parameter(Mandatory = $true)]\n [ValidateNotNull()]\n [string]$SourceUri\n )\n\n $uri = New-Object System.Uri $SourceUri\n\n # If running PS Core, not affected\n if ($PSEdition -eq \"Core\") {\n return $uri\n }\n\n # Retrieve the private Syntax field from the uri class,\n # this is our indirect reference to the attached parser\n $syntaxFieldInfo = $uri.GetType().GetField('m_Syntax', 'NonPublic,Instance')\n if (-not $syntaxFieldInfo) {\n throw [System.MissingFieldException]\"'m_Syntax' field not found\"\n }\n\n # Retrieve the private Flags field from the parser class,\n # this is the value we're looking to update at runtime\n $flagsFieldInfo = [System.UriParser].GetField('m_Flags', 'NonPublic,Instance')\n if (-not $flagsFieldInfo) {\n throw [System.MissingFieldException]\"'m_Flags' field not found\"\n }\n\n # Retrieve the actual instances\n $uriParser = $syntaxFieldInfo.GetValue($uri)\n $uriSyntaxFlags = $flagsFieldInfo.GetValue($uriParser)\n\n # Define the bit flags we want to remove\n $UnEscapeDotsAndSlashes = 0x2000000\n $SimpleUserSyntax = 0x20000\n\n # Clear the flags that we don't want\n $uriSyntaxFlags = [int]$uriSyntaxFlags -band -bnot($UnEscapeDotsAndSlashes)\n $uriSyntaxFlags = [int]$uriSyntaxFlags -band -bnot($SimpleUserSyntax)\n\n # Overwrite the existing Flags field\n $flagsFieldInfo.SetValue($uriParser, $uriSyntaxFlags)\n\n return $uri\n}\n\nfunction Get-WebRequestErrorBody {\n param (\n $RequestError\n )\n $rawResponse = \"\"\n # Powershell < 6 you can read the Exception\n if ($PSVersionTable.PSVersion.Major -lt 6) {\n if ($RequestError.Exception.Response) {\n $reader = New-Object System.IO.StreamReader($RequestError.Exception.Response.GetResponseStream())\n $reader.BaseStream.Position = 0\n $reader.DiscardBufferedData()\n $rawResponse = $reader.ReadToEnd()\n }\n }\n else {\n $rawResponse = $RequestError.ErrorDetails.Message\n }\n\n try { $response = $rawResponse | ConvertFrom-Json } catch { $response = $rawResponse }\n return $response\n}\n\nfunction Format-SecretName {\n [CmdletBinding()]\n Param(\n [string] $Name,\n [string] $Version\n )\n $displayName = \"'$Name'\"\n if (![string]::IsNullOrWhiteSpace($Version)) {\n $displayName += \" (v:$($Version))\"\n }\n return $displayName\n}\n\n### End Helper function\n\n$Secrets = @()\n$VariablesCreated = 0\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n$ConjurUrl = $ConjurUrl.TrimEnd(\"/\")\n\n# Extract secret names\n@(($ConjurSecretVariables -Split \"`n\").Trim()) | ForEach-Object {\n if (![string]::IsNullOrWhiteSpace($_)) {\n Write-Verbose \"Working on: '$_'\"\n $secretDefinition = ($_ -Split \"\\|\")\n $secretName = $secretDefinition[0].Trim()\n $secretNameAndVersion = ($secretName -Split \" \")\n $secretVersion = \"\"\n if ($secretNameAndVersion.Count -gt 1) {\n $secretName = $secretNameAndVersion[0].Trim()\n $secretVersion = $secretNameAndVersion[1].Trim()\n }\n if ([string]::IsNullOrWhiteSpace($secretName)) {\n throw \"Unable to establish secret name from: '$($_)'\"\n }\n\n $UriEscapedName = [uri]::EscapeDataString($secretName)\n $VariableIdPrefix = \"$($ConjurAccount):variable\"\n\n $secret = [PsCustomObject]@{\n Name = $secretName\n UriEscapedName = $uriEscapedName\n Version = $secretVersion\n VariableName = if (![string]::IsNullOrWhiteSpace($secretDefinition[1])) { $secretDefinition[1].Trim() } else { \"\" }\n VariableId = \"$($VariableIdPrefix):$($secretName)\"\n UriEscapedVariableId = \"$($VariableIdPrefix):$($UriEscapedName)\"\n }\n $Secrets += $secret\n }\n}\n$SecretsWithVersionSpecified = @($Secrets | Where-Object { ![string]::IsNullOrWhiteSpace($_.Version) })\n\nWrite-Verbose \"Conjur Url: $ConjurUrl\"\nWrite-Verbose \"Conjur Account: $ConjurAccount\"\nWrite-Verbose \"Conjur Login: $ConjurLogin\"\nWrite-Verbose \"Conjur API Key: ********\"\nWrite-Verbose \"Secrets to retrieve: $($Secrets.Count)\"\nWrite-Verbose \"Secrets with Version specified: $($SecretsWithVersionSpecified.Count)\"\nWrite-Verbose \"Print variables: $PrintVariableNames\"\n\ntry {\n\n $headers = @{\n \"Content-Type\" = \"application/json\"; \n \"Accept-Encoding\" = \"base64\"\n }\n\n $body = $ConjurApiKey\n $loginUriSegment = [uri]::EscapeDataString($ConjurLogin)\n $authnUri = New-DontUnescapePathDotsAndSlashes-Uri -SourceUri \"$ConjurUrl/authn/$ConjurAccount/$loginUriSegment/authenticate\"\n $authToken = Invoke-RestMethod -Uri $authnUri -Method Post -Headers $headers -Body $body\n}\ncatch {\n $ExceptionMessage = $_.Exception.Message\n $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n $Message = \"An error occurred logging in to Conjur: $ExceptionMessage\"\n $AdditionalDetail = \"\"\n if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n if ($null -ne $ErrorBody.error) {\n $AdditionalDetail = \"$($ErrorBody.error.code) - $($ErrorBody.error.message)\"\n }\n else {\n $AdditionalDetail += $ErrorBody\n }\n }\n if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n $Message += \"`nDetail: $AdditionalDetail\"\n }\n \n Write-Error $Message -Category AuthenticationError\n}\n\nif ([string]::IsNullOrWhiteSpace($authToken)) {\n Write-Error \"Null or Empty token!\"\n return\n}\n\n# Set token auth header\n$headers = @{\n \"Authorization\" = \"Token token=`\"$($authToken)`\"\"; \n}\n\nif ($SecretsWithVersionSpecified.Count -gt 0) {\n Write-Verbose \"Retrieving secrets individually as at least one has a version specified.\"\n foreach ($secret in $Secrets) {\n try {\n $name = $secret.Name\n $uriEscapedName = $secret.UriEscapedName\n $secretVersion = $secret.Version\n $variableName = $secret.VariableName\n $displayName = Format-SecretName -Name $name -Version $secretVersion\n\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim().Replace(\"/\",\".\"))\"\n }\n $secretUri = \"$ConjurUrl/secrets/$ConjurAccount/variable/$uriEscapedName\"\n if (![string]::IsNullOrWhiteSpace($secretVersion)) {\n $secretUri += \"?version=$($secretVersion)\"\n }\n $secretUri = New-DontUnescapePathDotsAndSlashes-Uri -SourceUri \"$secretUri\"\n Write-Verbose \"Retrieving Secret $displayName\"\n $secretValue = Invoke-RestMethod -Uri $secretUri -Method Get -Headers $headers \n\n if ([string]::IsNullOrWhiteSpace($secretValue)) {\n Write-Error \"Error: Secret $displayName not found or has no versions.\"\n break;\n }\n \n Set-OctopusVariable -Name $variableName -Value $secretValue -Sensitive\n \n if ($PrintVariableNames -eq $True) {\n Write-Output \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n }\n catch {\n $ExceptionMessage = $_.Exception.Message\n $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n $Message = \"An error occurred retrieving secret $($displayName) from Conjur: $ExceptionMessage\"\n $AdditionalDetail = \"\"\n if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n if ($null -ne $ErrorBody.error) {\n $AdditionalDetail = \"$($ErrorBody.error.code) - $($ErrorBody.error.message)\"\n }\n else {\n $AdditionalDetail += $ErrorBody\n }\n }\n \n if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n $Message += \"`nDetail: $AdditionalDetail\"\n }\n \n Write-Error $Message -Category ReadError\n break;\n }\n }\n}\nelse {\n Write-Verbose \"Retrieving secrets by batch as no versions specified.\"\n $uriEscapedVariableIds = @($Secrets | ForEach-Object { \"$($_.UriEscapedVariableId)\" }) -Join \",\"\n\n try { \n $secretsUri = New-DontUnescapePathDotsAndSlashes-Uri -SourceUri \"$ConjurUrl/secrets?variable_ids=$($uriEscapedVariableIds)\"\n $secretValues = Invoke-RestMethod -Uri $secretsUri -Method Get -Headers $headers\n $secretKeyValues = $secretValues | Get-Member | Where-Object { $_.MemberType -eq \"NoteProperty\" } | Select-Object -ExpandProperty \"Name\"\n foreach ($secret in $Secrets) {\n $name = $secret.Name\n $variableId = $secret.VariableId\n $variableName = $secret.VariableName\n\n Write-Verbose \"Extracting Secret '$($name)' from Conjur batched response\"\n\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim().Replace(\"/\",\".\"))\"\n }\n if ($secretKeyValues -inotcontains $variableId) {\n Write-Error \"Secret '$name' not found in Conjur response.\"\n return\n }\n \n $variableValue = $secretValues.$variableId\n Set-OctopusVariable -Name $variableName -Value $variableValue -Sensitive\n\n if ($PrintVariableNames -eq $True) {\n Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n }\n }\n catch {\n $ExceptionMessage = $_.Exception.Message\n $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n $Message = \"An error occurred retrieving batched secrets from Conjur: $ExceptionMessage\"\n $AdditionalDetail = \"\"\n if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n if ($null -ne $ErrorBody.error) {\n $AdditionalDetail = \"$($ErrorBody.error.code) - $($ErrorBody.error.message)\"\n }\n else {\n $AdditionalDetail += $ErrorBody\n }\n }\n if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n $Message += \"`nDetail: $AdditionalDetail\"\n }\n \n Write-Error $Message -Category AuthenticationError\n }\n}\n\nWrite-Host \"Created $variablesCreated output variables\"" - }, + "Octopus.Action.Script.ScriptBody": "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n$ErrorActionPreference = 'Stop'\n\n# Variables\n$ConjurUrl = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.Url\"]\n$ConjurAccount = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.Account\"]\n$ConjurLogin = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.Login\"]\n$ConjurApiKey = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.ApiKey\"]\n$ConjurSecretVariables = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.SecretVariables\"]\n$PrintVariableNames = $OctopusParameters[\"CyberArk.Conjur.RetrieveSecrets.PrintVariableNames\"]\n$ConjurTrustCertificate = [System.Convert]::ToBoolean($OctopusParameters['CyberArk.Conjur.TrustCertificate'])\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($ConjurUrl)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.Url not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurAccount)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.Account not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurLogin)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.Login not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurApiKey)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.ApiKey not specified\"\n}\nif ([string]::IsNullOrWhiteSpace($ConjurSecretVariables)) {\n throw \"Required parameter CyberArk.Conjur.RetrieveSecrets.SecretVariables not specified\"\n}\n\n### Helper functions\n\n# This function creates a URI and prevents Urls that have been Url encoded from being re-encoded.\n# Typically this happens on Windows (dynamic) workers in Octopus, and not PS Core.\n# Helpful background - https://stackoverflow.com/questions/25596564/percent-encoded-slash-is-decoded-before-the-request-dispatch\n# Function based from https://github.com/IISResetMe/PSdotNETRuntimeHacks/blob/trunk/Set-DontUnescapePathDotsAndSlashes.ps1\nfunction New-DontUnescapePathDotsAndSlashes-Uri {\n param(\n [Parameter(Mandatory = $true)]\n [ValidateNotNull()]\n [string]$SourceUri\n )\n\n $uri = New-Object System.Uri $SourceUri\n\n # If running PS Core, not affected\n if ($PSEdition -eq \"Core\") {\n return $uri\n }\n\n # Retrieve the private Syntax field from the uri class,\n # this is our indirect reference to the attached parser\n $syntaxFieldInfo = $uri.GetType().GetField('m_Syntax', 'NonPublic,Instance')\n if (-not $syntaxFieldInfo) {\n throw [System.MissingFieldException]\"'m_Syntax' field not found\"\n }\n\n # Retrieve the private Flags field from the parser class,\n # this is the value we're looking to update at runtime\n $flagsFieldInfo = [System.UriParser].GetField('m_Flags', 'NonPublic,Instance')\n if (-not $flagsFieldInfo) {\n throw [System.MissingFieldException]\"'m_Flags' field not found\"\n }\n\n # Retrieve the actual instances\n $uriParser = $syntaxFieldInfo.GetValue($uri)\n $uriSyntaxFlags = $flagsFieldInfo.GetValue($uriParser)\n\n # Define the bit flags we want to remove\n $UnEscapeDotsAndSlashes = 0x2000000\n $SimpleUserSyntax = 0x20000\n\n # Clear the flags that we don't want\n $uriSyntaxFlags = [int]$uriSyntaxFlags -band -bnot($UnEscapeDotsAndSlashes)\n $uriSyntaxFlags = [int]$uriSyntaxFlags -band -bnot($SimpleUserSyntax)\n\n # Overwrite the existing Flags field\n $flagsFieldInfo.SetValue($uriParser, $uriSyntaxFlags)\n\n return $uri\n}\n\nfunction Get-WebRequestErrorBody {\n param (\n $RequestError\n )\n $rawResponse = \"\"\n # Powershell < 6 you can read the Exception\n if ($PSVersionTable.PSVersion.Major -lt 6) {\n if ($RequestError.Exception.Response) {\n $reader = New-Object System.IO.StreamReader($RequestError.Exception.Response.GetResponseStream())\n $reader.BaseStream.Position = 0\n $reader.DiscardBufferedData()\n $rawResponse = $reader.ReadToEnd()\n }\n }\n else {\n $rawResponse = $RequestError.ErrorDetails.Message\n }\n\n try { $response = $rawResponse | ConvertFrom-Json } catch { $response = $rawResponse }\n return $response\n}\n\nfunction Format-SecretName {\n [CmdletBinding()]\n Param(\n [string] $Name,\n [string] $Version\n )\n $displayName = \"'$Name'\"\n if (![string]::IsNullOrWhiteSpace($Version)) {\n $displayName += \" (v:$($Version))\"\n }\n return $displayName\n}\n\nfunction Invoke-CyberArk-Rest-Method\n{\n # define parameters\n [CmdletBinding()]\n param(\n $Url,\n $Method,\n $Headers,\n $Body,\n $TrustCertificate\n )\n\n # define working variables\n $invokeArguments = @{\n Uri = $Url\n Method = $Method\n }\n\n # Check for the presence of variables\n if (![string]::IsNullOrWhitespace($Headers))\n {\n $invokeArguments.Add(\"Headers\", $Headers)\n }\n\n if (![string]::IsNullOrWhitespace($Body))\n {\n $invokeArguments.Add(\"Body\", $Body)\n }\n\n if ($TrustCertificate -eq $true)\n {\n $invokeArguments.Add(\"SkipCertificateCheck\", $TrustCertificate)\n }\n\n return Invoke-RestMethod @invokeArguments\n}\n\n### End Helper function\n\n$Secrets = @()\n$VariablesCreated = 0\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n$ConjurUrl = $ConjurUrl.TrimEnd(\"/\")\n\n\n# Extract secret names\n@(($ConjurSecretVariables -Split \"`n\").Trim()) | ForEach-Object {\n if (![string]::IsNullOrWhiteSpace($_)) {\n Write-Verbose \"Working on: '$_'\"\n $secretDefinition = ($_ -Split \"\\|\")\n $secretName = $secretDefinition[0].Trim()\n $secretNameAndVersion = ($secretName -Split \" \")\n $secretVersion = \"\"\n if ($secretNameAndVersion.Count -gt 1) {\n $secretName = $secretNameAndVersion[0].Trim()\n $secretVersion = $secretNameAndVersion[1].Trim()\n }\n if ([string]::IsNullOrWhiteSpace($secretName)) {\n throw \"Unable to establish secret name from: '$($_)'\"\n }\n\n $UriEscapedName = [uri]::EscapeDataString($secretName)\n $VariableIdPrefix = \"$($ConjurAccount):variable\"\n\n $secret = [PsCustomObject]@{\n Name = $secretName\n UriEscapedName = $uriEscapedName\n Version = $secretVersion\n VariableName = if (![string]::IsNullOrWhiteSpace($secretDefinition[1])) { $secretDefinition[1].Trim() } else { \"\" }\n VariableId = \"$($VariableIdPrefix):$($secretName)\"\n UriEscapedVariableId = \"$($VariableIdPrefix):$($UriEscapedName)\"\n }\n $Secrets += $secret\n }\n}\n$SecretsWithVersionSpecified = @($Secrets | Where-Object { ![string]::IsNullOrWhiteSpace($_.Version) })\n\nWrite-Verbose \"Conjur Url: $ConjurUrl\"\nWrite-Verbose \"Conjur Account: $ConjurAccount\"\nWrite-Verbose \"Conjur Login: $ConjurLogin\"\nWrite-Verbose \"Conjur API Key: ********\"\nWrite-Verbose \"Secrets to retrieve: $($Secrets.Count)\"\nWrite-Verbose \"Secrets with Version specified: $($SecretsWithVersionSpecified.Count)\"\nWrite-Verbose \"Print variables: $PrintVariableNames\"\n\ntry {\n\n $headers = @{\n \"Content-Type\" = \"application/json\"; \n \"Accept-Encoding\" = \"base64\"\n }\n\n $body = $ConjurApiKey\n $loginUriSegment = [uri]::EscapeDataString($ConjurLogin)\n $authnUri = New-DontUnescapePathDotsAndSlashes-Uri -SourceUri \"$ConjurUrl/authn/$ConjurAccount/$loginUriSegment/authenticate\"\n #$authToken = Invoke-RestMethod -Uri $authnUri -Method Post -Headers $headers -Body $body\n $authToken = Invoke-CyberArk-Rest-Method -Url $authnUri -Method Post -Headers $headers -Body $body -TrustCertificate $ConjurTrustCertificate\n}\ncatch {\n $ExceptionMessage = $_.Exception.Message\n $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n $Message = \"An error occurred logging in to Conjur: $ExceptionMessage\"\n $AdditionalDetail = \"\"\n if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n if ($null -ne $ErrorBody.error) {\n $AdditionalDetail = \"$($ErrorBody.error.code) - $($ErrorBody.error.message)\"\n }\n else {\n $AdditionalDetail += $ErrorBody\n }\n }\n if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n $Message += \"`nDetail: $AdditionalDetail\"\n }\n \n Write-Error $Message -Category AuthenticationError\n}\n\nif ([string]::IsNullOrWhiteSpace($authToken)) {\n Write-Error \"Null or Empty token!\"\n return\n}\n\n# Set token auth header\n$headers = @{\n \"Authorization\" = \"Token token=`\"$($authToken)`\"\"; \n}\n\nif ($SecretsWithVersionSpecified.Count -gt 0) {\n Write-Verbose \"Retrieving secrets individually as at least one has a version specified.\"\n foreach ($secret in $Secrets) {\n try {\n $name = $secret.Name\n $uriEscapedName = $secret.UriEscapedName\n $secretVersion = $secret.Version\n $variableName = $secret.VariableName\n $displayName = Format-SecretName -Name $name -Version $secretVersion\n\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim().Replace(\"/\",\".\"))\"\n }\n $secretUri = \"$ConjurUrl/secrets/$ConjurAccount/variable/$uriEscapedName\"\n if (![string]::IsNullOrWhiteSpace($secretVersion)) {\n $secretUri += \"?version=$($secretVersion)\"\n }\n $secretUri = New-DontUnescapePathDotsAndSlashes-Uri -SourceUri \"$secretUri\"\n Write-Verbose \"Retrieving Secret $displayName\"\n #$secretValue = Invoke-RestMethod -Uri $secretUri -Method Get -Headers $headers\n $secretValue = Invoke-CyberArk-Rest-Method -Url $secretUri -Method Get -Headers $headers -TrustCertificate $ConjurTrustCertificate\n\n if ([string]::IsNullOrWhiteSpace($secretValue)) {\n Write-Error \"Error: Secret $displayName not found or has no versions.\"\n break;\n }\n \n Set-OctopusVariable -Name $variableName -Value $secretValue -Sensitive\n \n if ($PrintVariableNames -eq $True) {\n Write-Output \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n }\n catch {\n $ExceptionMessage = $_.Exception.Message\n $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n $Message = \"An error occurred retrieving secret $($displayName) from Conjur: $ExceptionMessage\"\n $AdditionalDetail = \"\"\n if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n if ($null -ne $ErrorBody.error) {\n $AdditionalDetail = \"$($ErrorBody.error.code) - $($ErrorBody.error.message)\"\n }\n else {\n $AdditionalDetail += $ErrorBody\n }\n }\n \n if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n $Message += \"`nDetail: $AdditionalDetail\"\n }\n \n Write-Error $Message -Category ReadError\n break;\n }\n }\n}\nelse {\n Write-Verbose \"Retrieving secrets by batch as no versions specified.\"\n $uriEscapedVariableIds = @($Secrets | ForEach-Object { \"$($_.UriEscapedVariableId)\" }) -Join \",\"\n\n try { \n $secretsUri = New-DontUnescapePathDotsAndSlashes-Uri -SourceUri \"$ConjurUrl/secrets?variable_ids=$($uriEscapedVariableIds)\"\n #$secretValues = Invoke-RestMethod -Uri $secretsUri -Method Get -Headers $headers\n $secretValues = Invoke-CyberArk-Rest-Method -Url $secretsUri -Method Get -Headers $headers -TrustCertificate $ConjurTrustCertificate\n $secretKeyValues = $secretValues | Get-Member | Where-Object { $_.MemberType -eq \"NoteProperty\" } | Select-Object -ExpandProperty \"Name\"\n foreach ($secret in $Secrets) {\n $name = $secret.Name\n $variableId = $secret.VariableId\n $variableName = $secret.VariableName\n\n Write-Verbose \"Extracting Secret '$($name)' from Conjur batched response\"\n\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim().Replace(\"/\",\".\"))\"\n }\n if ($secretKeyValues -inotcontains $variableId) {\n Write-Error \"Secret '$name' not found in Conjur response.\"\n return\n }\n \n $variableValue = $secretValues.$variableId\n Set-OctopusVariable -Name $variableName -Value $variableValue -Sensitive\n\n if ($PrintVariableNames -eq $True) {\n Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n }\n }\n catch {\n $ExceptionMessage = $_.Exception.Message\n $ErrorBody = Get-WebRequestErrorBody -RequestError $_\n $Message = \"An error occurred retrieving batched secrets from Conjur: $ExceptionMessage\"\n $AdditionalDetail = \"\"\n if (![string]::IsNullOrWhiteSpace($ErrorBody)) {\n if ($null -ne $ErrorBody.error) {\n $AdditionalDetail = \"$($ErrorBody.error.code) - $($ErrorBody.error.message)\"\n }\n else {\n $AdditionalDetail += $ErrorBody\n }\n }\n if (![string]::IsNullOrWhiteSpace($AdditionalDetail)) {\n $Message += \"`nDetail: $AdditionalDetail\"\n }\n \n Write-Error $Message -Category AuthenticationError\n }\n}\n\nWrite-Host \"Created $variablesCreated output variables\"" + }, "Parameters": [ { "Id": "66a70ea0-8d3a-4682-9575-c1dae8ad75e6", @@ -22,6 +22,16 @@ "Octopus.ControlType": "SingleLineText" } }, + { + "Id": "8b77d118-197b-40be-9382-c8ee4d5aae1b", + "Name": "CyberArk.Conjur.TrustCertificate", + "Label": "Trust Server Certificate", + "HelpText": "Trust the server certificate when using an HTTPS connection and the caller cannot verify the Certificate Authority root.\n\nYou can use this option when using self-signed certificates.", + "DefaultValue": "False", + "DisplaySettings": { + "Octopus.ControlType": "Checkbox" + } + }, { "Id": "ceae6659-4643-490d-9d8d-f642c1c1b4a0", "Name": "CyberArk.Conjur.RetrieveSecrets.Account", @@ -75,10 +85,10 @@ ], "StepPackageId": "Octopus.Script", "$Meta": { - "ExportedAt": "2021-10-19T10:19:57.315Z", - "OctopusVersion": "2021.2.7697", + "ExportedAt": "2024-12-12T01:15:33.891Z", + "OctopusVersion": "2025.1.2648", "Type": "ActionTemplate" }, - "LastModifiedBy": "harrisonmeister", + "LastModifiedBy": "twerthi", "Category": "cyberark" - } \ No newline at end of file + }