Greetings to my fellow Technology Advocates and Specialists.
In this Session, I will demonstrateHow to Automate Azure Container Registry (ACR) Service Connection using Devops.
# TOPICS 1. Install Azure Devops CLI Extension in the Build Agent. 2. Validate Azure Devops CLI Extension Installation by running the Help option in the Build Agent. 3. Download Key Vault Secrets. 4. Create Azure Container Registry Service Connection. 5. Grant Access Permission to Azure Container Registry Service Connection for all Pipelines.
The YAML Pipeline is tested onWINDOWS BUILD AGENT Only!!!
Azure Subscription. Azure DevOps Organisation and Project. Full Access PAT (Personal Access Token). Service Principal with Required RBAC ( Contributor) applied on Subscription or Resource Group(s). Azure Resource Manager Service Connection in Azure DevOps. Azure Container Registry with "Admin" User Enabled. Key Vault with 3 Secrets stored - 1) Azure Container Registry password, 2) Azure DevOps Project ID, and 3) Azure Devops Personal Access Token (PAT). CODE REPOSITORY:- Setup ACR Service Connection using Devops
LIST OF AZURE RESOURCES DEPLOYED AND CONFIGURED FOR THIS AUTOMATION:- Azure Container Registry with "Admin" user enabled Key Vault with 3 Secrets stored - 1) Azure Container Registry password, 2) Azure DevOps Project ID, and 3) Azure Devops Personal Access Token (PAT).
HOW DOES MY CODE PLACEHOLDER LOOKS LIKE:-
AZURE DEVOPS YAML PIPELINE (azure-pipelines-acr-service-connection-v1.0.yml):-
trigger: none####################### Declare Parameters:-######################parameters: - name: DevOpsOrganisation type: string default: https://dev.azure.com/ArindamMitra0251 values: - https://dev.azure.com/ArindamMitra0251- name: DevOpsProjName type: string default: AMCLOUD values: - AMCLOUD- name: KVNAME displayName: Please Provide the Keyvault Name:- type: object default: ampockv- name: ACRName type: object default: ampocapplacr- name: ACRSrvConnectionName type: object default: AM-ACR-Srv-Connection######################## Declare Variables:-#######################variables: ServiceConnection: 'amcloud-cicd-service-connection' BuildAgent: 'windows-latest' emailID: "mail2arindam2003@yahoo.com"####################### Declare Build Agent:-######################pool: vmImage: '$(BuildAgent)'#################### Declare Stages:-###################stages:- stage: Az_DevOps_ACR_Service_Connection jobs: - job: Setup_ACR_Service_Connection displayName: Setup ACR Service Connection steps:######################################################### Install Az DevOps CLI Extension in the Build Agent:-####################################################### - task: AzureCLI@1 displayName: Install Devops CLI Extension inputs: azureSubscription: '$(ServiceConnection)' scriptType: ps scriptLocation: inlineScript inlineScript: | az extension add --name azure-devops az extension show --name azure-devops --output table################################################################ Help Option of Az DevOps CLI Extension in the Build Agent:-############################################################### - task: PowerShell@2 displayName: Help Option of Az Devops CLI inputs: targetType: 'inline' script: | az devops -h################################ # Download Keyvault Secrets:-################################ - task: AzureKeyVault@2 displayName: Fetch all Secrets from Keyvault inputs: azureSubscription: '$(ServiceConnection)' KeyVaultName: '${{ parameters.KVNAME }}' SecretsFilter: '*' RunAsPreJob: false############################################################# Create ACR Service Connection in Azure DevOps Project:-############################################################ - task: PowerShell@2 displayName: Create ACR Service Connection inputs: targetType: 'inline' script: | $B64Pat = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$(PAT)")) $header = @{ 'Authorization' = 'Basic ' + $B64Pat 'Content-Type' = 'application/json' } $body = '{ "data": {}, "name": "${{ parameters.ACRSrvConnectionName }}", "type": "dockerregistry", "authorization": { "parameters": { "username": "${{ parameters.ACRName }}", "password": "$(ACRPasswd)", "email": "$(emailID)", "registry": "https://${{ parameters.ACRName }}.azurecr.io" }, "scheme": "UsernamePassword" }, "isShared": false, "isReady": true, "serviceEndpointProjectReferences": [ { "projectReference": { "id": "$(AMCLOUD-DevOps-Prj-ID)", "name": "${{ parameters.DevOpsProjName }}" }, "name": "${{ parameters.ACRSrvConnectionName }}" } ] }' $srvEndpointID = Invoke-RestMethod -Method Post -Uri ${{ parameters.DevOpsOrganisation }}/_apis/serviceendpoint/endpoints?api-version=6.0-preview.4 -Headers $header -Body $body | Select -ExpandProperty id echo "#####################################################################################" echo "ACR Service Connection ${{ parameters.ACRSrvConnectionName }} created successfully." echo "#####################################################################################" $patchbody = '{ "allPipelines": { "authorized": true, "authorizedBy": null, "authorizedOn": null }, "pipelines": null, "resource": { "id": "$srvEndpointID", "type": "endpoint" } }' Invoke-RestMethod -Method PATCH -Uri ${{ parameters.DevOpsOrganisation }}/${{ parameters.DevOpsProjName }}/_apis/pipelines/pipelinepermissions/endpoint/"$srvEndpointID"?api-version=7.0-preview.1 -Headers $header -Body $patchbody echo "###############################################################################################################" echo "ACR Service Connection ${{ parameters.ACRSrvConnectionName }} was granted access permission to all Pipelines." echo "###############################################################################################################"
Enter fullscreen mode Exit fullscreen mode Now, let me explain each part of YAML Pipeline for better understanding.
BELOW FOLLOWS PIPELINE RUNTIME VARIABLES CODE SNIPPET:-
####################### Declare Parameters:-######################parameters: - name: DevOpsOrganisation type: string default: https://dev.azure.com/ArindamMitra0251 values: - https://dev.azure.com/ArindamMitra0251- name: DevOpsProjName type: string default: AMCLOUD values: - AMCLOUD- name: KVNAME displayName: Please Provide the Keyvault Name:- type: object default: ampockv- name: ACRName type: object default: ampocapplacr- name: ACRSrvConnectionName type: object default: AM-ACR-Srv-Connection
Enter fullscreen mode Exit fullscreen mode THIS IS HOW IT LOOKS:-
BELOW FOLLOWS PIPELINE VARIABLES CODE SNIPPET:-
######################## Declare Variables:-#######################variables: ServiceConnection: 'amcloud-cicd-service-connection' BuildAgent: 'windows-latest' emailID: "mail2arindam2003@yahoo.com"
Enter fullscreen mode Exit fullscreen mode NOTE:- Please change the values of the variables accordingly. The entire YAML pipeline is build using Runtime Parameters and Variables. No Values are Hardcoded.
This is a Single Stage Pipeline - Az_DevOps_ACR_Service_Connection (with 4 Pipeline Tasks):-
#################### Declare Stages:-###################stages:- stage: Az_DevOps_ACR_Service_Connection jobs: - job: Setup_ACR_Service_Connection displayName: Setup ACR Service Connection steps:
Enter fullscreen mode Exit fullscreen mode PIPELINE TASK #1:-:- Install Az DevOps CLI Extension in the Build Agent.
######################################################### Install Az DevOps CLI Extension in the Build Agent:-####################################################### - task: AzureCLI@1 displayName: Install Devops CLI Extension inputs: azureSubscription: '$(ServiceConnection)' scriptType: ps scriptLocation: inlineScript inlineScript: | az extension add --name azure-devops az extension show --name azure-devops --output table
Enter fullscreen mode Exit fullscreen mode PIPELINE TASK #2:-:- Validate installation of Az DevOps CLI Extension in the Build Agent by running the Help option.
################################################################ Help Option of Az DevOps CLI Extension in the Build Agent:-############################################################### - task: PowerShell@2 displayName: Help Option of Az Devops CLI inputs: targetType: 'inline' script: | az devops -h
Enter fullscreen mode Exit fullscreen mode PIPELINE TASK #3:-:- Download all secrets from Keyvault.
################################ # Download Keyvault Secrets:-################################ - task: AzureKeyVault@2 displayName: Fetch all Secrets from Keyvault inputs: azureSubscription: '$(ServiceConnection)' KeyVaultName: '${{ parameters.KVNAME }}' SecretsFilter: '*' RunAsPreJob: false
Enter fullscreen mode Exit fullscreen mode PIPELINE TASK #4:-:- Create ACR Service Connection in Azure DevOps Project. Grant the newly created ACR Service Connection in Azure DevOps Project access permission to all Pipelines.
############################################################# Create ACR Service Connection in Azure DevOps Project:-############################################################ - task: PowerShell@2 displayName: Create ACR Service Connection inputs: targetType: 'inline' script: | $B64Pat = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$(PAT)")) $header = @{ 'Authorization' = 'Basic ' + $B64Pat 'Content-Type' = 'application/json' } $body = '{ "data": {}, "name": "${{ parameters.ACRSrvConnectionName }}", "type": "dockerregistry", "authorization": { "parameters": { "username": "${{ parameters.ACRName }}", "password": "$(ACRPasswd)", "email": "$(emailID)", "registry": "https://${{ parameters.ACRName }}.azurecr.io" }, "scheme": "UsernamePassword" }, "isShared": false, "isReady": true, "serviceEndpointProjectReferences": [ { "projectReference": { "id": "$(AMCLOUD-DevOps-Prj-ID)", "name": "${{ parameters.DevOpsProjName }}" }, "name": "${{ parameters.ACRSrvConnectionName }}" } ] }' $srvEndpointID = Invoke-RestMethod -Method Post -Uri ${{ parameters.DevOpsOrganisation }}/_apis/serviceendpoint/endpoints?api-version=6.0-preview.4 -Headers $header -Body $body | Select -ExpandProperty id echo "#####################################################################################" echo "ACR Service Connection ${{ parameters.ACRSrvConnectionName }} created successfully." echo "#####################################################################################" $patchbody = '{ "allPipelines": { "authorized": true, "authorizedBy": null, "authorizedOn": null }, "pipelines": null, "resource": { "id": "$srvEndpointID", "type": "endpoint" } }' Invoke-RestMethod -Method PATCH -Uri ${{ parameters.DevOpsOrganisation }}/${{ parameters.DevOpsProjName }}/_apis/pipelines/pipelinepermissions/endpoint/"$srvEndpointID"?api-version=7.0-preview.1 -Headers $header -Body $patchbody echo "###############################################################################################################" echo "ACR Service Connection ${{ parameters.ACRSrvConnectionName }} was granted access permission to all Pipelines." echo "###############################################################################################################"
Enter fullscreen mode Exit fullscreen mode NOTE:- Passing PAT as Pipeline Runtime variable or Fetching it from Key Vault and use it as Environmental variables will not work and it will throw below error. Refer theGithub Issue: 24108 Sample format of the JSON Config file is used to prepare the "$body" variable section. It can be foundhere
NOW ITS TIME TO TEST!!!
TEST CASES:- 1. Pipeline executed successfully. 2. ACR Service connection created successfully in the Devops project.
Hope You Enjoyed the Session!!!
Stay Safe | Keep Learning | Spread Knowledge