paint-brush
Automação de direitos, permissões e níveis de acesso no Azure DevOpspor@socialdiscoverygroup
12,833 leituras
12,833 leituras

Automação de direitos, permissões e níveis de acesso no Azure DevOps

por Social Discovery Group6m2023/11/29
Read on Terminal Reader

Muito longo; Para ler

Quando o negócio está crescendo rapidamente, um engenheiro de DevOps enfrenta o desafio de automatizar processos em todos os sistemas usados para CI/CD, incluindo gerenciamento de acesso manual. Essas tarefas rotineiras retardam drasticamente a resolução das solicitações dos clientes. No artigo, a equipe do Social Discovery Group compartilha soluções personalizadas para automatizar direitos, permissões e níveis de acesso no Azure DevOps.
featured image - Automação de direitos, permissões e níveis de acesso no Azure DevOps
Social Discovery Group HackerNoon profile picture
0-item

Quando o negócio está crescendo rapidamente, um engenheiro de DevOps enfrenta o desafio de automatizar processos em todos os sistemas usados para CI/CD, incluindo gerenciamento de acesso manual. Essas tarefas rotineiras podem ser aceitáveis quando você tem uma equipe pequena, com até 10 releases com 3 estágios cada e 10 grupos variáveis.


Porém, imagine se sua equipe crescer para centenas de pessoas que precisam operar manualmente com até 500 liberações, cada uma com 10 estágios e 200 grupos variáveis. Nesse caso, o gerenciamento manual de acesso retarda drasticamente a resolução das solicitações dos clientes.


Nesta fase, todas as empresas enfrentam a necessidade de uma automatização eficiente.


No Social Discovery Group, contamos com o Azure DevOps como principal tecnologia de nuvem. No entanto, atualmente, falta a funcionalidade para automatizar direitos, permissões e níveis de acesso. Para atender prontamente às necessidades do usuário, decidimos encontrar algumas soluções personalizadas e automatizar a atribuição de permissões.

Como automatizar no Azure DevOps

Neste artigo, compartilharemos algumas boas dicas sobre como automatizar certas tarefas de rotina no Azure DevOps, com foco em:


  • Atribuir permissões a um grupo ou usuário para grupos variáveis com base em uma máscara usando Azure Pipeline.


  • Atribuir permissões de grupo ou usuário a estágios específicos para grupos de lançamento inteiros, categorizados em grupos de catálogos usando o Azure Pipeline.

A pilha de tecnologia usada: Azure Services, Azure DevOps, Bash, Azure CLI

Atualmente, o Azure oferece 3 opções para atribuir permissões: utilizando a interface gráfica do site, utilizando o az DevOps CLI e os pedidos de API. A primeira opção é a mais simples e rápida; no entanto, à medida que a empresa cresce e o número de pipelines e variáveis de CI/CD aumenta, a atribuição manual de permissões torna-se demorada.


A segunda opção para conceder permissões tem funcionalidade limitada; ou seja, o usuário não pode ir além do que uma determinada equipe oferece. A terceira opção através da API REST é a mais versátil no momento. Vamos considerar um exemplo específico em que temos vários pipelines de lançamento com vários estágios:


Liberar pipelines com vários estágios


Liberar pipelines com vários estágios


Cada estágio de implantação requer permissão de um usuário/grupo específico (a chamada função de aprovações pré-implantação). Um problema aparece aqui quando um usuário ou grupo específico precisa ser adicionado ou removido de uma determinada lista de aprovadores.


