I have automated the deployment of a logic app standard via Azure Devops Pipeline using an arm template.
I have another pipeline that uses the Azure Devops zip deployment task to deploy the workflows (as recommended by Microsoft documentation).
My current struggle is when I have workflows that call other workflows.
When I deploy the zip file across different logic app standard instances the workflow url referenced is always the same.
How can I reference/call the workflow in a way that is not hardcoded and dynamically changes in the deploy? Can I use workflow() to reference other workflows?
As the access key is a property of the workflow and not the logic app standard I'm not able to set it as an app setting or parameter to be consumed inside the workflow.
Any ideas on how to bypass this issue?
What I ended up doing was the following.
I have created key vault secrets. In those key vault secrets I store the workflow url containing the authorization secret.
As I've created the other workflows pointing to the key vault secret name instead of a hardcoded url the logic app at run time will query the key vault, retrieve the url from the workflow i want to authenticate to and use it as input. As it already contains the signature it authenticates correctly.
It's probably a workaround but it was the only way I was able to achieve success in this operation.
For those with the same problem as me here are the steps:
First I have developed the workflow to obtain the secret containing the url from the keyvault
Get keyvault secret
Then it calls the url using the secret as input.
Secret as input for the url
When I have my workflows ready to deploy. I export them and put the code on Azure Devops.
Then in a build pipeline I use the following tasks
task: ArchiveFiles#2
displayName: "Archive Functions"
inputs:
rootFolderOrFile: "$(Build.Repository.LocalPath)/LogicApps"
includeRootFolder: false
archiveFile: "$(Build.ArtifactStagingDirectory)/LogicApps.zip"
task: AzureFunctionApp#1
displayName: "Deploy Functions"
inputs:
azureSubscription: "${ { parameters.Subscription }}"
appName: "mylogicappstandard"
package: "$(Agent.BuildDirectory)/${ { parameters.ArtifactName}}/LogicApps.zip"
task: AzureCLI#2
displayName: 'Update Signature url in ${ { parameters.KeyvaultName}}'
inputs:
azureSubscription: "${ { parameters.Subscription }}"
scriptType: 'ps'
scriptLocation: 'inlineScript'
inlineScript: "$(Agent.BuildDirectory)/${ { parameters.ArtifactName}}/Scripts/Get-WorkflowUrlSignature.ps1 $(AzureSubscriptionId) ${ { parameters.ResourceGroup }} mylogicappstandard ${ { parameters.KeyvaultName}}"
You can find the details for the script here Get-WorkflowUrlSignature.ps1
[CmdletBinding()]
param (
[Parameter(Mandatory)][string]$SubscriptionId,
[Parameter(Mandatory)][string]$ResourceGroup,
[Parameter(Mandatory)][string]$LogicAppName,
[Parameter(Mandatory)][string]$KeyVaultName
)
$json = az rest --method get --uri "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Web/sites/$LogicAppName/hostruntime/runtime/webhooks/workflow/api/management/workflows?api-version=2018-11-01"
$workflows = $json | convertfrom-json
foreach ($workflow in $workflows.Name){
$uri ="https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Web/sites/$LogicAppName/hostruntime/runtime/webhooks/workflow/api/management/workflows/$workflow/triggers/manual/listCallbackUrl?api-version=2018-11-01"
if (az rest --method post --uri $uri){
# Gets the url with signature
$sigurl = az rest --method post --uri $uri | convertfrom-json
$secret = $sigurl.value.Replace('&','"&"')
$workflowName = $workflow.Replace("_","")
#Creates or updates secret in the keyvault
Write-Output "Updating secret $workflowName in the keyvault"
az keyvault secret set --name $workflowName --vault-name $KeyVaultName --value $secret
}else{
Write-Output "The workflow $workflow does not have any trigger url"
}
}
I hope this helps other people automate the process. Please let me know if you have an easier way to do it or to query the access key or url sig.
Related
There are many questions similar to mine, but I hit a wall finding what I want, please help.
I am running Azure Dev ops pipeline within the organization "MyOrganization" and in the project "MyProject". The service connection or subscription I am connected to is "Subscription-Id" (something like this: abc123-def456..xyz3265)
Pipeline has several tasks.
The first task is a powershell taks that creates Azure Resource Group and then an Azure Key vault. (NewKeyVault)
Second task, will scan another existing key vault (SourceKeyVault) and copy its secrets into the NewKeyVault. I know how to do this and it works just fine when I run the powershell tasks from within my PCwhen I explicitly log in with my log in to azure.
Howerer, here when ran under Azure Dev Ops pipleline, I get error that the "logged in" user has no permissions to Create, get list, etc.. to the secrets.
I want to automatically assign access policy to newly created key vault.
If using the web portal, I can see the Devops as a registered application and can do it. I don't know how to access it from within power shell task within the devops running pipeline.
Based on your expectation, you may consider using the Azure CLI pipeline task, where you can run az keyvault set-policy command to configure keyvault access policies for specific user.
az keyvault set-policy -n $(TheAzureKeyVaultName) --secret-permissions get list --object-id $(UserPrincipalGUID)
See more information on az keyvault set-policy.
steps:
- task: AzureCLI#2
displayName: 'Azure CLI '
inputs:
azureSubscription: 'ARM_Svc_Cnn_Auto_Sub1'
scriptType: ps
scriptLocation: inlineScript
inlineScript: 'az keyvault set-policy -n $(TheAzureKeyVaultName) --secret-permissions get list --object-id $(UserPrincipalGUID)'
This task requires to use the Azure Resource Manager service connection to authenticate and login Azure.
For the automatically created ARM service connection, you can use this API to find out which service principal that the ARM service connection is referenced to az login.
In my case, the ARM service connection is referencing the service principal MyDevOpsOrg-TheProjectName-MySubID which is the contributor of my target KeyVault (inherited from subscription) and has sufficient permission to set key vault access policy.
I was able to resolve an issue in a simple manner - I am using Azure Power shell
script that creates the key vault itself
New-AzKeyVault -VaultName $newKvName -ResourceGroupName $resourceGroupName -Location $location
(all the variables referenced with $ are arguments passed to the script)
And then I get the context for a logged in principal
(AzDevOps pipeline is a principal in itself, registered in Azure AD)
#This gives a context object, which has principal
#id as a property of.
$Context = Get-AzContext
Then I set that principal as access policy
Set-AzKeyVaultAccessPolicy -VaultName $newKvName -ServicePrincipalName $Context.Account.Id -PermissionsToSecrets Get,List,Set
We have recently started using Azure DevOps Pipelines for our Dynamics 365 CRM implementation, but it is still new to me
I recently came across this blog post by Joe Griffin on how you can use PowerShell in Azure DevOps pipelines to ensure, that Access Team Templates works when deploying a solution - and I would like to use that.
However, I don't know where I add my parameters to script. Can I do that inline or do I need to add the script to my repo to do that? If so - how can I do that?
param(
#objectTypeCode: Unique Code that identifies the table in the environment for the Access Team Template. Always potentially different.
[Parameter(Mandatory=$true)]
[int]$objectTypeCode,
#atName: Name of the Access Team Template
[Parameter(Mandatory=$true)]
[String]$atName,
#accessRights: Number which represents the access rights defined for the template. Refer to this article for details on how to construct: https://learn.microsoft.com/en-us/dynamics365/customer-engagement/web-api/accessrights?view=dynamics-ce-odata-9
[Parameter(Mandatory=$true)]
[int]$accessRights,
#d365URL: URL of the environment to connect to
[Parameter(Mandatory=$true)]
[String]$d365URL,
#clientID: AAD Client ID for the Application User linked to this environment
[Parameter(Mandatory=$true)]
[String]$clientID,
#clientSecret: AAD Client Secret for the Application User linked to this environment
[Parameter(Mandatory=$true)]
[String]$clientSecret
)
#Install dependencies
Install-Module Microsoft.Xrm.Data.PowerShell -Scope CurrentUser -Force
#Connect to the D365 environment
$conn = Connect-CrmOnline -ServerUrl $d365URL -ClientSecret $clientSecret -OAuthClientId $clientID -OAuthRedirectUri "http://localhost"
#We first attempt to retrieve the rows if they already exist, and update it accordingly; if this errors, then the row does not exist, so we need to create it instead
Write-Host "Processing Access Team Template for $atName..."
try
{
$atTemplate = Get-CrmRecord -conn $conn -EntityLogicalName teamtemplate -Id "44396647-CEDF-EB11-BACB-000D3A5810F2" -Fields teamtemplateid,teamtemplatename,objecttypecode,defaultaccessrightsmask,issystem
$atTemplateId = $atTemplate.teamtemplateid
Write-Host "Got existing Access Team Template row with ID $atTemplateId!"
$atTemplate.teamtemplatename = $atName
$atTemplate.objecttypecode = $objectTypeCode
$atTemplate.defaultaccessrightsmask = $accessRights
$atTemplate.issystem = 0
Set-CrmRecord -conn $conn -CrmRecord $atTemplate
Write-Host "Successfully updated Access Team Template row with ID $atTemplateId!"
}
catch [System.Management.Automation.RuntimeException]
{
Write-Host "Access Template row with ID $atTemplateId does not exist, creating..."
$atTemplateId = New-CrmRecord -conn $conn -EntityLogicalName teamtemplate `
-Fields #{"teamtemplateid"=[guid]"{44396647-CEDF-EB11-BACB-000D3A5810F2}";"teamtemplatename"=$atName;"objecttypecode"=$objectTypeCode;"defaultaccessrightsmask"=$accessRights;"issystem"=0}
Write-Host "Successfully created new Access Template row with ID $atTemplateId"
}
Write-Host "Script execution finished!"
You can use "Azure Powershell" task (If the script has to do something on azure) and can specify path to your powershell file and can add parameter values as in this screenshot,
or you can use "Powershell"task and can add path to the file and parameter,
You can add a Powershell task in your yaml and invoke the Powershell script to perform required task. Script arguments can be set in and passed through DevOps library.
- task: AzurePowerShell#5
displayName: 'Powershell task'
inputs:
azureSubscription: '${{ parameters.ServiceConn }}'
ScriptType: 'FilePath'
ScriptPath: '[Path to script]/PowershellScriptName.ps1'
ScriptArguments: '-objectTypeCode $(objectTypeCode) -atName $(atName) -accessRights $(accessRights) -d365URL $(d365URL) -clientID $(clientID) -clientSecret $(clientSecret)'
azurePowerShellVersion: 'LatestVersion'
pwsh: true
Is there a way to deploy complete variable group variables to Azure Function app settings using Yaml.
Below is the yaml code and how I am deploying variable :-
variables:
- group: MyDevVariable #This is my variable group name
#Place where I am referring my variables from variable groups
deploy:
steps:
-task: AzureFunctionApp#1
inputs:
appSetting: '-Key1 $(Key1) -Key2 $(Key2)' #Key1 and Key2 are stored in variable group.
but if I have many variables, I have to mentions every variable in appSettings as key $(key).
So Is there a way to deploying all my variables from variable group to azure function app setting.
Any response is greatly appreciated.
Thanks in advance.
I don't believe that you can iterate the group's variables in the YAML directly. There's no syntax to reach into the group from what I've seen. What you can do is to write a script that gets the variables out of the group (if you have Azure CLI installed on the agent) and then reference it later:
deploy:
steps:
- task: AzureCLI#2
inputs:
name: GetSettings
azureSubscription: Your Service Connection
scriptType: ps
scriptLocation: inlineScript
inlineScript: |
$env:AZURE_DEVOPS_EXT_PAT = '$(System.AccessToken)'
$groupVars = (az pipelines variable-group list --group-name "My Group Name") | ConvertFrom-JSON
$settingsList = ""
$groupVars.variables.PSObject.Properties | ForEach-Object {
$settingsList += "-$($_.Name) `"$($_.Value.value)`" "
}
Write-Host "##vso[task.setvariable variable=settingsList;isOutput=true]$settingsList"
Write-Host "Using settings $settingsList"
- task: AzureFunctionApp#1
inputs:
appSetting: $(GetSettings.settingsList)
NOTE: This may encounter issues with secret variables, in which case I'd store them in Azure Key Vault and use the key vault secrets task to read them into variables.
Hi and thanks for taking the time to look at my question.
I'm using terraform to create an api_management object in Azure. I've mastered the setup of API's, Products, Policies, Subscriptions and Users.
My devs setup an authorisation server on the API Management object in Azure, which I automated using azurerm_api_management_authorization_server which works fine.
However, I can't see how in terraform I can configure the API settings to use that authorisation server.
API User Authorisation Settings
Looks as if this capability is currently not available via Terraform, which can be found by the open issue against the azurerm provider:
https://github.com/terraform-providers/terraform-provider-azurerm/issues/3341
What I would recommend doing to let you continue building out your infrastructure within Terraform, would be to utilise the azurerm_template_deployment resource.
This would let you utilise the available ARM API's from an ARM deployment:
https://learn.microsoft.com/en-us/azure/templates/microsoft.apimanagement/2019-01-01/service/apis
Sadly, until that issue is closed that capability won't be in the azurerm provider.
Note to the Answer provided by Lachie White
As I'm running this from a yaml pipeline in azure devops, I got around this limitation by using an azure powershell task
- task: AzurePowerShell#5
inputs:
azureSubscription: 'Subscription (111111111-1111-1111-1111-111111111111)'
ScriptType: 'InlineScript'
Inline: |
$ApiMgmtContext = New-AzApiManagementContext -ResourceGroupName "api-mgmt-rg" -ServiceName "api-mgmt"
$ApiAuthorizationServer = Get-AzApiManagementAuthorizationServer -Context $ApiMgmtContext
$ApiAuthorizationServerName = $ApiAuthorizationServer.Name
Set-AzApiManagementApi -Context $ApiMgmtContext -ApiId "api-name" -AuthorizationServerId "$ApiAuthorizationServerName"
azurePowerShellVersion: 'LatestVersion'
I have a question regarding Azure DevOps, It seems it is not possible to set in pipeline's jobs Azure subscription field using variables. On attempt to do this I'm getting the error message:
The pipeline is not valid.
I was trying to use in variable:
Subscription ID
Service Connection Name
Service Connection ID
But with no luck - the same issue again and again. Since I need to change subscriptions for pipeline very often, it's very critical problem for me. Could you please elaborate the issue?
If you use YAML pipelines you could configure your subscription as variable as follows:
- task: AzureCLI#2
inputs:
azureSubscription: '$(SubscriptionId)'
scriptType: 'ps'
scriptLocation: 'inlineScript'
inlineScript: |
az --version
az account show
Variable settings
And during every build you can override your azure subscription.