Dynamicallly get KeyVault secret in Azure DevOps Powershell script - azure

We have an Azure Key Vault task in our release pipeline which downloads some secrets for use in the stage.
In an Inline Azure PowerShell script you can just use the following to get the secret value:
$secretValue = $(nameOfTheSecretInKeyVault)
This works fine.
However we want to move to using scripts in the repo, i.e. poiting the DevOps task to a file path i.e. /somePath/myScript.ps1
So I would need to parameterise the above line of code, as I cannot just change the name in the inline script like I'm currently doing, but I can't get it to work.
I have tried:
$compositeName = "${someParameter}-Application"
$secretValue1 = $($compositeName)
$secretValue2 = $("${compositeName}")
$secretValue3 = env:$compositeName
$secretValue4 = $(${compositeName})
The top line is just building up the name of the secret which it needs to look for. Unfortunately none of these work. Attempt #1, #2 and #4 come back with the string name only, not having actually got the secret value, and #3 errors saying it doesn't exist.
Is there a way to achieve this, or do I simply need to parameterise the secret and pass it into the script from the ADO task?

As you, I couldn't figure out a way to access the variables the log mentions are loaded in the Download secrets task of the job. It did work in inline mode, but not a chance with a script file.
So instead I leveraged the existing wiring (variable group linked to my KeyVault) and just run the command myself at the start of my script:
$mySecretValue = (Get-AzKeyVaultSecret -VaultName "myVault" -Name "mySecret").SecretValueText
From there I could use it as any other variable.

Either run your KeyVault tasks first, before your PowerShell script, or do it all in PowerShell.
You will need to create a service connection to your Azure subscription from Azure DevOps. Allow the service connection to access the KeyVault. Access the KeyVault from PowerShell or Azure CLI.
E.g. for PowerShell:
(Get-AzKeyVaultSecret -vaultName "Contosokeyvault" -name "ExamplePassword").SecretValueText
Here is a detailed walk through.

There is also native key vault integration now so you can just have your keys read in as a variable group transparently, no Keyvault-specific powershell code required.
https://learn.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=azure-devops&tabs=yaml#link-secrets-from-an-azure-key-vault

One way to tackle this would be to add a parameter for your script to pass the release variable in when you call it, something like -secretValue $(nameOfTheSecretInKeyVault)
You should be able to use $env:nameOfTheSecretInKeyVault, but remember . become _
EDIT: Looking at your question again if you used env:$nameOfTheSecretInKeyVault you would have had an issue. It's $env:<variable_name>

If anyone comes across this in the future and is looking for a bash alternative, I ended up being able to do this with the following command
$(az keyvault secret show --name "${secret_name}" --vault-name "${vault_name} --query "value" | sed "s/\"//g")
This let's you get the value of the vault secret and use it wherever. The sed at the end is needed to drop the " that gets pulled out from the query

Related

How to get value from Azure App Service from Azure pipeline

I have a configuration in App Service like this
I want to pass this setting into the argument of a pipeline's task
How can I do it?
I've tried to create a variable group but I still don't know how to link the app setting into the variable
Microsoft provide command line tools to access this information. I don't have a web-app to access to give specific commands but roughly something like this.
See documentation here: https://learn.microsoft.com/en-us/azure/app-service/configure-common?tabs=cli#configure-app-settings
For example using az cli you could do something like:
az webapp config connection-string list --resource-group <group-name> --name <app-name> > settings.json
You can then select the specific item out of that list using jq.
myvalue=$(jq -r .some.path settings.json)
And you can also set the value in a variable which you can use in another task:
##vso[task.setvariable variable=appsetting;]value
So :
Download app settings
Select item
Set variable to pass to next step
Use variable in next step.

[Azure Terraform]: Create Start/Stop VM Solution