À medida que a empresa se expande, quando o número de pipelines e estágios aumenta N vezes, o caso rotineiro se torna um problema, e a solução para esse problema só é possível por meio de solicitações de API. Esta é a aparência da implementação do nosso lado:


 " pool: vmImage: ubuntu-latest parameters: - name: folder_names type: string default: '\' - name: stage_names type: string default: 'Dev' - name: group_names type: string default: 'Devops' variables: - name: organization value: ORGANIZATION - name: project value: PROJECT - name: pat Value: PAT steps: - bash: | export organization="$(organization)" export project="$(project)" export pat="$(pat)" export folder_names='${{ parameters.folder_names }}' export stage_names='${{ parameters.stage_names }}' export group_names='${{ parameters.group_names }}' export pipeline_name_array=() export stage_name_array=() export group_name_array=() IFS=',' read -ra folder_name_array <<< "$folder_names" IFS=',' read -ra stage_name_array <<< "$stage_names" IFS=',' read -ra group_name_array <<< "$group_names" # Make a GET request to retrieve the release pipelines within the specified project pipeline_url="https://vsrm.dev.azure.com/$organization/$project/_apis/release/definitions?api-version=7.0" pipeline_response=$(curl -s -u ":$pat" "$pipeline_url") # Check for errors in the response if [[ "$pipeline_response" == *"error"* ]]; then echo "Error fetching release pipeline data." exit 1 fi pipeline_names=($(echo "$pipeline_response" | jq -r '.value[].name')) pipeline_ids=($(echo "$pipeline_response" | jq -r '.value[].id')) for ((i=0; i<${#pipeline_names[@]}; i++)); do pipeline_name="${pipeline_names[i]}" pipeline_id="${pipeline_ids[i]}" # Make a GET request to retrieve the release pipeline details pipeline_detail_url="https://vsrm.dev.azure.com/$organization/$project/_apis/release/definitions/$pipeline_id?api-version=7.0" pipeline_detail_response=$(curl -s -u ":$pat" "$pipeline_detail_url") # Extract the releaseDefinition.path from the pipeline details pipeline_path=$(echo "$pipeline_detail_response" | jq -r '.path') # Check if the pipeline_path matches any of the specified folder_names for folder_name in "${folder_name_array[@]}"; do if [[ "$pipeline_path" == *"$folder_name"* ]]; then # Make a GET request to retrieve all releases for the specified pipeline releases_url="https://vsrm.dev.azure.com/$organization/$project/_apis/release/releases?api-version=7.0&definitionId=$pipeline_id" releases_response=$(curl -s -u ":$pat" "$releases_url") # Extract the release names release_names=$(echo "$releases_response" | jq -r '.value[].id') release_definition_url="https://vsrm.dev.azure.com/$organization/$project/_apis/release/definitions/$pipeline_id?api-version=7.0" release_definition_response=$(curl -s -u ":$pat" "$release_definition_url") # Iterate through each group name for group_name in "${group_name_array[@]}"; do # Make a GET request to retrieve the list of groups groups_response=$(curl -s -u ":$pat" "https://vssps.dev.azure.com/$organization/_apis/graph/groups?api-version=7.1-preview.1") # Find the origin_id for the specified group name origin_id=$(echo "$groups_response" | jq -r ".value[] | select(.displayName == \"$group_name\") | .originId") if [ -z "$origin_id" ]; then echo "Group '$group_name' not found or origin_id not available for release '$release_name'." else # Iterate through each stage name for stage_name in "${stage_name_array[@]}"; do # Construct the JSON structure for the new approval new_approval='{ "rank": 1, "isAutomated": false, "isNotificationOn": false, "approver": { "id": "'"$origin_id"'" } }' # Use jq to update the JSON structure for the specified stage updated_definition=$(echo "$release_definition_response" | jq --argjson new_approval "$new_approval" '.environments |= map(if .name == "'"$stage_name"'" then .preDeployApprovals.approvals += [$new_approval] else . end)') # Make a PUT request to update the release definition for the specified stage put_response=$(curl -s -u ":$pat" -X PUT -H "Content-Type: application/json" -d "$updated_definition" "$release_definition_url") release_definition_response=$(curl -s -u ":$pat" "$release_definition_url") # Check if the update was successful if [[ "$put_response" == *"The resource could not be found."* ]]; then echo "Error updating release definition for stage '$stage_name' and group '$group_name'." else echo "Pre-deployment approval added successfully to stage '$stage_name' for group '$group_name' in '$pipeline_id'." fi done fi done fi done done displayName: 'PreDeployApprovals' "


Um problema semelhante surge com a seção Biblioteca quando vários grupos de variáveis são criados, onde uma palavra específica é usada para indicar afiliação a algo. Vamos analisar um exemplo em que vários grupos de variáveis são criados contendo a palavra "SERVIÇOS" para denotar sua afiliação com variáveis relacionadas ao serviço.


E examine também um cenário em que um grupo específico precisa de acesso a todas as variáveis com determinadas permissões.


Seção da biblioteca quando vários grupos de variáveis


