paint-brush
Automatización de derechos, permisos y niveles de acceso en Azure DevOpspor@socialdiscoverygroup
12,818 lecturas
12,818 lecturas

Automatización de derechos, permisos y niveles de acceso en Azure DevOps

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

Demasiado Largo; Para Leer

Cuando el negocio crece rápidamente, un ingeniero de DevOps enfrenta el desafío de automatizar procesos en todos los sistemas utilizados para CI/CD, incluida la gestión de acceso manual. Estas tareas rutinarias ralentizan drásticamente la resolución de las solicitudes de los clientes. En el artículo, el equipo de Social Discovery Group comparte soluciones personalizadas para automatizar derechos, permisos y niveles de acceso en Azure DevOps.
featured image - Automatización de derechos, permisos y niveles de acceso en Azure DevOps
Social Discovery Group HackerNoon profile picture
0-item

Cuando el negocio crece rápidamente, un ingeniero de DevOps enfrenta el desafío de automatizar procesos en todos los sistemas utilizados para CI/CD, incluida la gestión de acceso manual. Estas tareas rutinarias pueden ser aceptables cuando se tiene un equipo pequeño, hasta 10 versiones con 3 etapas cada una y 10 grupos variables.


Sin embargo, imagine si su equipo crece hasta tener cientos de personas que necesitan operar manualmente con hasta 500 versiones, cada una con 10 etapas y 200 grupos variables. En este caso, la gestión de acceso manual ralentiza drásticamente la resolución de las solicitudes de los clientes.


En esta etapa, todas las empresas enfrentan la necesidad de una automatización eficiente.


En Social Discovery Group, confiamos en Azure DevOps como la principal tecnología de nube. Sin embargo, actualmente carece de la funcionalidad para automatizar derechos, permisos y niveles de acceso. Para abordar las necesidades de los usuarios con prontitud, decidimos buscar algunas soluciones personalizadas y automatizar la asignación de permisos.

Cómo automatizar en Azure DevOps

En este artículo, compartiremos algunos buenos trucos sobre cómo automatizar ciertas tareas rutinarias en Azure DevOps, centrándonos en:


  • Asignar permisos a un grupo o usuario para grupos de variables en función de una máscara mediante Azure Pipeline.


  • Asignar permisos de grupo o usuario a etapas específicas para grupos de versiones completos, categorizados en grupos de catálogo mediante Azure Pipeline.

La pila de tecnología utilizada: servicios de Azure, Azure DevOps, Bash, CLI de Azure

Actualmente, Azure ofrece tres opciones para asignar permisos: usar la interfaz gráfica del sitio, usar la CLI de az DevOps y las solicitudes de API. La primera opción es la más sencilla y rápida; sin embargo, a medida que la empresa crece y aumenta el número de canales y variables de CI/CD, la asignación manual de permisos lleva mucho tiempo.


La segunda opción para otorgar permisos tiene una funcionalidad limitada; es decir, el usuario no puede ir más allá de lo que ofrece un equipo específico. La tercera opción a través de la API REST es la más versátil en estos momentos. Consideremos un ejemplo específico en el que tenemos numerosos procesos de lanzamiento con múltiples etapas:


Canalizaciones de lanzamiento con múltiples etapas


Canalizaciones de lanzamiento con múltiples etapas


Cada etapa de implementación requiere permiso de un usuario/grupo específico (la llamada función de aprobaciones previas a la implementación). Aquí aparece un problema cuando es necesario agregar o eliminar un usuario o grupo específico de una lista determinada de aprobadores.


A medida que la empresa se expande, cuando el número de tuberías y etapas aumenta N veces, el caso de rutina se convierte en un problema y la solución a este problema solo es posible a través de solicitudes de API. Así es como se ve la implementación desde nuestro 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' "


Un problema similar surge con la sección Biblioteca cuando se crean numerosos grupos de variables, donde se usa una palabra específica para indicar afiliación con algo. Analicemos un ejemplo en el que se crean varios grupos de variables que contienen la palabra "SERVICIOS" para indicar su afiliación con variables relacionadas con el servicio.


Y también examine un escenario en el que un grupo específico necesita acceso a todas las variables con ciertos permisos.


Sección de biblioteca cuando numerosos grupos de variables


La solución a este caso común también es posible únicamente a través de la 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' "


Al automatizar estos procesos, obtuvimos una comprensión más detallada de las estructuras de derechos y permisos en Azure DevOps, lo que mejoró la seguridad del proyecto.


Ahora contamos con canales estables y versátiles para una amplia gama de tareas, acelerando el tiempo de procesamiento de las solicitudes de los usuarios y mejorando su calidad de ejecución.


Además, la velocidad y la calidad generales del desarrollo de nuestro sistema han mejorado porque asignamos más tiempo a otras tareas de CI/CD, alejándonos de las acciones rutinarias.


Hemos realizado un gran esfuerzo para automatizar las tareas diarias, explorar y analizar varias opciones de implementación, depurar y perfeccionar. Tener scripts y canalizaciones listos para usar es una gran comodidad, ya que pueden realizar tareas en cuestión de segundos.