I am using Terraform to create an Automation Account in Azure.
The following resource in Azure provider does the job: azurerm_automation_account.
Ok. So I got my AA created... here is when problems arise.
"Run As" account: there seems to be a way to create it from Terraform... but the process is cumbersome. I have lost hope, and will probably resort to enable it manually from Azure portal (it is just one click)... but it will brake my automation pipeline :(
"Start/Stop VM Solution": I need the powershell runbooks in this solution to start-stop VMs according to a given schedule. There is a resource in Azure provider called "azurerm_automation_runbook". It has 2 useful arguments to reference runbook scripts:
"content": with it I could "load" a local powershell script content. I know this would work (I could manually download the .ps1 script used by "Start/Stop VM Solution" and use "content" to load it), but I would be missing any fixes/updates made by Microsoft in its code)
"publish_content_link": by which I could point to the URI of a given powershell runbook. I have looked in the "Runbook Gallery" for the runbooks contained in the "Start/Stop VM Solution" (not found them). Anyone had any luck with this? A different approach could be to "create" the "Start/Stop VM Solution" from a Terraform script (this will automatically populate the desired runbooks in my Automation Account)... but not sure if this would be possible.
Thanks in advance.
For point 1: I also found it very challenging and while things have improved lately, there still doesn't seem to be an easy, straight forward way of creating the Run As Account. I eventually resorted to creating it manually from the Azure Portal but below are potential areas you can explore:
I'm not sure if you've considered using the external data source from terraform to execute the Powershell script from Microsoft. It's still a pain because of the last step where you have to authenticate manually, but it still brings you closer to having a blueprint of your environment. Although I'm not sure how it would behave if running this Terraform script a second time.
For point 2: Could you confirm that the script you want to use is a Powershell script and not a Powershell Workflow script? Also could you please elaborate on this approach (I have a feeling that might be the best approach):
A different approach could be to "create" the "Start/Stop VM Solution" from a Terraform script (this will automatically populate the desired runbooks in my Automation Account)
If you look at the Runbooks Gallery, you'll see most of these Powershell scripts have not been updated for many years and are still working fine. If this will be used in a production environment, it would be better if you have control over the changes and update then at your convenience. If you want to get the URI, you can just click on 'View Source Project' and it will lead you to the GitHub repo. E.g. for the Runbook Stop-Start-AzureVM (Scheduled VM Shutdown/Startup).
You'll also notice most of the scripts is submitted by external parties. If you link to a URI that's maintained by someone else and that person publishes malicious code in there or even accidentally messes up the code, it's not desirable. But again I'm not sure as to the extent of your automation (e.g. if you expect to execute the terraform script once a month to ensure the Runbook is up to date)
If I get the scripts from somewhere, I'll validate it prior to using them in my environment.
data "local_file" "start_vm_parallel" {
filename = "./scripts/start-vm-parallel.ps1"
}
resource "azurerm_automation_runbook" "start_vm_parallel" {
name = local.NAME
location = local.REGION
resource_group_name = local.RG
automation_account_name = azurerm_automation_account.automation_prod.name
log_verbose = "true"
log_progress = "true"
description = "This runbook starts VMs in parallel based on a matching tag value"
runbook_type = "PowerShellWorkflow"
content = data.local_file.start_vm_parallel.content
publish_content_link {
uri = "https://path.to.script/script.ps1"
}
}
If you're using a Powershell Workflow, you need to make sure that the Runbook name matches the workflow name inside the script.
One last thing to remember before you even start using your Runbooks, is to update the modules by creating a 'modules update' Runbook from the Azure Automation team and running it on schedule, once a month.

How safe/protect Azure service principal secret

My deploy task using PowerShell script, which use Service Principal for connection to Azure KeyVault for pull secret. Secret (password) store in PowerShell script's code as plain text. Maybe there is another solution how to minimize token viewing.
And also i use powershell inline mode (not separate script) with Azure DevOps Secret Variable in deploy task, but this solution difficult to support (script has several different operations, so you have to keep many versions of the script).
Script is store in Git repository, anyone who has access to it will be able to see the secret and gain access to other keys. Perhaps I don't understand this concept correctly, but if keys cannot be stored in the code, then what should I do?
I devops you can use variable groups and define that the variables is pulled directly from a selected keyvault (if the service principal you have selected have read/list access to the KV) LINK.
This means that you can define all secrets in keyvault, and they would be pulled before any tasks happens in your yaml. To be able to use them in the script you can define them as a env variable or parameter to your script and just reference $env:variable or just $variable, instead of having the secret hardcoded in your script.

