Closing parentheses in string dropped when creating app service app setting via Azure cli - powershell

I'm creating an Application Setting in an Azure App Service via the Azure cli. The value of the setting is a KeyVault reference which, if you're not familiar, has a special syntax:
#Microsoft.KeyVault(SecretUri=https://something.vault.azure.net/secrets/SomeKey/xxxxxxxxxx)
My powershell script creates the KeyVault secret and stores the secret id. I then construct the Application Setting value like:
$new_secret_id = "#Microsoft.KeyVault(SecretUri=$secret_id)"
I use Write-Host to verify $new_secret_id is exactly correct at this point.
Then I use the following command to create the Application Setting but the trailing paren is always missing and that causes the app setting to become a verbatim value instead of a KeyVault reference. If I hard-code a value instead of using the variable $secret_id it works, it does not strip the closing ).
az webapp config appsettings set `
--resource-group $rg `
--name $app_name `
--settings A_SECRET=$new_secret_id
Update
I've been trying with various combinations of values for $secred_id. It only seems to happen when the value is a URL.

This is already a documented problem (feature):
https://github.com/Azure/azure-cli/issues/8506
We made this change to help prevent the shell from interpreting the special characters in the setting value
As noted in the github comments, you can embed double quotes.
--settings "A_SECRET=""#Microsoft.KeyVault(SecretUri=$secret_id)"""

Related

Automatically pass string to powershell user input

In my powershell script, I call the following azure function:
az repos import create --git-source-url https://incommunities#dev.azure.com/my-organisation/Templates/_git/$($Framework) --detect true --project $ProjectAlias --repository $ProjectAlias --requires-authorization
When running, it prompts the user for a Password/PAT token, e.g:
Git Password / PAT:
Is there a way to automatically pass the password/token to the user input without having to enter manually?
I attempted to pipe the value through, however this does not seem to work e.g
my-pat-token | az repos import create --git-source-url https://incommunities#dev.azure.com/my-organisation/Templates/_git/$($Framework) --detect true --project $ProjectAlias --repository $ProjectAlias --requires-authorization
Is this both a) possible and then if so b) how can I do this?
There are two approaches you can use, both come courtesy from this nice blog post which you'll probably want to read, as it talks about a bunch of Azure Devops tasks.
Use an environmental variable
These commands will check for the presence of an environmental variable and will use it instead of prompting.
To do this, set an environment variable called AZURE_DEVOPS_EXT_PAT to the value of your PAT. (More info on how these tokens work here from the Microsoft Docs)
# set environment variable for current process
$env:AZURE_DEVOPS_EXT_PAT = 'xxxxxxxxxx'
When you're automating things, just set this variable before running the Azure commands.
Pipe the value in
I am not as big of a fan of this sort of approach but you can "echo out" the PAT value and pipe that into a command, which might work. IMHO this is more fragile and frunky and I wouldn't advise it.
$pat | az devops login

Correct way to use secret variable in PowerShell script

What is the correct way to use a secret variable in a PowerShell script? It may be a pipeline variable, a variable group one, or a variable brought in from an Azure Key Vault task.
I have seen in the documentation that it cannot be used in the same way as a normal (non-secret) variable. It says "Instead, we suggest that you map your secrets into environment variables." and "You need to explicitly map secret variables."
I have used an environment variable and it works. Are there other ways to do it? This blog says you can use it directly in the script, which seems to contradict the MS document.
This one passes the variable as an argument or parameter to the scripts. Does anyone know what is actually going on behind the scenes?
have seen in the documentation that it cannot be used in the same way as a normal (non-secret) variable. It says "Instead, we suggest that you map your secrets into environment variables." and "You need to explicitly map secret variables."
The doc is misunderstood, it's not saying the secret variables cannot be used in the same way as a normal variable, instead, it says it's not suggested to pass secrets on the command line directly since some operating systems log command line arguments which could cause information leakage as mentioned, and it's suggested to map your secrets into environment variables.
This blog says you can use it directly in the script, which seems to contradict the MS document.
As mentioned above, the secrets can be used directly in the script although it's not suggested, so they are not contradictory.
You can also check the example in the MSDN doc:
steps:
- powershell: |
# Using an input-macro:
Write-Host "This works: $(mySecret)"
# Using the env var directly:
Write-Host "This does not work: $env:MYSECRET"
# Using the mapped env var:
Write-Host "This works: $env:MY_MAPPED_ENV_VAR" # Recommended
env:
MY_MAPPED_ENV_VAR: $(mySecret)
and you will see in the first line of the powershell script, the secret variable is used directly in the command.
In conclusion, i suggest we should follow the MSDN doc, map your secrets into environment variables and then use them.

How to pass / store secrets in Azure DevOps Services that can be accessed from unit test

I need to use secret passwords in unit tests execution that are retrieved from Environmental Variables.
Tests are executed by Visual Studio Test task in version 2.*
_networkCredential = new NetworkCredential(Environment.GetEnvironmentVariable("DomainAccountUsername"), Environment.GetEnvironmentVariable("DomainAccountPassword"));
If I set DomainAccountPassword directly from Powershell everything works fine, test ends successfully, but I don't want to show password to other users in my team.
Write-Host "##vso[task.setvariable variable=DomainAccountPassword;]MyExamplePassword"
Passing secret defined in Library Group does not work, causing authentication error.
Write-Host "##vso[task.setvariable variable=DomainAccountPassword;]$(secretPassword)"
How can I pass secret to VSTS task so it can authenticate in external API?
Thank You!
As per Documentation
Secret variables are encrypted at rest with a 2048-bit RSA key. Secrets are available on the agent for tasks and scripts to use (so be careful about who has access to alter your pipeline).
...
Unlike a normal variable, they are not automatically decrypted into environment variables for scripts. You can explicitly map them in, though.
To pass a secret to a script, use the Environment section of the scripting task's input variables.
To use secrets in scripts
Set the variable to secret:
Pass the variable to the script explicitly
And use the new env var in your script by name $env:topshelfPassword
If your pipeline is YAML and not in the Classic Editor
You should not set secret variables in your YAML file. Instead, you should set them in the pipeline editor using the web interface. These variables are scoped to the pipeline in which you set them.
The following example shows how to pass a secret variable called mySecret set in the web interface to a script.
YAML
steps:
- powershell: |
# Using an input-macro:
Write-Host "This works: $(mySecret)"
# Using the env var directly:
Write-Host "This does not work: $env:MYSECRET"
# Using the mapped env var:
Write-Host "This works: $env:MY_MAPPED_ENV_VAR" # Recommended
env:
MY_MAPPED_ENV_VAR: $(mySecret)
Notice how the variable is declared in the web ui as mySecret and what would work for a typical non-secret variable ($env:mySecret) doesn't b/c it's a secret. However, what works in YAML that doesn't work in the Classic experience (I believe I'm correct) is the use of "input-macro" syntax ($(mySecret)).
It seems that Visual Studio Test task cannot get secret in runtime as environmental variable but it can accept secret set as parameter from TestContext
_networkCredential = new NetworkCredential(Environment.GetEnvironmentVariable("DomainAccountUsername"), TestContext.Parameters["DomainAccountPassword"]);
I have added .runsettings file to test project
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<TestRunParameters>
<Parameter name="DomainAccountPassword" value="" />
</TestRunParameters>
</RunSettings>
And in Visual Studio Test task options I have set path to settings file and overrided DomainAccountPassword parameter with my secret.
Visual Studio Test task options

How to set secret environment variable with logging commands in TFS Release

I'm passing a secret Release Task Variable to a PowerShell script and trying to set that value as an environment variable using logging commands so I can use it in other tasks in the same Release. I'm able to do this with a non-secret variable, but not with a secret one.
So, the following is working (I can see it using ls env: and also use it to connect to a tfs instance as a Personal Access Token) when PAT is a non-secret variable:
Inline Script Arguments: -token "$(PAT)"
Param(
[string]$token
)
Write-Host "##vso[task.setvariable variable=API_TOKEN;]$token"
I can only use the environment variable set above if I use it in a subsequent powershell task - it's not available within the task where PAT is passed.
But the following does not seem to be working when PAT is a secret variable:
Inline Script Arguments: -token "$(PAT)"
Param(
[string]$token
)
Write-Host "##vso[task.setvariable variable=API_TOKEN;issecret=true]$token"
(Note: I also tried changing API_TOKEN to something else like MYTOKEN, in case API_TOKEN is reserved, but still don't see MYTOKEN var at all if I do ls env: in a subsequent PowerShell task.)
How can I set an environment variable to a secret value passed from a Release Task, for use by that task or by other tasks in the Release? In other words, when or how can I access the environment variable set by the above-referenced logging commands with issecret=true? (I'm not actually sure I'm setting it properly, since I can't see it, but I assume I am since the non-secret version works.)
Not sure if it matters, but I have ticked the box in the release definition that says "Allow scripts to access OAuth token".
Update
There is more information here, but it's very confusing. I couldn't figure out how to set and access a secret environment variable - I suspect they are not actually environment variables, but in that case I don't understand why the logging commands are needed at all, since we can already pass secret variables to scripts. I was able to workaround by passing the secret variable from the Release Task directly to the PowerShell script, and then from there to other scripts, instead of trying to set/access the value as an environment variable.
Actually the logging command also works for secret variables (what you tried should work). As the logging command usage mentions:
When issecret is set to true, the value of the variable will be saved
as secret and masked out from log. Secret variables are not passed
into tasks as environment variables and must be passed as inputs.
You can use the script echo $(API_TOKEN) instead of ls env: (since secret variables are not showing by the command ls env:), then you will get ********.
And for the use of the secret variable $(API_TOKEN) in your following release tasks, the value should be passed as inputs (as the usage mentions).
There is no way to set a secret environment variable using the mentioned logging commands.

How to add secret variable as task environment variable in VSTS

This documentation states that secret variables are
Not decrypted into environment variables. So scripts and programs run by your build steps are not given access by default.
One of my build tasks require that an environment variable be set that is stored in a secret variable. Does this mean it's impossible to do this using secret varaibles in VSTS? If not, how do I do this?
For further background, I'm trying to code sign my electron app using electron-builder. It requires that two environment variables be set: CSC_LINK and CSC_KEY_PASSWORD. One of these is the password to a code signing certificate so needs to be kept secure.
Set Environment Variable
Use a Command Line task, like this:
target_environment_variable now contains the value of secret_variable.
Verify
Add a subsequent Command Line task that writes all environment variables to a disk file, like this: (note: in the Arguments text box, write to a folder that both you and build agent can access):
Queue the build definition, then view the file containing the environment variables:
When using the YAML-syntax this can be achieved too:
steps:
- script: |
echo %MYSECRET%
env:
MySecret: $(Secret_Variable)
You can supply variables to pass to tasks in the Variables page of the build definition:
Then they can be passed in to a task as an input like so: