Unable to Update RBAC role using Azure DevOps Pipeline - azure

I am using Azure Devops Pipeline.
I create a ServiceConnection in Azure Devops and added an Service Principal in it.
Agent i am using is 'ubuntu-latest'
I created a powershell task in pipeline
- task: AzureCLI#2
displayName: 'Assign Role'
name: task_inline
inputs:
scriptType: 'pscore'
azureSubscription: 'AzureConnRM'
scriptLocation: scriptPath
addSpnToEnvironment: true
scriptPath: './abc.ps1'
In Powershell to update an existing RBAC Role i am running below command:
az role assignment update --role-assignment $myjson --debug --verbose
and json which i am passing is
$myjson = '{
"conditionVersion": "",
"roleDefinitionName": "Contributor",
"principalType": "User",
"condition": "",
"id": "/subscriptions/097ca710-067e-4a70-8ce6-494268568148/resourceGroups/Trial-RG/providers/Microsoft.Authorization/roleAssignments/45d7dc3c-4a95-8a1c-bd87-f8a460c6d255",
"resourceGroup": "Trial-RG",
"roleDefinitionId": "/subscriptions/097ca710-067e-4a70-8ce6-494268568148/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
"type": "Microsoft.Authorization/roleAssignments",
"scope": "/subscriptions/097ca710-067e-4a70-8ce6-494268568148/resourceGroups/Trial-RG",
"principalId": "8cd5df22-42f4-405e-b3ab-d562eaf1da92",
"canDelegate": "",
"description": "Updated",
"name": "45d7dc3c-4a95-8a1c-bd87-f8a460c6d255"
}'
But get the error:
Error detail: Expecting property name enclosed in double quotes: line 2 column 3 (char 4)

Thanks #Toni
--debug helped me see the detailed log.
3 fields conditionVersion, canDelegate, condition were not getting set correctly. I removed these properties from my json and it worked.

Related

azure function pipeline automate setup

