From 93aee71aa4e0388850ad8a9262f8e8a4a83ae2f8 Mon Sep 17 00:00:00 2001 From: harrisonmeister Date: Thu, 18 Sep 2025 13:30:04 +0100 Subject: [PATCH 1/2] Add GCP Secret Manager - Retrieve Secrets (OIDC) step template This step retrieves one or more secrets from [Secret Manager](https://cloud.google.com/secret-manager) on Google Cloud Platform (GCP), 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 deployment or runbook process steps. You should retrieve secrets with a specific version rather than the *latest* version. You can choose a custom output variable name for each secret, or one will be created dynamically. --- The step authenticates with GCP using an [OpenID Connect](https://octopus.com/docs/infrastructure/accounts/openid-connect) account. See our [blog post](https://octopus.com/blog/generic-oidc#using-generic-oidc-accounts-with-google-cloud) for more details on configuring an account for GCP authentication. --- ...p-secret-manager-retrieve-secret-oidc.json | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 step-templates/gcp-secret-manager-retrieve-secret-oidc.json diff --git a/step-templates/gcp-secret-manager-retrieve-secret-oidc.json b/step-templates/gcp-secret-manager-retrieve-secret-oidc.json new file mode 100644 index 000000000..9c495aa54 --- /dev/null +++ b/step-templates/gcp-secret-manager-retrieve-secret-oidc.json @@ -0,0 +1,92 @@ +{ + "Id": "a0119b66-831b-407e-b87b-45b19afe18a8", + "Name": "GCP Secret Manager - Retrieve Secrets (OIDC)", + "Description": "This step retrieves one or more secrets from [Secret Manager](https://cloud.google.com/secret-manager) on Google Cloud Platform (GCP), 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 deployment or runbook process steps.\n\nYou should retrieve secrets with a specific version rather than the *latest* version. You can choose a custom output variable name for each secret, or one will be created dynamically.\n\n---\n\nThe step authenticates with GCP using an [OpenID Connect](https://octopus.com/docs/infrastructure/accounts/openid-connect) account. See our [blog post](https://octopus.com/blog/generic-oidc#using-generic-oidc-accounts-with-google-cloud) for more details on configuring an account for GCP authentication.\n\n---\n\n**Required:** \n- Octopus Server **2021.2** or higher.\n- PowerShell **5.1** or higher.\n- The Google Cloud (`gcloud`) CLI, version **338.0.0** or higher installed on the target or worker. If the CLI can't be found, the step will fail.\n- A Google account with permissions to retrieve secrets from Secret Manager on Google Cloud. Accessing a secret version requires the **Secret Manager Secret Accessor** role (`roles/secretmanager.secretAccessor`) on the secret, project, folder, or organization. \n\nNotes:\n\n- Tested on Octopus **2025.4**.\n- Tested on both Windows Server 2022 and Ubuntu 22.04.", + "ActionType": "Octopus.GoogleCloudScripting", + "Version": 1, + "CommunityActionTemplateId": null, + "Packages": [], + "GitDependencies": [], + "Properties": { + "Octopus.Action.Script.ScriptSource": "Inline", + "Octopus.Action.Script.Syntax": "PowerShell", + "Octopus.Action.GoogleCloud.ImpersonateServiceAccount": "False", + "Octopus.Action.GoogleCloud.UseVMServiceAccount": "False", + "Octopus.Action.GoogleCloudAccount.Variable": "#{GCP.SecretManager.RetrieveSecrets.Account}", + "Octopus.Action.GoogleCloud.Project": "#{GCP.SecretManager.RetrieveSecrets.Project}", + "Octopus.Action.GoogleCloud.Region": "#{GCP.SecretManager.RetrieveSecrets.Region}", + "Octopus.Action.GoogleCloud.Zone": "#{GCP.SecretManager.RetrieveSecrets.Zone}", + "Octopus.Action.Script.ScriptBody": "$ErrorActionPreference = 'Stop'\n\n# Variables\n$SecretNames = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.SecretNames\"]\n$PrintVariableNames = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.PrintVariableNames\"]\n\n# GCP Project/Region/Zone\n$Project = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Project\"]\n$Region = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Region\"]\n$Zone = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Zone\"]\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($SecretNames)) {\n throw \"Required parameter GCP.SecretManager.RetrieveSecrets.SecretNames not specified\"\n}\n\n$Secrets = @()\n$VariablesCreated = 0\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n\n# Extract secret names\n@(($SecretNames -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 = \"latest\"\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 $secret = [PsCustomObject]@{\n Name = $secretName\n SecretVersion = $secretVersion\n VariableName = if (![string]::IsNullOrWhiteSpace($secretDefinition[1])) { $secretDefinition[1].Trim() } else { \"\" }\n }\n $Secrets += $secret\n }\n}\n\nWrite-Verbose \"GCP Default Project: $Project\"\nWrite-Verbose \"GCP Default Region: $Region\"\nWrite-Verbose \"GCP Default Zone: $Zone\"\nWrite-Verbose \"Secrets to retrieve: $($Secrets.Count)\"\nWrite-Verbose \"Print variables: $PrintVariableNames\"\n\n# Retrieve Secrets\nforeach ($secret in $secrets) {\n $name = $secret.Name\n $secretVersion = $secret.SecretVersion\n $variableName = $secret.VariableName\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim())-$secretVersion\"\n }\n Write-Host \"Retrieving Secret '$name' (version: $secretVersion)\"\n if ($secretVersion -ieq \"latest\") {\n Write-Host \"Note: Retrieving the 'latest' version for secret '$name' isn't recommended. Consider choosing a specific version to retrieve.\"\n }\n \n $secretValue = (gcloud secrets versions access $secretVersion --secret=\"$name\") -Join \"`n\"\n \n if ([string]::IsNullOrWhiteSpace($secretValue)) {\n throw \"Error: Secret '$name' (version: $secretVersion) not found or has no versions.\"\n }\n\n Set-OctopusVariable -Name $variableName -Value $secretValue -Sensitive\n\n if ($PrintVariableNames -eq $True) {\n Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n}\n\nWrite-Host \"Created $variablesCreated output variables\"\n" + }, + "Parameters": [ + { + "Id": "98bef883-493d-45ca-8030-9323340f7b8d", + "Name": "GCP.SecretManager.RetrieveSecrets.Account", + "Label": "OpenID Connect (OIDC) Account", + "HelpText": "An [OpenID Connect](https://octopus.com/docs/infrastructure/accounts/openid-connect) account with permission to access Secret Manager secrets.", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "GenericOidcAccount" + } + }, + { + "Id": "4fce0e10-2378-4008-ace0-0bda4bebef5f", + "Name": "GCP.SecretManager.RetrieveSecrets.Project", + "Label": "Google Cloud Project", + "HelpText": "Specify the default project. This sets the `CLOUDSDK_CORE_PROJECT` [environment variable](https://g.octopushq.com/GCPDefaultProject).", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "SingleLineText" + } + }, + { + "Id": "0775f353-d9c7-4e5f-87d9-15dd4b7126f7", + "Name": "GCP.SecretManager.RetrieveSecrets.Region", + "Label": "Google Cloud Region", + "HelpText": "Specify the default region. View the [GCP Regions and Zones](https://g.octopushq.com/GCPRegionsZones) documentation for a current list of the available region and zone codes.\n\nThis sets the `CLOUDSDK_COMPUTE_REGION` [environment variable](https://g.octopushq.com/GCPDefaultRegionAndZone).", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "SingleLineText" + } + }, + { + "Id": "d575b319-cd58-4200-9211-cddd328c1a62", + "Name": "GCP.SecretManager.RetrieveSecrets.Zone", + "Label": "Google Cloud Zone", + "HelpText": "Specify the default zone. View the [GCP Regions and Zones](https://g.octopushq.com/GCPRegionsZones) documentation for a current list of the available region and zone codes.\n\nThis sets the `CLOUDSDK_COMPUTE_ZONE` [environment variable](https://g.octopushq.com/GCPDefaultRegionAndZone).", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "SingleLineText" + } + }, + { + "Id": "8194e79f-1a22-4126-a7aa-cbd300ef1fda", + "Name": "GCP.SecretManager.RetrieveSecrets.SecretNames", + "Label": "Secret names to retrieve", + "HelpText": "Specify the names of the secrets to be returned from Secret Manager in Google Cloud, in the format:\n\n`SecretName SecretVersion | OutputVariableName` where:\n\n- `SecretName` is the name of the secret to retrieve.\n- `SecretVersion` is the version of the secret to retrieve. *If this value isn't specified, the latest version will be retrieved*.\n- `OutputVariableName` is the _optional_ Octopus [output variable](https://octopus.com/docs/projects/variables/output-variables) name to store the secret's value in. *If this value isn't specified, an output name will be generated dynamically*.\n\n**Note:** Multiple fields can be retrieved by entering each one on a new line.", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "MultiLineText" + } + }, + { + "Id": "24508f90-d88e-4527-b577-8e13c91d962f", + "Name": "GCP.SecretManager.RetrieveSecrets.PrintVariableNames", + "Label": "Print output variable names", + "HelpText": "Write out the Octopus [output variable](https://octopus.com/docs/projects/variables/output-variables) names to the task log. Default: `False`.", + "DefaultValue": "False", + "DisplaySettings": { + "Octopus.ControlType": "Checkbox" + } + } + ], + "StepPackageId": "Octopus.GoogleCloudScripting", + "$Meta": { + "ExportedAt": "2025-09-18T12:25:52.896Z", + "OctopusVersion": "2025.4.1096", + "Type": "ActionTemplate" + }, + "LastModifiedBy": "harrisonmeister", + "Category": "google-cloud", + "MinimumServerVersion": "2021.2.0" +} From f67a26694c06d18ed576464ee4674f76c2c834ce Mon Sep 17 00:00:00 2001 From: harrisonmeister Date: Thu, 18 Sep 2025 15:59:23 +0100 Subject: [PATCH 2/2] Fix case of variable name [nitpick] --- step-templates/gcp-secret-manager-retrieve-secret-oidc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/step-templates/gcp-secret-manager-retrieve-secret-oidc.json b/step-templates/gcp-secret-manager-retrieve-secret-oidc.json index 9c495aa54..bb9e3d4b9 100644 --- a/step-templates/gcp-secret-manager-retrieve-secret-oidc.json +++ b/step-templates/gcp-secret-manager-retrieve-secret-oidc.json @@ -16,7 +16,7 @@ "Octopus.Action.GoogleCloud.Project": "#{GCP.SecretManager.RetrieveSecrets.Project}", "Octopus.Action.GoogleCloud.Region": "#{GCP.SecretManager.RetrieveSecrets.Region}", "Octopus.Action.GoogleCloud.Zone": "#{GCP.SecretManager.RetrieveSecrets.Zone}", - "Octopus.Action.Script.ScriptBody": "$ErrorActionPreference = 'Stop'\n\n# Variables\n$SecretNames = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.SecretNames\"]\n$PrintVariableNames = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.PrintVariableNames\"]\n\n# GCP Project/Region/Zone\n$Project = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Project\"]\n$Region = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Region\"]\n$Zone = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Zone\"]\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($SecretNames)) {\n throw \"Required parameter GCP.SecretManager.RetrieveSecrets.SecretNames not specified\"\n}\n\n$Secrets = @()\n$VariablesCreated = 0\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n\n# Extract secret names\n@(($SecretNames -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 = \"latest\"\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 $secret = [PsCustomObject]@{\n Name = $secretName\n SecretVersion = $secretVersion\n VariableName = if (![string]::IsNullOrWhiteSpace($secretDefinition[1])) { $secretDefinition[1].Trim() } else { \"\" }\n }\n $Secrets += $secret\n }\n}\n\nWrite-Verbose \"GCP Default Project: $Project\"\nWrite-Verbose \"GCP Default Region: $Region\"\nWrite-Verbose \"GCP Default Zone: $Zone\"\nWrite-Verbose \"Secrets to retrieve: $($Secrets.Count)\"\nWrite-Verbose \"Print variables: $PrintVariableNames\"\n\n# Retrieve Secrets\nforeach ($secret in $secrets) {\n $name = $secret.Name\n $secretVersion = $secret.SecretVersion\n $variableName = $secret.VariableName\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim())-$secretVersion\"\n }\n Write-Host \"Retrieving Secret '$name' (version: $secretVersion)\"\n if ($secretVersion -ieq \"latest\") {\n Write-Host \"Note: Retrieving the 'latest' version for secret '$name' isn't recommended. Consider choosing a specific version to retrieve.\"\n }\n \n $secretValue = (gcloud secrets versions access $secretVersion --secret=\"$name\") -Join \"`n\"\n \n if ([string]::IsNullOrWhiteSpace($secretValue)) {\n throw \"Error: Secret '$name' (version: $secretVersion) not found or has no versions.\"\n }\n\n Set-OctopusVariable -Name $variableName -Value $secretValue -Sensitive\n\n if ($PrintVariableNames -eq $True) {\n Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n}\n\nWrite-Host \"Created $variablesCreated output variables\"\n" + "Octopus.Action.Script.ScriptBody": "$ErrorActionPreference = 'Stop'\n\n# Variables\n$SecretNames = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.SecretNames\"]\n$PrintVariableNames = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.PrintVariableNames\"]\n\n# GCP Project/Region/Zone\n$Project = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Project\"]\n$Region = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Region\"]\n$Zone = $OctopusParameters[\"GCP.SecretManager.RetrieveSecrets.Zone\"]\n\n# Validation\nif ([string]::IsNullOrWhiteSpace($SecretNames)) {\n throw \"Required parameter GCP.SecretManager.RetrieveSecrets.SecretNames not specified\"\n}\n\n$Secrets = @()\n$VariablesCreated = 0\n$StepName = $OctopusParameters[\"Octopus.Step.Name\"]\n\n# Extract secret names\n@(($SecretNames -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 = \"latest\"\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 $secret = [PsCustomObject]@{\n Name = $secretName\n SecretVersion = $secretVersion\n VariableName = if (![string]::IsNullOrWhiteSpace($secretDefinition[1])) { $secretDefinition[1].Trim() } else { \"\" }\n }\n $Secrets += $secret\n }\n}\n\nWrite-Verbose \"GCP Default Project: $Project\"\nWrite-Verbose \"GCP Default Region: $Region\"\nWrite-Verbose \"GCP Default Zone: $Zone\"\nWrite-Verbose \"Secrets to retrieve: $($Secrets.Count)\"\nWrite-Verbose \"Print variables: $PrintVariableNames\"\n\n# Retrieve Secrets\nforeach ($secret in $secrets) {\n $name = $secret.Name\n $secretVersion = $secret.SecretVersion\n $variableName = $secret.VariableName\n if ([string]::IsNullOrWhiteSpace($variableName)) {\n $variableName = \"$($name.Trim())-$secretVersion\"\n }\n Write-Host \"Retrieving Secret '$name' (version: $secretVersion)\"\n if ($secretVersion -ieq \"latest\") {\n Write-Host \"Note: Retrieving the 'latest' version for secret '$name' isn't recommended. Consider choosing a specific version to retrieve.\"\n }\n \n $secretValue = (gcloud secrets versions access $secretVersion --secret=\"$name\") -Join \"`n\"\n \n if ([string]::IsNullOrWhiteSpace($secretValue)) {\n throw \"Error: Secret '$name' (version: $secretVersion) not found or has no versions.\"\n }\n\n Set-OctopusVariable -Name $variableName -Value $secretValue -Sensitive\n\n if ($PrintVariableNames -eq $True) {\n Write-Host \"Created output variable: ##{Octopus.Action[$StepName].Output.$variableName}\"\n }\n $VariablesCreated += 1\n}\n\nWrite-Host \"Created $VariablesCreated output variables\"\n" }, "Parameters": [ {