Azure Functions: How do I automatically inject a azure-cli-retrieved SAS token into my local settings file?

In the Azure Functions local dev environment, I can generate a SAS token from the command line using
az storage account keys list ...
az storage account generate-sas ...
But then I have to cut and paste the generated SAS token into my local.settings.json each time.
Is there a way for the settings file to access the SAS token via e.g. an environment variable, or must I use a shell script/sed etc. to populate it each time I create a SAS token?
I suppose local.settings.json is just a dumb JSON file. So is host.json. So then I am really unsure - apart from the sed route - how to make such a SAS token or any other environment variable available directly to the Azure Functions local dev runtime. Perhaps there is a magic environment variable specifically for this purpose.
Thanks as ever
You can use this method: func settings add -name "setting name" -value "XXXX" and inject your SAS token as value

TFS\Team Services, Using Azure KeyVault secrets from a Variable Group in a Build Definition

I have a simple Build setup in Team Services. The build simply downloads source code from a Team Services hosted Git repo and then executes a Powershell script.
The Powershell Script receives 4 parameters;
-SiteName "$(AppServiceName)" -AzureRMTenantID "$(AzureRMTenantID)" -AzureRMUN "$(AzureRMUN)" -AzureRMPW "$(AzureRMPW)"
AppServiceName is entered manually when the build is queued.
The 3 AzureRM* parameters should be coming from a Variable Group which I have linked to the Build Definition;
The Variable Group AzureDevOps is configured to Link the Secrets from Azure Key Vault as variables;
Based on everything I have been able to find regarding this pattern, it seems like it should just work.
As an interim sanity check, I am printing the variables out in my powershell script just so I can confirm they are being passed correctly.
Thus far, I have not been able to get the values of any of the AzureRM* variables to print correctly which leads me to believe they are NOT being passed as expected.
Generating script.
Formatted command: . 'd:\a\1\s\AppServices\Create Canned App Service Application.ps1' -SiteName "Testers" -AzureRMTenantID "" -AzureRMUN "" -AzureRMPW ""
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -File "d:\a\_temp\23b9a27a-4b6d-4232-8e24-150173e08915.ps1"
Working Set of Variables:
SiteName: Testers
ResourceGroup: Applications
ASE Name: appservices-ase
Location: East US
Additional Variables:
AzureRMTenantID:
I am not expecting the variables to be printed in the log command here;
Formatted command: . 'd:\a\1\s\AppServices\Create Canned App Service Application.ps1' -SiteName "Testers" -AzureRMTenantID "" -AzureRMUN "" -AzureRMPW ""
but I would expect them to be printed within my script where I am explicitly writing them out;
Write-Host "Working Set of Variables:`nSiteName: "$SiteName"`r`nResourceGroup: "$RG"`r`nASE Name: "$ASEName"`r`nLocation: "$Location
Write-Host "Additional Variables:`nAzureRMTenantID: "$AzureRMTenantID"`r`n"$AzureRMUN"`r`n"$AzureRMPW
If I run the PS script locally, the values do print as expected;
PS C:\ashley\scm\AzureAutomation\AppServices> & '.\Create Canned App Service Application.ps1' -SiteName "tester" -AzureRMTenantID 12345 -AzureRMUN user -AzureRMPW 1234
Working Set of Variables:
SiteName: tester
ResourceGroup: Applications
ASE Name: appservices-ase
Location: East US
Additional Variables:
AzureRMTenantID: 12345
user
1234
Does anyone know how to make this work? I am wondering if the problem has to do with the KeyVault permissions since the request is coming from the "Hosted 2017" Agent Queue built into Team Services.
First, you can’t print out the secret variables’ value, you can send the data to a service (e.g. Web API) to get the actual data during the build/release.
Secondly, the Key Vault secrets variables are used for release, it will add Azure Key Vault task during the release. Link secrets from an Azure Key vault as variables
You will get the empty value if you are using in build. You can add Key Vault Task to the build definition, then you can use the related variables in the following tasks. (Do not need to link to that variable group in build definition)
The Key Vault support currently works only with Release Definitions. You can create a Release Definition and link your Git Repo as an artifact and can achieve the same.
I receive this error while linking Azure Keyvault VG to BD.

Resources