A solução para este caso comum também só é possível através da API REST:


 " variables: - name: organization value: ORGANIZATION - name: project value: PROJECT - name: pat value: PAT parameters: - name: searchWord type: string default: 'SERVICES' - name: UserOrGroupName type: string default: 'Devops' - name: UserRights type: string default: 'Administrator' steps: - bash: | export organization="$(organization)" export project="$(project)" export pat="$(pat)" export userOrGroupName='${{ parameters.UserOrGroupName }}' export UserRights='${{ parameters.UserRights }}' export searchWord='${{ parameters.searchWord }}' # Perform the API request and store the JSON response in a variable response=$(curl -s -u ":$pat" "https://dev.azure.com/$organization/$project/_apis/distributedtask/variablegroups?api-version=6.0") # Initialize an empty array to store matching JSON objects matching_json=() # Loop through the JSON objects and append matching objects to the array while read -r json; do if [[ $(echo "$json" | jq -r '.name' | grep "$searchWord") ]]; then matching_json+=("$json") fi done < <(echo "$response" | jq -c '.value[]') # Iterate through the matching variable groups and assign permissions for group in "${matching_json[@]}"; do # Extract the variable group ID and name variableGroupId=$(echo "$group" | jq -r '.id') variableGroupName=$(echo "$group" | jq -r '.name') # Determine the type of userOrGroupName (username or group name) if [[ $myString != *'@'* ]]; then # If userOrGroupName matches the username format, it's treated as a username roleName=$UserRights assignType="group" groupsResponse=$(curl -s -u ":$pat" "https://vssps.dev.azure.com/$organization/_apis/graph/groups?api-version=6.0-preview.1") #groupOriginId=$(curl -s -u ":$pat" "https://vssps.dev.azure.com/$organization/_apis/identities?searchFilter=$userOrGroupName&api-version=6.0" | jq -r '.value[0].originId') groupOriginId=$(echo "$groupsResponse" | jq -r ".value[] | select(.displayName == \"$userOrGroupName\") | .originId") # Get the user's originId using Azure DevOps REST API #userOriginId=$(curl -s -u ":$pat" "https://vssps.dev.azure.com/$organization/_apis/identities?searchFilter=$userOrGroupName&api-version=6.0" | jq -r '.value[0].principalName') else # Otherwise, it's treated as a group name roleName=$UserRights assignType="user" userOriginId=$(curl -s -u ":$pat" "https://vssps.dev.azure.com/$organization/_apis/identities?searchFilter=$userOrGroupName&api-version=6.0" | jq -r '.value[0].principalName') # Get the group's originId using Azure DevOps REST API #groupOriginId=$(curl -s -u ":$pat" "https://vssps.dev.azure.com/$organization/_apis/identities?searchFilter=$userOrGroupName&api-version=6.0" | jq -r '.value[0].originId') fi # Construct the API URL for assigning permissions apiUrl="https://dev.azure.com/$organization/_apis/securityroles/scopes/distributedtask.variablegroup/roleassignments/resources/19802563-1b7b-43d6-81e0-16cf29d68c0d$"$variableGroupId"?api-version=5.1-preview" # Assign permissions based on the userOrGroupName type if [ "$assignType" == "group" ]; then # Assign permissions to a group # Construct the request body with group's originId requestBody="[{ \"roleName\": \"$roleName\", \"userId\": \"$groupOriginId\" }]" else # Assign permissions to a user # Construct the request body with the user's uniqueName requestBody="[{ \"roleName\": \"$roleName\", \"uniqueName\": \"$userOrGroupName\" }]" fi # Execute the REST API call to assign permissions response=$(curl -s -u ":$pat" -X PUT -H "Content-Type: application/json" -d "$requestBody" "$apiUrl") # Check if the permissions were successfully assigned if [[ "$response" == *"error"* ]]; then echo "Error assigning permissions to $assignType '$userOrGroupName' in variable group '$variableGroupName'." else echo "Permissions assigned successfully to $assignType '$userOrGroupName' in variable group '$variableGroupName'." fi done displayName: 'variable-groups' "


Ao automatizar esses processos, obtivemos uma compreensão mais detalhada dos direitos e estruturas de permissão no Azure DevOps, aumentando a segurança do projeto.


Agora temos pipelines estáveis e versáteis para uma ampla gama de tarefas, agilizando o tempo de processamento das solicitações dos usuários e melhorando sua qualidade de execução.


Além disso, a velocidade e a qualidade geral do desenvolvimento do nosso sistema melhoraram porque alocamos mais tempo para outras tarefas de CI/CD, nos afastando das ações rotineiras.


Fizemos um esforço significativo para automatizar tarefas diárias, explorar e analisar várias opções de implementação, depurar e refinar. Ter pipelines e scripts prontos é uma enorme conveniência, pois eles podem realizar tarefas em questão de segundos.