can we automatically create a pipeline for each new function thats created ie fully automate the lot? Im not sure if it possible and wondering if anyone has done or can point me to something that has a set by step pocess?
can we automatically create a pipeline for each new function thats
created ie fully automate the lot?
Yes, you can.
For the simplest situation, for example, this is the deployment pipeline on my side:
trigger:
- none
pool:
vmImage: ubuntu-latest
parameters:
- name: functionname
default: bowman0822
steps:
- task: DownloadBuildArtifacts#1
inputs:
buildType: 'specific'
project: 'xxx'
pipeline: 'xxx'
buildVersionToDownload: 'latest'
downloadType: 'single'
downloadPath: '$(System.ArtifactsDirectory)'
- script: |
dir
displayName: 'Run a multi-line script'
- task: AzureFunctionApp#1
inputs:
azureSubscription: 'testbowman_in_AAD'
appType: 'functionAppLinux'
appName: '${{parameters.functionname}}'
package: '$(System.DefaultWorkingDirectory)/azurefunction'
runtimeStack: 'PYTHON|3.9'
#key step see the below.
- task: PythonScript#0
inputs:
scriptSource: 'inline'
script: |
import requests
import json
org_name = "<The Organization Name>"
project_name = "<The Product Name>"
pipeline_name = "${{parameters.functionname}}"
pat = "<Your Personal Access Token>"
url = "https://dev.azure.com/"+org_name+"/"+project_name+"/_apis/build/definitions?api-version=5.0"
payload = json.dumps({
"name": ""+pipeline_name+"",
"Repository": {
"name": "functiontest",
"type": "TfsGit"
},
"Process": {
"phases": [
{
"name": "Agent job 1",
"refName": "Job_1",
"condition": "succeeded()",
"target": {
"executionOptions": {
"type": 0
},
"allowScriptsAuthAccessOption": False,
"type": 1
},
"jobAuthorizationScope": "project"
}
]
}
})
headers = {
'Authorization': 'Basic '+pat,
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
Successfully created on my side:
Please note that the above sample is the simplest situation, there is nothing in the created pipeline. If you want specific requirements in pipeline, I suggest you to first manually create a pipeline, and then use this API so that from the response you can know how the request structure of Create API should be.
The code above is based on this REST API:
https://learn.microsoft.com/en-us/rest/api/azure/devops/build/definitions/create?view=azure-devops-rest-5.0
By the way, if you want YAML definition, there should be additional step to push the YAML definition to your repo.

How can I pass pipeline variable to parameters file for blueprint assignment

I'm trying to create an Azure DevOps pipeline for deploying Azure Blueprint. There are some fields in the parameters file(JSON) which I want to be configurable. How can I pass these values as pipeline variables and use them in the parameters file?
I tried defining a pipeline variable and reference it in the parameter file like this "$(var-name)", but it didn't work. Is there a way to solve this?
Below is my pipeline definition, I'm using AzureBlueprint extension for creating and assigning blueprint:
steps:
- task: CreateBlueprint#1
inputs:
azureSubscription: $(serviceConnection)
BlueprintName: $(blueprintName)
BlueprintPath: '$(blueprintPath)'
AlternateLocation: false
PublishBlueprint: true
- task: AssignBlueprint#1
inputs:
azureSubscription: $(serviceConnection)
AssignmentName: '$(blueprintName)-assignment'
BlueprintName: $(blueprintName)
ParametersFile: '$(blueprintPath)/assign.json'
SubscriptionID: $(subscriptionId)
Wait: true
Timeout: 500
and my parameters file:
"parameters":{
"organization" : {
"value": "xxxx"
},
"active-directory-domain-services_ad-domain-admin-password" : {
"reference": {
"keyVault": {
"id": "/subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.KeyVault/vaults/xxxx"
},
"secretName": "xxxx"
}
},
"jumpbox_jumpbox-local-admin-password" : {
"reference": {
"keyVault": {
"id": "/subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.KeyVault/vaults/xxxx"
},
"secretName": "xxxx"
}
},
"keyvault_ad-domain-admin-user-password" : {
"value" : "xxxx"
},
"keyvault_deployment-user-object-id" : {
"value" : "xxxx"
},
"keyvault_jumpbox-local-admin-user-password" : {
"value" : "xxxx"
}
}
Since the Tasks (CreateBlueprint and AssignBlueprint) you are using doesn't support overriding parameters, you have two options:
Use the Azure CLI az blueprint command to directly create and assign blueprints.
Change the parameters file bei either using JSON variable substitution or by using a small PowerShell script (see blow):
Sample:
$paramFile = Get-Content ./azuredeploy.parameters.json | ConvertFrom-Json
$paramFile.parameters.organization.value = "your-org-name"
$paramFile | ConvertTo-Json | Set-Content ./azuredeploy.parameters.json
Be aware that the Task you are using hasn't received an update within the last 17 months (here is the GitHub repository).
AssignBlueprint#1 doesn't support natively this. However you can modify assign.json using Json substitution
It comes down to having Azure Pipeline variables with a name like a path to a leaf in the json file which you want to teplace.
Here is an example:
variables:
Data.DebugMode: disabled
Data.DefaultConnection.ConnectionString: 'Data Source=(prodDB)\MSDB;AttachDbFilename=prod.mdf;'
Data.DBAccess.Users.0: Admin-3
Data.FeatureFlags.Preview.1.NewWelcomeMessage: AllAccounts
# Update appsettings.json via FileTransform task.
- task: FileTransform#1
displayName: 'File transformation: appsettings.json'
inputs:
folderPath: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
targetFiles: '**/appsettings.json'
fileType: json

Pass tags (with spaces) to an ARM template using Azure Devops Pipeline

I am using Azure DevOps Pipelines to deploy an ARM template. My template has a tags parameter that I pass into the pipeline using AzureResourceManagerTemplateDeployment#3.
My ARM template has a value in parameters section as an object. tags is an object, which is what many of the sample templates show:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the resource, including its prefix."
}
},
"tags": {
"type": "object",
"defaultValue": {
"Cost Center": "Admin"
}
}
},
"resources": [
{
"apiVersion": "2019-06-01",
"kind": "StorageV2",
"location": "[resourceGroup().location]",
"name": "[parameters('resourceName')]",
"properties": {
"supportsHttpsTrafficOnly": true
},
"sku": {
"name": "Standard_LRS"
},
"type": "Microsoft.Storage/storageAccounts",
"tags": "[parameters('tags')]"
}
]
}
[Edited to match the thread that follows]
I am using ubuntu-latest for my pool. Tags may have spaces.
In my pipeline for simplicity, I set the tags to a variable.
pool:
vmImage: 'ubuntu-latest'
variables:
- name: tags
value: ("Location Region=West US 2" "Environment=${{ parameters.environment }}")
When I call the template deployment, I am passing in the tags as an overrideParameters
- task: AzureResourceManagerTemplateDeployment#3
displayName: "Deploy my templateaccount"
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'ResourceManager-connection'
subscriptionId: ${{ parameters.subscriptionid }}
action: 'Create Or Update Resource Group'
resourceGroupName: '$(resourceGroupName)'
location: '${{ parameters.location }}'
templateLocation: 'Linked artifact'
csmFile: 'mytemplatelocation/azuredeploy.json'
overrideParameters: -resourceName abcdefg76534 -tags "$(tags)"
deploymentMode: 'Incremental'
deploymentOutputs: resourceOutput
- pwsh: Write-Output '$(resourceOutput)'
So far I have not understood how AzureResourceManagerTemplateDeployment#3 on Ubuntu is expecting the tags to be sent.
In each case, the template fails to deploy.
Is this scenario supported in Azure DevOps Pipeline?
Anyone with a suggestion?
The format for the tags that worked in Azure DevOps pipeline AzureResourceManagerTemplateDeployment#3 is to use JSON for your ARM Template objects, such as tags.
Left curly bracket, colon separating the key value pairs, and comma separating the tags.
Each key and the value in my case worked with quotes.
A right curly bracket.
But following templates works by passing in a JSON object: {"Cost Center":"DevTest","Location":"West US"} as your template parameter. In context this looks like:
- task: AzureResourceManagerTemplateDeployment#3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'ResourceManager-connection'
subscriptionId: 'XXXXX'
action: 'Create Or Update Resource Group'
resourceGroupName: 'rg-wus2-exampletest'
location: 'West US 2'
templateLocation: 'Linked artifact'
csmFile: 'storageaccount/example.azuredeploy.json'
csmParametersFile: 'storageaccount/azuredeploy.parameters.json'
overrideParameters: '-resourceName oweruhsow -resourceTags {"Cost Center":"DevTest","Location":"West US"}'
deploymentMode: 'Complete'
This Pipeline module is expecting JSON objects, not the same format used elsewhere with PowerShell (https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resource) to deploy from the command line.
Also as a side note, other posts suggested that you name use something other than tags for your tags parameter. The one that worked for me is resourceTags. Here is my ARM template:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the resource"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for the resources."
}
},
"resourceTags": {
"type": "object",
"defaultValue": {
"Cost Center": "Admin"
}
}
},
"resources": [
{
"apiVersion": "2019-06-01",
"kind": "StorageV2",
"location": "[parameters('location')]",
"name": "[parameters('resourceName')]",
"properties": {
"supportsHttpsTrafficOnly": true
},
"sku": {
"name": "Standard_LRS"
},
"type": "Microsoft.Storage/storageAccounts",
"tags": "[parameters('resourceTags')]"
}
]
}
If you want to set your template object as a the variable, you then can pass it in using the DevOps variable such as $(tags):
variables:
tags: '{"Cost Center":"DevTest","Location":"West US"}'
steps:
- task: AzureResourceManagerTemplateDeployment#3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'ResourceManager-connection'
subscriptionId: '9f241d6e-16e2-4b2b-a485-cc546f04799b'
action: 'Create Or Update Resource Group'
resourceGroupName: 'rg-wus2-exampletest'
location: 'West US 2'
templateLocation: 'Linked artifact'
csmFile: 'storageaccount/example.azuredeploy.json'
csmParametersFile: 'storageaccount/azuredeploy.parameters.json'
overrideParameters: '-resourceName oweruhso11w -resourceTags $(tags)'
deploymentMode: 'Complete'
Also (as a side note), for some reason, the module needed to have a csmParametersFile or it would just fail with something about failing with RESOURCEGROUP in all caps. The param file is not needed to deploy from the command line, but Pipelines modules does seem to require it.
A csmParamters file that can have just about nothing in it, but it seems to be needed.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": { }
}
This also works using the pool image: windows-latest
Many thanks to ToMakesSense in the post at https://github.com/MicrosoftDocs/azure-devops-docs/issues/9051
If the parameter value you're using has multiple words, enclose them in quotes, even if you're passing them using variables.
For example, -name "parameter value" -name2 "$(var)".
Try to use below format:
overrideParameters: -location "${{ parameters.location }}" -tags "$(tags)"
More details please refer our official doc here-- Azure Resource Group Deployment task

