7
votes

I am attempting to read an Azure DevOps secret variable from a Powershell pipeline script. The variable looks like this within Azure:

enter image description here

I've attempted to access the secret variable both as a param such as

[CmdletBinding()]
Param (
    $SecurePassword = $env:Password
)

and simply as an environment variable such as

$SecurePassword = $env:Password

Unfortunately the variable continues to appear null using either method.

enter image description here

I have no issue accessing non-secret variables. Any help would be greatly appreciated.

---------------------------------------- EDIT ----------------------------------------

I found documentation here stating that secrets are available to scripts within the pipeline if explicitly mapped in the environment section of the task.

enter image description here

I've updated my Powershell task and attempted to map the variable as both $(Password) and Password without any luck.

enter image description here

Mapping $(Password) as above reveals the string hidden behind asterisks.

Using $(Password) returns

2
It would break security if you could do that - theoretically you could extract a bunch of passwords this way.Nick.McDermaid
According to the information in your log, you should want to use ConvertTo-SecureString to decrypt encrypted environment variables, but this only applies to strings encrypted with powershell, and Secret variables in azure devops are encrypted at rest with a 2048-bit RSA key. They are Automatically masked out of any log output from the build or release. So I think you can't decrypt it in the log.Hugh Lin
I've edited my question to include useful information I found herepirateofebay

2 Answers

3
votes

We had a requirement to create a new project in Azure DevOps and needed to migrate all of the pipelines to the new project. Lo and behold, no one knew all of the secrets, and export / import doesn't accomplish this.

I wrote a script to output all environment variables into an "Extensions" tab next to the build summary. It's formatted and everything.

The key to outputting the secret is by altering the string by inserting the '<-eliminate->' phrase within the secret value and saving to a file. Once the file is created, we then remove all instances of the string '<-eliminate->', save the file, and there it sits as an extension page to the build summary.

I would like to somehow find All secrets dynamically, but for now manually defining the variable name does the trick.

I re-formatted for this post and removed proprietary info, please let me know if it's broken :)

function GetSecretLength ($secretVar){
     $i = 0;
     while($true){
          try { 
               $secretVar.substring(0,$i)|out-null 
          } catch { 
               break
          };
          $i++; 
     }
     if ($i -le 1) { return 1 }
     else { return $i-1 };
} 
function GetSecret($secret){
     $length = GetSecretLength($secret);
     if ($length -ge 2) {
        return $secret.substring(0,$length-1 )+"<-eliminate->"+$secret.substring($length-1,1)
    } elseif ($length -eq 1) {
        return $secret+"<-eliminate->"
    } else {
        return ""
    }
} 

$var = (gci env:*).GetEnumerator() | Sort-Object Name
$out = ""

Foreach ($v in $var) { $out = $out + "`t{0,-28} = {1,-28}`n" -f $v.Name, (GetSecret($v.Value)) }

$fileName = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY\build-variables.md"
write-output "dump variables on $fileName"
set-content $fileName $out

write-output "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Environment Variables;]$fileName"

((Get-Content -path $fileName -Raw) -replace '<-eliminate->', '') | Set-Content -Path $fileName

You have to add the secret variables that you want into the "Environment Variables" of the Powershell task: Environment Variables

You end up with this pretty tab: enter image description here

2
votes

Why not just store the password in a keyvault as a secret? then there are azure commands for accessing the secret, and avoid all this. Heck, we generate random passwords, store them in keyvaults, then access the contents in the appropriate resource, without ever needing to expose the decrypted secret in a powershell command, like in an ARM template for an azure sql server database.

I know this doesn't solve your initial question, but it is a workaround that does work.