Tuesday 7 February 2023

Set Value for a Secret Variable in Azure Release Pipelines while Triggering from Another Release

 You might want to trigger a release from another release pipeline, specially if you are deploying to a multi tenant application environment. In such cases when you trigger a pipeline from another pipeline the variables you are setting dynamically cannot be a secret variable. If you set a variable that should be settable at release time as a secret, the release cannot be triggerd via the Azure DevOps REST API call, as it will throw an exception such as below.

The 'secret' property of
variables cannot be altered while creating a release. Verify the value
provided for variables UserPwd at scope Release and try again.  

Let's try to understand bit more of the requirement.

You might need a release that should be triggered by another release. The release that is getting tirggered may have a variable that should be set by the calling release dynamically, but it should be set as a scret. For example below release has a UserPwd which should be set at trigger time dynamcally, but it should be a secret as well to prevent the password from geting exposed.


In Azure DevOps UI you can just trigger the release and add a value for the secret variable. Then you can run it without a problem and your secret will not be exposed.




However, if we try to use below PowerShell script to trigger the release, from another release (or aother build pipeline) and set UserPwd (secret variable) you will get the error described above saying, a secret cannot be set.

$token = '$(PAT)'
$ReleaseDefId = '2'
$TriggerDescription = '$(TriggerDescription)'
$azdoAccoutName= 'chamindac'
$teamProjectName='YAML_CICD'
$UserName='$(UserName)';
$UserPwd='$(UserPwd)'
$User=""



# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User,$token)));
$header = @{Authorization=("Basic {0}" -f $base64AuthInfo)};

$ReleaseMetadata = '{"definitionId": ' + $ReleaseDefId + ',"description": "' + $TriggerDescription + '",

                        "isDraft": false,"reason": "none","manualEnvironments": null,

                        "variables": {

                            "UserName": {

                                "value": "' + $UserName + '"

                            },

                            "UserPwd": {

                                "value": "' + $UserPwd + '"

                            }

                         }

                        }';



$Uri = 'https://vsrm.dev.azure.com/' + $azdoAccoutName + '/' + $teamProjectName + '/_apis/release/releases?api-version=6.0'


$ReleaseResponse = Invoke-RestMethod -Method Post -ContentType application/json -Uri $Uri -Body $ReleaseMetadata -Headers $header

$ReleaseResponse

We have to make the UserPwd as not a secret to make it settable while creating release with the REST API. It will allow the release to be triggered via the script above from another release but the secret value will be exposed.

Now when the release is triggered by the other release, it runs fine but the secret is getting exposed as shown below.


The problem here is 
  • We cannot hide the UserPwd making it a secret as it does not alow to trigger via REST API
  • We cannot keep it as non secret because release varaibles will show the actual secret value

How to fix?

By adding the PoweShell script segement below to the end of the triggering script shown above, will make the created release UserPwd variable to be set as a secret. What we do in ths script is update the created release instance metadata to mark the variable UserPwd as a secret after triggering it.
   # update password as secret

    #----------------------

    $ReleaseResponse.variables.UserPwd | Add-Member -NotePropertyName 'isSecret' -NotePropertyValue 'True'

    $ReleaseUpdateMetadata = $ReleaseResponse | ConvertTo-Json -Depth 100



    $Uri = 'https://vsrm.dev.azure.com/' + $azdoAccoutName + '/' + $teamProjectName + '/_apis/release/releases/' + $ReleaseResponse.id + '?api-version=6.0'

    

    # update password as secret

    Invoke-RestMethod -Method Put -ContentType application/json -Uri $Uri -Body $ReleaseUpdateMetadata -Headers $header

    #-------------------------


In the release definition UserPwd will remain as a non secret with a dummy value allowing it to be set at the time of triggering via REST API.

The release will get triggerd via the script and then the UserPwd is set as a secret so it is no longer exposed.








 

No comments:

Popular Posts