"The parameter LinuxFxVersion has an invalid value" when creating WebApp resource from Node.js

I am trying to create a simple WebApp using the Azure SDK for JS in a Node.js environment, but I keep getting the response:
{
"Code":"BadRequest",
"Message":"The parameter LinuxFxVersion has an invalid value.",
"Target":null,
"Details":[
{"Message":"The parameter LinuxFxVersion has an invalid value."},
{"Code":"BadRequest"},
{"ErrorEntity": {
"ExtendedCode":"01007",
"MessageTemplate":"The parameter {0} has an invalid value.",
"Parameters":["LinuxFxVersion"],
"Code":"BadRequest",
"Message":"The parameter LinuxFxVersion has an invalid value."}
}],
"Innererror":null
}
I've tried a variety of different sets of properties and environments with no success. I always get this error. Here's a snippet of the TypeScript code I am using:
const wsmClient: WebSiteManagementClient...
const webAppName: string...
const servicePlanId: string...
const rgName: string...
const envelope: Site = {
name: webAppName,
location: 'westus2',
kind: 'app,linux',
serverFarmId: servicePlanId,
siteConfig: {
linuxFxVersion: 'JAVA|11-java11'
}
};
const appResp = await wsmClient.webApps.createOrUpdate(
rgName,
webAppName,
envelope
);
What am I doing wrong?
Reason:
Your app service plan is not Linux, actually it's Windows. Windows host doesn't have parameter LinuxFxVersion.
If we create a site without explicitly configuring the host as Linux, it will be a Windows host/serverFarm/app service plan by default. Using {"kind":"linux"} is not enough.
Solution:
Explicitly define the app service plan in Linux, and make sure {"reserved": true} to set it as a Linux host (See documentation)
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2019-08-01",
"name": "[parameters('hostingPlanName')]",
"location": "[parameters('location')]",
"kind": "app,linux",
"properties": {
"reserved": true
},
"sku": {
"Tier": "[parameters('hostingPlanSkuTier')]",
"Name": "[parameters('hostingPlanSkuName')]"
}
}
I test your json data, it's caused your properties. Your json data has no "properties" property. If you want to create web with the json property check this web app Rest API request body:Web Apps - Create Or Update.
The correct format should be like the below sample:
{
"location": "CentralUS",
"kind":"app,linux",
"properties":{
"serverFarmId":"your Resource ID",
"siteConfig":{
"linuxFxVersion":"JAVA|11-java11"
}
}
}
#imwenyz answer helped me.
I am running as Azure DevOps pipeline, which has AzureWebApp#1 task. And the app service on Azure that I configured is windows based.
I am getting the error at this task as follows.
##[error]Error: Failed to patch App Service 'BasicReactApp' configuration. Error: BadRequest - The parameter LinuxFxVersion has an invalid value. (CODE: 400)
So I had to modify the task as follows.
- task: AzureWebApp#1
displayName: 'Azure Web App Deploy: '
inputs:
azureSubscription: $(azureSubscription)
#appType: webAppLinux # this is the cause for the error in my case.
appType: webApp
appName: $(webAppName)
runtimeStack: 'NODE|14.x'
package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
startUpCommand: 'npm run start'
Basically, as you can see, changed the appType from webAppLinux to webApp
I had the similar issue while deploying the webapp using Terraform.
resource "azurerm_linux_web_app" "app_service" {
name = "app-name"
location = azurerm_resource_group.resourcegroup.location
resource_group_name = azurerm_resource_group.resourcegroup.name
service_plan_id = azurerm_service_plan.plan.id
site_config {
application_stack {
docker_image = "<image-registry>"
docker_image_tag = var.GIT_VERSION
}
}
}
In my case, docker_image_tag version was not populated correctly. After providing the correct value, Terraform deployed successfully.

Automtically create app service identity when deploying an ARM template for App Service with authentication

I Have been struggling with Azure App Service authentication for a while now. I have CI/CD pipeline running and want to configure app service authentication using an ARM template. See here (part of) my template:
{
"name": "[parameters('apiAppName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('apiHostingPlanName'))]"
],
"properties": {
"name": "[parameters('apiAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('apiHostingPlanName'))]",
"siteConfig": {
"siteAuthEnabled": true,
"siteAuthSettings": {
"unauthenticatedClientAction": 0,
"defaultProvider": 0,
"tokenStoreEnabled": true,
"clientAffinityEnabled": false
}
}
}
}
When deploying this, it still shows all authentication providers as not configured.
To configure the AAD provider, I've only come up with two solutions:
Configure it useing the portal. Not wat I want, manual clicking doesn't combine with continuous delivery
Use Azure Powershell in my release pipeline to create (if not exists) an app registration with client secret and clientid and specify that in the ARM template.
I was wondering, is there any way I can get the needed application identity automatically created? Possibly using / in combination with Managed Service Identity
maybe something like... add a resources array under the existing Microsoft.Web/sites section.
{
"name": "authsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
],
"properties": {
"enabled": true,
"httpApiPrefixPath": null,
"unauthenticatedClientAction": "RedirectToLoginPage",
"tokenStoreEnabled": true,
"allowedExternalRedirectUrls": null,
"defaultProvider": "AzureActiveDirectory",
"clientId": "[variables('clientId')]",
"clientSecret": "[variables('clientSecret')]",
"issuer": "[concat('https://sts.windows.net/', subscription().tenantId, '/')]",
"allowedAudiences": [
"[concat('https://', variables('fqdn'), '/.auth/login/aad/callback')]"
],
"additionalLoginParams": null,
"isAadAutoProvisioned": false
}
}
I tested different options to make it works using only an Arm Template to deploy the webapp and enable directly the auth but it doesnt seems to work. The way i went to stay with a proper CI/CD manner is by adding an extra task with an Azure CLI command enable the auth and assign the app clientId.
My tasks :
- task: RalphJansen.Azure-AD-Application-Management.New-Azure-AD-Application.New-Azure-AD-Application#2
displayName: 'New Azure AD Application'
inputs:
azureSubscription: 'SubscriptionID'
name: '$(apiName)'
signOnUrl: 'https://$(apiName).azurewebsites.net'
- task: AzureResourceGroupDeployment#2
displayName: 'Create WebApp'
inputs:
azureSubscription: 'SubscriptionID'
resourceGroupName: '$(ResourceGroup)'
location: 'Canada East'
csmFile: '$(System.DefaultWorkingDirectory)/_build/drop/azuredeploy.json'
overrideParameters: '-apiName $(apiName) -appServicePlanName $(appServicePlanName)'
- task: AzureCLI#1
displayName: 'Update WebApp to do Oauth authentification & enable Oauth2ImplicitFlow'
inputs:
azureSubscription: 'SubscriptionID'
scriptLocation: inlineScript
inlineScript: |
call az webapp auth update --name $(apiName) --aad-client-id $(out.ApplicationId) --action LoginWithAzureActiveDirectory --enabled true --resource-group "$(ResourceGroup)" --aad-token-issuer-url "https://sts.windows.net/your AAD ID here" --token-store true
call az ad app update --id $(out.ApplicationId) --oauth2-allow-implicit-flow true
Probably a little late, but if you hadn't found an answer yet...
resources[]
"apiVersion": "2018-02-01",
"type": "Microsoft.Web/sites",
"kind": "app",
"name": "[variables('webAppName')]",
"location": "[parameters('location')]",
"identity": {
"type": "SystemAssigned"
},
and include the servicePrincpalId in outputs so that it can be re-used for setting access to the required resources keyvault; blob; sql etc
"outputs": {
"appServicePrincipalId": {
"type": "string",
"value": "[reference(concat(resourceId('Microsoft.Web/sites/', variables('webAppName')),'/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]"
},

Resources