From f4c3052652c058f69fc1401e7e392a7840df931b Mon Sep 17 00:00:00 2001 From: Twerthi Date: Wed, 28 Jan 2026 10:08:21 -0800 Subject: [PATCH] Adding OIDC Azure Account compatibility --- .../azure-create-containerapp-environment.json | 18 ++++++++++++++---- step-templates/azure-deploy-containerapp.json | 18 ++++++++++++++---- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/step-templates/azure-create-containerapp-environment.json b/step-templates/azure-create-containerapp-environment.json index 838e191e3..b4f869e93 100644 --- a/step-templates/azure-create-containerapp-environment.json +++ b/step-templates/azure-create-containerapp-environment.json @@ -3,13 +3,13 @@ "Name": "Azure - Create Container App Environment", "Description": "Creates a Container App Environment if it doesn't exist. An output variable called `ManagedEnvironmentId` is created which holds the Id.", "ActionType": "Octopus.Script", - "Version": 5, + "Version": 6, "CommunityActionTemplateId": null, "Packages": [], "Properties": { "Octopus.Action.Script.ScriptSource": "Inline", "Octopus.Action.Script.Syntax": "PowerShell", - "Octopus.Action.Script.ScriptBody": "# Define functions\nfunction Get-ModuleInstalled\n{\n # Define parameters\n param(\n $PowerShellModuleName\n )\n\n # Check to see if the module is installed\n if ($null -ne (Get-Module -ListAvailable -Name $PowerShellModuleName))\n {\n # It is installed\n return $true\n }\n else\n {\n # Module not installed\n return $false\n }\n}\n\nfunction Get-NugetPackageProviderNotInstalled\n{\n\t# See if the nuget package provider has been installed\n return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n}\n\nfunction Install-PowerShellModule\n{\n # Define parameters\n param(\n $PowerShellModuleName,\n $LocalModulesPath\n )\n\n\t# Check to see if the package provider has been installed\n if ((Get-NugetPackageProviderNotInstalled) -ne $false)\n {\n \t# Display that we need the nuget package provider\n Write-Host \"Nuget package provider not found, installing ...\"\n \n # Install Nuget package provider\n Install-PackageProvider -Name Nuget -Force\n }\n\n\t# Save the module in the temporary location\n Write-Host \"Saving module $PowerShellModuleName to temporary folder ...\"\n Save-Module -Name $PowerShellModuleName -Path $LocalModulesPath -Force\n Write-Host \"Save successful!\"\n}\n\n# Check to see if $IsWindows is available\n# Check to see if $IsWindows is available\nif ($null -eq $IsWindows)\n{\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\n# Check to see if it's running on Windows\nif ($IsWindows)\n{\n\t# Disable the progress bar so downloading files via Invoke-WebRequest are faster\n $ProgressPreference = 'SilentlyContinue'\n}\n\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\n# Define PowerShell Modules path\n$LocalModules = (New-Item \"$PWD/Modules\" -ItemType Directory -Force).FullName\n$env:PSModulePath = \"$LocalModules$([IO.Path]::PathSeparator)$env:PSModulePath\"\n$azureModule = \"Az.App\"\n\n# Get variables\n$templateAzureAccountClient = $OctopusParameters['Template.Azure.Account.ClientId']\n$templateAzureAccountPassword = $OctopusParameters['Template.Azure.Account.Password']\n$templateAzureAccountTenantId = $OctopusParameters['Template.Azure.Account.TenantId']\n$templateAzureResourceGroup = $OctopusParameters['Template.Azure.ResourceGroup.Name']\n$templateAzureSubscriptionId = $OctopusParameters['Template.Azure.Account.SubscriptionId']\n$templateEnvironmentName = $OctopusParameters['Template.ContainerApp.Environment.Name']\n$templateAzureLocation = $OctopusParameters['Template.Azure.Location.Name']\n\n# Check for required PowerShell module\nWrite-Host \"Checking for module $azureModule ...\"\n\nif ((Get-ModuleInstalled -PowerShellModuleName $azureModule) -eq $false)\n{\n\t# Install the module\n Install-PowerShellModule -PowerShellModuleName $azureModule -LocalModulesPath $LocalModules\n}\n\n# Import the necessary module\nWrite-Host \"Importing module $azureModule ...\"\nImport-Module $azureModule\n\n# Check to see if the account was specified\nif (![string]::IsNullOrWhitespace($templateAzureAccountClient))\n{\n\t# Login using the provided account\n Write-Host \"Logging in as specified account ...\"\n \n\t# Create credential object for az module\n\t$securePassword = ConvertTo-SecureString $templateAzureAccountPassword -AsPlainText -Force\n\t$azureCredentials = New-Object System.Management.Automation.PSCredential ($templateAzureAccountClient, $securePassword) \n\n Connect-AzAccount -Credential $azureCredentials -ServicePrincipal -Tenant $templateAzureAccountTenantId -Subscription $templateAzureSubscriptionId | Out-Null\n \n Write-Host \"Login successful!\"\n}\nelse\n{\n\tWrite-Host \"Using machine Managed Identity ...\"\n Connect-AzAccount -Identity | Out-Null\n \n # Get Identity context\n $identityContext = Get-AzContext\n \n # Set variables\n $templateAzureSubscriptionId = $identityContext.Subscription\n \n if ([string]::IsNullOrWhitespace($templateAzureAccountTenantId))\n {\n \t$templateAzureAccountTenantId = $identityContext.Tenant\n }\n \n Set-AzContext -Tenant $templateAzureAccountTenantId | Out-Null\n\n\tWrite-Host \"Successfully set context for Managed Identity!\"\n}\n\n# Check to see if Container App Environment already exists\nWrite-Host \"Getting list of existing environments ...\"\n$existingEnvironments = Get-AzContainerAppManagedEnv -ResourceGroupName $templateAzureResourceGroup -SubscriptionId $templateAzureSubscriptionId\n$managedEnvironment = $null\n\nif (($null -ne $existingEnvironments) -and ($null -ne ($existingEnvironments | Where-Object {$_.Name -eq $templateEnvironmentName})))\n{\n\tWrite-Host \"Environment $templateEnvironmentName already exists.\"\n $managedEnvironment = $existingEnvironments | Where-Object {$_.Name -eq $templateEnvironmentName}\n}\nelse\n{\n\tWrite-Host \"Environment $templateEnvironmentName not found, creating ...\"\n $managedEnvironment = New-AzContainerAppManagedEnv -EnvName $templateEnvironmentName -ResourceGroupName $templateAzureResourceGroup -Location $templateAzureLocation -AppLogConfigurationDestination \"\" # Empty AppLogConfigurationDestination is workaround for properties issue caused by marking this as required\n}\n\n# Set output variable\nWrite-Host \"Setting output variable ManagedEnvironmentId to $($managedEnvironment.Id)\"\nSet-OctopusVariable -name \"ManagedEnvironmentId\" -value \"$($managedEnvironment.Id)\"" + "Octopus.Action.Script.ScriptBody": "# Define functions\nfunction Get-ModuleInstalled\n{\n # Define parameters\n param(\n $PowerShellModuleName\n )\n\n # Check to see if the module is installed\n if ($null -ne (Get-Module -ListAvailable -Name $PowerShellModuleName))\n {\n # It is installed\n return $true\n }\n else\n {\n # Module not installed\n return $false\n }\n}\n\nfunction Get-NugetPackageProviderNotInstalled\n{\n\t# See if the nuget package provider has been installed\n return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n}\n\nfunction Install-PowerShellModule\n{\n # Define parameters\n param(\n $PowerShellModuleName,\n $LocalModulesPath\n )\n\n\t# Check to see if the package provider has been installed\n if ((Get-NugetPackageProviderNotInstalled) -ne $false)\n {\n \t# Display that we need the nuget package provider\n Write-Host \"Nuget package provider not found, installing ...\"\n \n # Install Nuget package provider\n Install-PackageProvider -Name Nuget -Force\n }\n\n\t# Save the module in the temporary location\n Write-Host \"Saving module $PowerShellModuleName to temporary folder ...\"\n Save-Module -Name $PowerShellModuleName -Path $LocalModulesPath -Force\n Write-Host \"Save successful!\"\n}\n\n# Check to see if $IsWindows is available\nif ($null -eq $IsWindows)\n{\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\n# Check to see if it's running on Windows\nif ($IsWindows)\n{\n\t# Disable the progress bar so downloading files via Invoke-WebRequest are faster\n $ProgressPreference = 'SilentlyContinue'\n}\n\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\n# Define PowerShell Modules path\n$LocalModules = (New-Item \"$PWD/Modules\" -ItemType Directory -Force).FullName\n$env:PSModulePath = \"$LocalModules$([IO.Path]::PathSeparator)$env:PSModulePath\"\n$azureModule = \"Az.App\"\n\n# Get variables\n$templateAzureAccountClient = $OctopusParameters['Template.Azure.Account.ClientId']\n$templateAzureAccountPassword = $OctopusParameters['Template.Azure.Account.Password']\n$templateAzureAccountTenantId = $OctopusParameters['Template.Azure.Account.TenantId']\n$templateAzureResourceGroup = $OctopusParameters['Template.Azure.ResourceGroup.Name']\n$templateAzureSubscriptionId = $OctopusParameters['Template.Azure.Account.SubscriptionId']\n$templateEnvironmentName = $OctopusParameters['Template.ContainerApp.Environment.Name']\n$templateAzureLocation = $OctopusParameters['Template.Azure.Location.Name']\n$templateAzureJWTToken = $OctopusParameters['Template.Azure.Account.JWTToken']\n\n# Check for required PowerShell module\nWrite-Host \"Checking for module $azureModule ...\"\n\nif ((Get-ModuleInstalled -PowerShellModuleName $azureModule) -eq $false)\n{\n\t# Install the module\n Install-PowerShellModule -PowerShellModuleName $azureModule -LocalModulesPath $LocalModules\n}\n\n# Import the necessary module\nWrite-Host \"Importing module $azureModule ...\"\nImport-Module $azureModule\n\n# Check to see if the account was specified\nif (![string]::IsNullOrWhitespace($templateAzureAccountClient))\n{\n\t# Login using the provided account\n Write-Host \"Logging in as specified account ...\"\n\n # Check to see if jwt token was provided\n if (![string]::IsNullOrWhitespace($templateAzureJWTToken))\n {\n # Log in with OIDC\n Write-Host \"Logging in using OIDC ...\"\n\n # Log in\n Connect-AzAccount -FederatedToken $templateAzureJWTToken -ApplicationId $templateAzureAccountClient -Tenant $templateAzureAccountTenantId -Subscription $templateAzureSubscriptionId | Out-Null \n }\n\n if (![string]::IsNullOrWhitespace($templateAzureAccountPassword))\n {\n # Log in with Azure Service Principal\n Write-Host \"Logging in with Azure Service Principal ...\"\n \n # Create credential object for az module\n\t $securePassword = ConvertTo-SecureString $templateAzureAccountPassword -AsPlainText -Force\n\t $azureCredentials = New-Object System.Management.Automation.PSCredential ($templateAzureAccountClient, $securePassword) \n\n Connect-AzAccount -Credential $azureCredentials -ServicePrincipal -Tenant $templateAzureAccountTenantId -Subscription $templateAzureSubscriptionId | Out-Null\n } \n \n Write-Host \"Login successful!\"\n}\nelse\n{\n\tWrite-Host \"Using machine Managed Identity ...\"\n Connect-AzAccount -Identity | Out-Null\n \n # Get Identity context\n $identityContext = Get-AzContext\n \n # Set variables\n $templateAzureSubscriptionId = $identityContext.Subscription\n \n if ([string]::IsNullOrWhitespace($templateAzureAccountTenantId))\n {\n \t$templateAzureAccountTenantId = $identityContext.Tenant\n }\n \n Set-AzContext -Tenant $templateAzureAccountTenantId | Out-Null\n\n\tWrite-Host \"Successfully set context for Managed Identity!\"\n}\n\n# Check to see if Container App Environment already exists\nWrite-Host \"Getting list of existing environments ...\"\n$existingEnvironments = Get-AzContainerAppManagedEnv -ResourceGroupName $templateAzureResourceGroup -SubscriptionId $templateAzureSubscriptionId\n$managedEnvironment = $null\n\nif (($null -ne $existingEnvironments) -and ($null -ne ($existingEnvironments | Where-Object {$_.Name -eq $templateEnvironmentName})))\n{\n\tWrite-Host \"Environment $templateEnvironmentName already exists.\"\n $managedEnvironment = $existingEnvironments | Where-Object {$_.Name -eq $templateEnvironmentName}\n}\nelse\n{\n\tWrite-Host \"Environment $templateEnvironmentName not found, creating ...\"\n $managedEnvironment = New-AzContainerAppManagedEnv -EnvName $templateEnvironmentName -ResourceGroupName $templateAzureResourceGroup -Location $templateAzureLocation -AppLogConfigurationDestination \"\" # Empty AppLogConfigurationDestination is workaround for properties issue caused by marking this as required\n}\n\n# Set output variable\nWrite-Host \"Setting output variable ManagedEnvironmentId to $($managedEnvironment.Id)\"\nSet-OctopusVariable -name \"ManagedEnvironmentId\" -value \"$($managedEnvironment.Id)\"" }, "Parameters": [ { @@ -62,6 +62,16 @@ "Octopus.ControlType": "Sensitive" } }, + { + "Id": "a4a216e0-0ba5-4dd9-b759-6c7121eda110", + "Name": "Template.Azure.Account.JWTToken", + "Label": "Azure Account JWT Token", + "HelpText": "The JWT token of the Azure account to use. This value can be retrieved from an Azure Account variable type. Add an Azure Account to your project , then assign the `OpenIdConnect.Jwt` property to for this entry. Leave blank if you're using an Azure Service Principal account type.\n\nFor example, if your Azure Account variable is called MyAccount, the value for this input would be `#{MyAccount.OpenIdConnect.Jwt}`", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "SingleLineText" + } + }, { "Id": "66f5ee93-3ba9-44e7-8a04-50535b1907cb", "Name": "Template.ContainerApp.Environment.Name", @@ -85,8 +95,8 @@ ], "StepPackageId": "Octopus.Script", "$Meta": { - "ExportedAt": "2025-03-26T15:16:57.216Z", - "OctopusVersion": "2025.1.9982", + "ExportedAt": "2026-01-28T16:54:33.969Z", + "OctopusVersion": "2026.1.5902", "Type": "ActionTemplate" }, "LastModifiedBy": "twerthi", diff --git a/step-templates/azure-deploy-containerapp.json b/step-templates/azure-deploy-containerapp.json index de0536e4f..3a9aa336c 100644 --- a/step-templates/azure-deploy-containerapp.json +++ b/step-templates/azure-deploy-containerapp.json @@ -3,7 +3,7 @@ "Name": "Azure - Deploy Container App", "Description": "Deploys a container to an Azure Container App Environment", "ActionType": "Octopus.Script", - "Version": 7, + "Version": 8, "CommunityActionTemplateId": null, "Packages": [ { @@ -23,7 +23,7 @@ "Properties": { "Octopus.Action.Script.ScriptSource": "Inline", "Octopus.Action.Script.Syntax": "PowerShell", - "Octopus.Action.Script.ScriptBody": "# Define functions\nfunction Get-ModuleInstalled\n{\n # Define parameters\n param(\n $PowerShellModuleName\n )\n\n # Check to see if the module is installed\n if ($null -ne (Get-Module -ListAvailable -Name $PowerShellModuleName))\n {\n # It is installed\n return $true\n }\n else\n {\n # Module not installed\n return $false\n }\n}\n\nfunction Get-NugetPackageProviderNotInstalled\n{\n\t# See if the nuget package provider has been installed\n return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n}\n\nfunction Install-PowerShellModule\n{\n # Define parameters\n param(\n $PowerShellModuleName,\n $LocalModulesPath\n )\n\n\t# Check to see if the package provider has been installed\n if ((Get-NugetPackageProviderNotInstalled) -ne $false)\n {\n \t# Display that we need the nuget package provider\n Write-Host \"Nuget package provider not found, installing ...\"\n \n # Install Nuget package provider\n Install-PackageProvider -Name Nuget -Force\n }\n\n\t# Save the module in the temporary location\n Write-Host \"Saving module $PowerShellModuleName to temporary folder ...\"\n Save-Module -Name $PowerShellModuleName -Path $LocalModulesPath -Force\n Write-Host \"Save successful!\"\n}\n\n# Check to see if $IsWindows is available\nif ($null -eq $IsWindows)\n{\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\n# Check to see if it's running on Windows\nif ($IsWindows)\n{\n\t# Disable the progress bar so downloading files via Invoke-WebRequest are faster\n $ProgressPreference = 'SilentlyContinue'\n}\n\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\n# Define PowerShell Modules path\n$LocalModules = (New-Item \"$PWD/modules\" -ItemType Directory -Force).FullName\n$env:PSModulePath = \"$LocalModules$([IO.Path]::PathSeparator)$env:PSModulePath\"\n$azureModule = \"Az.App\"\n\n# Get variables\n$templateAzureAccountClient = $OctopusParameters['Template.Azure.Account.ClientId']\n$templateAzureAccountPassword = $OctopusParameters['Template.Azure.Account.Password']\n$templateAzureAccountTenantId = $OctopusParameters['Template.Azure.Account.TenantId']\n$templateAzureResourceGroup = $OctopusParameters['Template.Azure.ResourceGroup.Name']\n$templateAzureSubscriptionId = $OctopusParameters['Template.Azure.Account.SubscriptionId']\n$templateEnvironmentName = $OctopusParameters['Template.ContainerApp.Environment.Name']\n$templateAzureLocation = $OctopusParameters['Template.Azure.Location.Name']\n$templateAzureContainer = $OctopusParameters['Template.Azure.Container.Image']\n$templateAzureContainerIngressPort = $OctopusParameters['Template.Azure.Container.Ingress.Port']\n$templateAzureContainerIngressExternal = $OctopusParameters['Template.Azure.Container.ExternalIngress']\n$vmMetaData = $null\n$secretRef = @()\n$templateAzureContainerSecrets = $null\n\nif (![string]::IsNullOrWhitespace($OctopusParameters['Template.Azure.Container.Variables']))\n{\n $templateAzureContainerEnvVars = ($OctopusParameters['Template.Azure.Container.Variables'] | ConvertFrom-JSON)\n}\nelse\n{\n\t$templateAzureContainerEnvVars = $null\n}\n\nif (![string]::IsNullOrWhitespace($OctopusParameters['Template.Azure.Container.Secrets']))\n{\n $templateAzureContainerSecrets = ($OctopusParameters['Template.Azure.Container.Secrets'] | ConvertFrom-JSON)\n}\nelse\n{\n\t$templateAzureContainerSecrets = $null\n}\n\n$templateAzureContainerCPU = $OctopusParameters['Template.Azure.Container.Cpu']\n$templateAzureContainerMemory = $OctopusParameters['Template.Azure.Container.Memory']\n\n# Check for required PowerShell module\nWrite-Host \"Checking for module $azureModule ...\"\n\nif ((Get-ModuleInstalled -PowerShellModuleName $azureModule) -eq $false)\n{\n\t# Install the module\n Install-PowerShellModule -PowerShellModuleName $azureModule -LocalModulesPath $LocalModules\n}\n\n# Import the necessary module\nWrite-Host \"Importing module $azureModule ...\"\nImport-Module $azureModule\n\n# Check to see if the account was specified\nif (![string]::IsNullOrWhitespace($templateAzureAccountClient))\n{\n\t# Login using the provided account\n Write-Host \"Logging in as specified account ...\"\n \n\t# Create credential object for az module\n\t$securePassword = ConvertTo-SecureString $templateAzureAccountPassword -AsPlainText -Force\n\t$azureCredentials = New-Object System.Management.Automation.PSCredential ($templateAzureAccountClient, $securePassword) \n\n Connect-AzAccount -Credential $azureCredentials -ServicePrincipal -Tenant $templateAzureAccountTenantId -Subscription $templateAzureSubscriptionId | Out-Null\n \n Write-Host \"Login successful!\"\n}\nelse\n{\n\tWrite-Host \"Using machine Managed Identity ...\"\n $vmMetaData = Invoke-RestMethod -Headers @{\"Metadata\"=\"true\"} -Method GET -Uri \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\"\n \n Connect-AzAccount -Identity\n \n # Get Identity context\n $identityContext = Get-AzContext\n \n # Set variables\n $templateAzureSubscriptionId = $vmMetaData.compute.subscriptionId\n \n if ([string]::IsNullOrWhitespace($templateAzureAccountTenantId))\n {\n \t$templateAzureAccountTenantId = $identityContext.Tenant\n }\n \n Set-AzContext -Tenant $templateAzureAccountTenantId | Out-Null\n\tWrite-Host \"Successfully set context for Managed Identity!\"\n}\n\n# Check to see if the environment name is a / in it\nif ($templateEnvironmentName.Contains(\"/\") -ne $true)\n{\n\t# Lookup environment id by name\n Write-Host \"Looking up Managed Environment by Name ...\"\n $templateEnvironmentName = (Get-AzContainerAppManagedEnv -ResourceGroupName $templateAzureResourceGroup -EnvName $templateEnvironmentName -SubscriptionId $templateAzureSubscriptionId).Id\n}\n\n# Build parameter list to pass to New-AzContainerAppTemplateObject\n$PSBoundParameters.Add(\"Image\", $OctopusParameters[\"Octopus.Action.Package[Template.Azure.Container.Image].Image\"])\n$PSBoundParameters.Add(\"Name\", $OctopusParameters[\"Template.Azure.Container.Name\"])\n\nif (![string]::IsNullOrWhitespace($templateAzureContainerCPU))\n{\n $PSBoundParameters.Add(\"ResourceCpu\", \"$templateAzureContainerCPU\")\n}\n\nif (![string]::IsNullOrWhitespace($templateAzureContainerMemory))\n{\n $PSBoundParameters.Add(\"ResourceMemory\", \"$templateAzureContainerMemory\")\n}\n\nif ($null -ne $templateAzureContainerEnvVars)\n{\n # Loop through list\n $envVars = @()\n foreach ($envVar in $templateAzureContainerEnvVars)\n {\n \t$envEntry = @{}\n $envEntry.Add(\"Name\", $envVar.Name)\n \n # Check for specific property\n if ($envVar.SecretRef)\n {\n \t$envEntry.Add(\"SecretRef\", $envVar.SecretRef)\n }\n else\n {\n \t$envEntry.Add(\"Value\", $envVar.Value)\n }\n \n # Add to collection\n $envVars += $envEntry\n }\n \n $PSBoundParameters.Add(\"Env\", $envVars)\n}\n\nif ($null -ne $templateAzureContainerSecrets)\n{\n\t# Loop through list\n foreach ($secret in $templateAzureContainerSecrets)\n {\n # Create new secret object and add to array\n $secretRef += New-AzContainerAppSecretObject -Name $secret.Name -Value $secret.Value\n }\n}\n\n# Create new container app\n$containerDefinition = New-AzContainerAppTemplateObject @PSBoundParameters\n$PSBoundParameters.Clear()\n\n# Define ingress components\nif (![string]::IsNullOrWhitespace($templateAzureContainerIngressPort))\n{\n\t$PSBoundParameters.Add(\"IngressExternal\", [System.Convert]::ToBoolean($templateAzureContainerIngressExternal))\n $PSBoundParameters.Add(\"IngressTargetPort\", $templateAzureContainerIngressPort)\n}\n\n# Check the image\nif ($OctopusParameters[\"Octopus.Action.Package[Template.Azure.Container.Image].Image\"].Contains(\"azurecr.io\"))\n{\n\t# Define local parameters\n $registryCredentials = @{}\n $registrySecret = @{}\n \n # Accessing an ACR repository, configure credentials\n if (![string]::IsNullOrWhitespace($templateAzureAccountClient))\n {\n\n\t\t# Use configured client, name must be lower case\n $registryCredentials.Add(\"Username\", $templateAzureAccountClient)\n $registryCredentials.Add(\"PasswordSecretRef\", \"clientpassword\")\n\n\t\t$secretRef += New-AzContainerAppSecretObject -Name \"clientpassword\" -Value $templateAzureAccountPassword\n }\n else\n {\n \t# Using Managed Identity\n $registryCredentials.Add(\"Identity\", \"system\")\n \n }\n \n $registryServer = $OctopusParameters[\"Octopus.Action.Package[Template.Azure.Container.Image].Image\"]\n $registryServer = $registryServer.Substring(0, $registryServer.IndexOf(\"/\"))\n $registryCredentials.Add(\"Server\", $registryServer)\n \n # Add credentials\n $PSBoundParameters.Add(\"Registry\", $registryCredentials)\n}\n\n# Define secrets component\nif ($secretRef.Count -gt 0)\n{\n\t# Add to parameters\n $PSBoundParameters.Add(\"Secret\", $secretRef)\n}\n\n# Create new configuration object\nWrite-Host \"Creating new Configuration Object ...\"\n$configurationObject = New-AzContainerAppConfigurationObject @PSBoundParameters\n$PSBoundParameters.Clear()\n\n# Define parameters\n$PSBoundParameters.Add(\"Name\", $OctopusParameters[\"Template.Azure.Container.Name\"])\n$PSBoundParameters.Add(\"TemplateContainer\", $containerDefinition)\n$PSBoundParameters.Add(\"ResourceGroupName\", $templateAzureResourceGroup)\n$PSBoundParameters.Add(\"Configuration\", $configurationObject)\n\n\n# Check to see if the container app already exists\n$containerApps = Get-AzContainerApp -ResourceGroupName $templateAzureResourceGroup\n\nif ($null -eq $containerApps)\n{\n $containerApp = $null\n}\nelse\n{\n $containerApp = ($containerApps | Where-Object {$_.Name -eq $OctopusParameters[\"Template.Azure.Container.Name\"]})\n}\n\nif ($null -eq $containerApp)\n{\n\t# Add parameters required for creating container app\n\t$PSBoundParameters.Add(\"EnvironmentId\", $templateEnvironmentName)\n\t$PSBoundParameters.Add(\"Location\", $templateAzureLocation)\n\t\n\t# Deploy container\n Write-Host \"Creating new container app ...\"\n\tNew-AzContainerApp @PSBoundParameters\n}\nelse\n{\n\tWrite-Host \"Updating existing container app ...\"\n Update-AzContainerApp @PSBoundParameters\n}\n" + "Octopus.Action.Script.ScriptBody": "# Define functions\nfunction Get-ModuleInstalled\n{\n # Define parameters\n param(\n $PowerShellModuleName\n )\n\n # Check to see if the module is installed\n if ($null -ne (Get-Module -ListAvailable -Name $PowerShellModuleName))\n {\n # It is installed\n return $true\n }\n else\n {\n # Module not installed\n return $false\n }\n}\n\nfunction Get-NugetPackageProviderNotInstalled\n{\n\t# See if the nuget package provider has been installed\n return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n}\n\nfunction Install-PowerShellModule\n{\n # Define parameters\n param(\n $PowerShellModuleName,\n $LocalModulesPath\n )\n\n\t# Check to see if the package provider has been installed\n if ((Get-NugetPackageProviderNotInstalled) -ne $false)\n {\n \t# Display that we need the nuget package provider\n Write-Host \"Nuget package provider not found, installing ...\"\n \n # Install Nuget package provider\n Install-PackageProvider -Name Nuget -Force\n }\n\n\t# Save the module in the temporary location\n Write-Host \"Saving module $PowerShellModuleName to temporary folder ...\"\n Save-Module -Name $PowerShellModuleName -Path $LocalModulesPath -Force\n Write-Host \"Save successful!\"\n}\n\n# Check to see if $IsWindows is available\nif ($null -eq $IsWindows)\n{\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\n# Check to see if it's running on Windows\nif ($IsWindows)\n{\n\t# Disable the progress bar so downloading files via Invoke-WebRequest are faster\n $ProgressPreference = 'SilentlyContinue'\n}\n\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\n# Define PowerShell Modules path\n$LocalModules = (New-Item \"$PWD/modules\" -ItemType Directory -Force).FullName\n$env:PSModulePath = \"$LocalModules$([IO.Path]::PathSeparator)$env:PSModulePath\"\n$azureModule = \"Az.App\"\n\n# Get variables\n$templateAzureAccountClient = $OctopusParameters['Template.Azure.Account.ClientId']\n$templateAzureAccountPassword = $OctopusParameters['Template.Azure.Account.Password']\n$templateAzureAccountTenantId = $OctopusParameters['Template.Azure.Account.TenantId']\n$templateAzureResourceGroup = $OctopusParameters['Template.Azure.ResourceGroup.Name']\n$templateAzureSubscriptionId = $OctopusParameters['Template.Azure.Account.SubscriptionId']\n$templateEnvironmentName = $OctopusParameters['Template.ContainerApp.Environment.Name']\n$templateAzureLocation = $OctopusParameters['Template.Azure.Location.Name']\n$templateAzureContainer = $OctopusParameters['Template.Azure.Container.Image']\n$templateAzureContainerIngressPort = $OctopusParameters['Template.Azure.Container.Ingress.Port']\n$templateAzureContainerIngressExternal = $OctopusParameters['Template.Azure.Container.ExternalIngress']\n$vmMetaData = $null\n$secretRef = @()\n$templateAzureContainerSecrets = $null\n$templateAzureJWTToken = $OctopusParameters['Template.Azure.Account.JWTToken']\n\nif (![string]::IsNullOrWhitespace($OctopusParameters['Template.Azure.Container.Variables']))\n{\n $templateAzureContainerEnvVars = ($OctopusParameters['Template.Azure.Container.Variables'] | ConvertFrom-JSON)\n}\nelse\n{\n\t$templateAzureContainerEnvVars = $null\n}\n\nif (![string]::IsNullOrWhitespace($OctopusParameters['Template.Azure.Container.Secrets']))\n{\n $templateAzureContainerSecrets = ($OctopusParameters['Template.Azure.Container.Secrets'] | ConvertFrom-JSON)\n}\nelse\n{\n\t$templateAzureContainerSecrets = $null\n}\n\n$templateAzureContainerCPU = $OctopusParameters['Template.Azure.Container.Cpu']\n$templateAzureContainerMemory = $OctopusParameters['Template.Azure.Container.Memory']\n\n# Check for required PowerShell module\nWrite-Host \"Checking for module $azureModule ...\"\n\nif ((Get-ModuleInstalled -PowerShellModuleName $azureModule) -eq $false)\n{\n\t# Install the module\n Install-PowerShellModule -PowerShellModuleName $azureModule -LocalModulesPath $LocalModules\n}\n\n# Import the necessary module\nWrite-Host \"Importing module $azureModule ...\"\nImport-Module $azureModule\n\n# Check to see if the account was specified\nif (![string]::IsNullOrWhitespace($templateAzureAccountClient))\n{\n\t# Login using the provided account\n Write-Host \"Logging in as specified account ...\"\n\n # Check to see if the jtw token was given\n if (![string]::IsNullOrWhitespace($templateAzureJWTToken))\n {\n # Log in with OIDC\n Write-Host \"Logging in using OIDC ...\"\n\n \n # Log in\n Connect-AzAccount -FederatedToken $templateAzureJWTToken -ApplicationId $templateAzureAccountClient -Tenant $templateAzureAccountTenantId -Subscription $templateAzureSubscriptionId | Out-Null \n }\n\n if (![string]::IsNullOrWhitespace($templateAzureAccountPassword))\n {\n # Log in with Azure Service Principal\n Write-Host \"Logging in with Azure Service Principal ...\"\n \n # Create credential object for az module\n\t $securePassword = ConvertTo-SecureString $templateAzureAccountPassword -AsPlainText -Force\n\t $azureCredentials = New-Object System.Management.Automation.PSCredential ($templateAzureAccountClient, $securePassword) \n\n Connect-AzAccount -Credential $azureCredentials -ServicePrincipal -Tenant $templateAzureAccountTenantId -Subscription $templateAzureSubscriptionId | Out-Null\n } \n \n Write-Host \"Login successful!\"\n}\nelse\n{\n\tWrite-Host \"Using machine Managed Identity ...\"\n $vmMetaData = Invoke-RestMethod -Headers @{\"Metadata\"=\"true\"} -Method GET -Uri \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\"\n \n Connect-AzAccount -Identity\n \n # Get Identity context\n $identityContext = Get-AzContext\n \n # Set variables\n $templateAzureSubscriptionId = $vmMetaData.compute.subscriptionId\n \n if ([string]::IsNullOrWhitespace($templateAzureAccountTenantId))\n {\n \t$templateAzureAccountTenantId = $identityContext.Tenant\n }\n \n Set-AzContext -Tenant $templateAzureAccountTenantId | Out-Null\n\tWrite-Host \"Successfully set context for Managed Identity!\"\n}\n\n# Check to see if the environment name is a / in it\nif ($templateEnvironmentName.Contains(\"/\") -ne $true)\n{\n\t# Lookup environment id by name\n Write-Host \"Looking up Managed Environment by Name ...\"\n $templateEnvironmentName = (Get-AzContainerAppManagedEnv -ResourceGroupName $templateAzureResourceGroup -EnvName $templateEnvironmentName -SubscriptionId $templateAzureSubscriptionId).Id\n}\n\n# Build parameter list to pass to New-AzContainerAppTemplateObject\n$PSBoundParameters.Add(\"Image\", $OctopusParameters[\"Octopus.Action.Package[Template.Azure.Container.Image].Image\"])\n$PSBoundParameters.Add(\"Name\", $OctopusParameters[\"Template.Azure.Container.Name\"])\n\nif (![string]::IsNullOrWhitespace($templateAzureContainerCPU))\n{\n $PSBoundParameters.Add(\"ResourceCpu\", \"$templateAzureContainerCPU\")\n}\n\nif (![string]::IsNullOrWhitespace($templateAzureContainerMemory))\n{\n $PSBoundParameters.Add(\"ResourceMemory\", \"$templateAzureContainerMemory\")\n}\n\nif ($null -ne $templateAzureContainerEnvVars)\n{\n # Loop through list\n $envVars = @()\n foreach ($envVar in $templateAzureContainerEnvVars)\n {\n \t$envEntry = @{}\n $envEntry.Add(\"Name\", $envVar.Name)\n \n # Check for specific property\n if ($envVar.SecretRef)\n {\n \t$envEntry.Add(\"SecretRef\", $envVar.SecretRef)\n }\n else\n {\n \t$envEntry.Add(\"Value\", $envVar.Value)\n }\n \n # Add to collection\n $envVars += $envEntry\n }\n \n $PSBoundParameters.Add(\"Env\", $envVars)\n}\n\nif ($null -ne $templateAzureContainerSecrets)\n{\n\t# Loop through list\n foreach ($secret in $templateAzureContainerSecrets)\n {\n # Create new secret object and add to array\n $secretRef += New-AzContainerAppSecretObject -Name $secret.Name -Value $secret.Value\n }\n}\n\n# Create new container app\n$containerDefinition = New-AzContainerAppTemplateObject @PSBoundParameters\n$PSBoundParameters.Clear()\n\n# Define ingress components\nif (![string]::IsNullOrWhitespace($templateAzureContainerIngressPort))\n{\n\t$PSBoundParameters.Add(\"IngressExternal\", [System.Convert]::ToBoolean($templateAzureContainerIngressExternal))\n $PSBoundParameters.Add(\"IngressTargetPort\", $templateAzureContainerIngressPort)\n}\n\n# Check the image\nif ($OctopusParameters[\"Octopus.Action.Package[Template.Azure.Container.Image].Image\"].Contains(\"azurecr.io\"))\n{\n\t# Define local parameters\n $registryCredentials = @{}\n $registrySecret = @{}\n \n # Accessing an ACR repository, configure credentials\n if (![string]::IsNullOrWhitespace($templateAzureAccountClient))\n {\n\n\t\t# Use configured client, name must be lower case\n $registryCredentials.Add(\"Username\", $templateAzureAccountClient)\n $registryCredentials.Add(\"PasswordSecretRef\", \"clientpassword\")\n\n\t\t$secretRef += New-AzContainerAppSecretObject -Name \"clientpassword\" -Value $templateAzureAccountPassword\n }\n else\n {\n \t# Using Managed Identity\n $registryCredentials.Add(\"Identity\", \"system\")\n \n }\n \n $registryServer = $OctopusParameters[\"Octopus.Action.Package[Template.Azure.Container.Image].Image\"]\n $registryServer = $registryServer.Substring(0, $registryServer.IndexOf(\"/\"))\n $registryCredentials.Add(\"Server\", $registryServer)\n \n # Add credentials\n $PSBoundParameters.Add(\"Registry\", $registryCredentials)\n}\n\n# Define secrets component\nif ($secretRef.Count -gt 0)\n{\n\t# Add to parameters\n $PSBoundParameters.Add(\"Secret\", $secretRef)\n}\n\n# Create new configuration object\nWrite-Host \"Creating new Configuration Object ...\"\n$configurationObject = New-AzContainerAppConfigurationObject @PSBoundParameters\n$PSBoundParameters.Clear()\n\n# Define parameters\n$PSBoundParameters.Add(\"Name\", $OctopusParameters[\"Template.Azure.Container.Name\"])\n$PSBoundParameters.Add(\"TemplateContainer\", $containerDefinition)\n$PSBoundParameters.Add(\"ResourceGroupName\", $templateAzureResourceGroup)\n$PSBoundParameters.Add(\"Configuration\", $configurationObject)\n\n\n# Check to see if the container app already exists\n$containerApps = Get-AzContainerApp -ResourceGroupName $templateAzureResourceGroup\n\nif ($null -eq $containerApps)\n{\n $containerApp = $null\n}\nelse\n{\n $containerApp = ($containerApps | Where-Object {$_.Name -eq $OctopusParameters[\"Template.Azure.Container.Name\"]})\n}\n\nif ($null -eq $containerApp)\n{\n\t# Add parameters required for creating container app\n\t$PSBoundParameters.Add(\"EnvironmentId\", $templateEnvironmentName)\n\t$PSBoundParameters.Add(\"Location\", $templateAzureLocation)\n\t\n\t# Deploy container\n Write-Host \"Creating new container app ...\"\n\tNew-AzContainerApp @PSBoundParameters\n}\nelse\n{\n\tWrite-Host \"Updating existing container app ...\"\n Update-AzContainerApp @PSBoundParameters\n}\n" }, "Parameters": [ { @@ -76,6 +76,16 @@ "Octopus.ControlType": "Sensitive" } }, + { + "Id": "79b217e1-f2c4-476b-a37a-02a549731e1a", + "Name": "Template.Azure.Account.JWTToken", + "Label": "Azure Account JWT Token", + "HelpText": "The JWT token of the Azure account to use. This value can be retrieved from an Azure Account variable type. Add an Azure Account to your project , then assign the `OpenIdConnect.Jwt` property to for this entry. Leave blank if you're using an Azure Service Principal account type.\n\nFor example, if your Azure Account variable is called MyAccount, the value for this input would be `#{MyAccount.OpenIdConnect.Jwt}`", + "DefaultValue": "", + "DisplaySettings": { + "Octopus.ControlType": "SingleLineText" + } + }, { "Id": "f7fafc7e-2658-4a6f-ac30-7d9f738b9f52", "Name": "Template.ContainerApp.Environment.Name", @@ -179,8 +189,8 @@ ], "StepPackageId": "Octopus.Script", "$Meta": { - "ExportedAt": "2025-03-26T15:16:57.216Z", - "OctopusVersion": "2025.1.9982", + "ExportedAt": "2026-01-28T18:05:42.201Z", + "OctopusVersion": "2026.1.5902", "Type": "ActionTemplate" }, "LastModifiedBy": "twerthi",