Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing secret variable from YAML pipeline to Powershell script

I have a pipeline where I run the AzurePowerShell@5 task. The pipeline runs a separate powershell script like this:

  - task: AzurePowerShell@5
    displayName: "PowerShell Script"
    inputs:
      azureSubscription: "Platform - Management"
      ScriptType: "filePath"
      ScriptPath: ./post_migration/post-migration.ps1
      ScriptArguments: "-SubscriptionId ${env:SUBSCRIPTIONID} -ResourceGroup ${env:RESOURCEGROUP} -VmName ${env:VMNAME} -Username ${env:USERNAME} -Password ${env:PWD}"
      azurePowerShellVersion: "LatestVersion"
    env:
      PWD: $(Password)

The variable Password is marked as "Keep this value secret". The reason to do like this is that we need to be able to set different values on the variables every time.

The param block for the variable $Password in the powershell script looks like this:

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[SecureString]$Password

When I run the pipeline i get this error message:

Cannot process argument transformation on parameter 'Password'. Cannot convert the "***" value of type "System.String" to type "System.Security.SecureString".

All other variables seem to work fine, but not the secret. Any suggestion about what I'm doing wrong?

like image 312
Santa Avatar asked Oct 17 '25 21:10

Santa


1 Answers

The secret is passed as cleartext in the environment, not as a SecureString. There is no way to pass the secret from the agent to the script in encrypted/protected form.

You can probably cheat a little:

-Password $(ConvertTo-SecureString $env:PWD -AsPlainText -Force)

That will take the insecure value from the environment, then convert it before passing it into your script.

⚠️ Just understand, this isn't in any way more secure, since the value won't be encrypted and it will be passed plaintext in memory. But it will allow you to call a script that expects a secure string.

The agent's "keep secure" checkbox on variables does a few things, but not what you're expecting:

  1. Variables marked as secure aren't automatically available to scripts - Unlike other variables which are set as an environment variable by default, secure variables need to be explicitly passed in through the env: section or inlined in an input using the $(...) or ${{ ... }} or $[ ... ]` syntax:

    - pwsh: |
        echo $(SECRET)
    - pwsh: | 
        echo ${{ variables.SECRET }}
    - pwsh: | 
        echo $[ variables.SECRET ]
    - pwsh: |
        echo $env:SECRET
      env:
        SECRET: $(SECRET)
    - task: PowerShell@2:
      inputs:
        scriptArguments: $(SECRET) ${{ variables.SECRET }} $[ variables.SECRET ] $env:SECRET
      env:
        SECRET: $(SECRET)
    
  2. Variables marked as secure are scrubbed from the logs - The primary purpose of marking a string as secure is to tell the agent to not accidentally expose the value through the logs. So every time a secret is written to Standard Out/Error the value is replaced by ***, the same is done in the deug logs that are written to the agent's disk.

  3. Secrets can't be passed to another job through output variables. - The agent will try to detect when a secret is passed to an output variable and block this. This prevents the secret from being logged in the initialization phase of the next job, since output variables don't carry the secret-true flag unfortunately.

What secrets do not do:

  1. Secrets aren't stored in protected memory - Since the value must be passable to any executable, script or task, it can't be stored as a SecureString at all times. When you explicitly pass a secret to a step, it's passed in as plain text. This is due to the fact that there is no equivalent of SecureString that will work everywhere.
like image 161
jessehouwing Avatar answered Oct 19 '25 11:10

jessehouwing



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!