Compartir vía


Uso de plantillas para la seguridad

Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2020

En este artículo se describe cómo las plantillas pueden simplificar la seguridad de Azure Pipelines. Las plantillas pueden definir la estructura externa de la canalización y ayudar a evitar la infiltración de código malintencionada. Las plantillas también pueden incluir automáticamente pasos para realizar tareas como el examen de credenciales. Si varias canalizaciones de su equipo u organización comparten la misma estructura, considere la posibilidad de usar plantillas.

Las comprobaciones en los recursos protegidos forman el marco de seguridad fundamental para Azure Pipelines. Estas comprobaciones se aplican independientemente de la estructura de canalización, las fases y los trabajos. Puede usar plantillas para ayudar a aplicar estas comprobaciones.

Incluye y amplía plantillas

Azure Pipelines proporciona plantillas de inclusión y extensión.

  • Las plantillas incluyen el código de la plantilla directamente en el archivo externo que hace referencia a ella, similar a #include en C++. En la siguiente canalización de ejemplo se inserta la plantilla de include-npm-steps.yml en la steps sección .

      steps:
      - template: templates/include-npm-steps.yml 
    
  • Amplía las plantillas para definir la estructura externa de la canalización y ofrecer puntos específicos para las personalizaciones dirigidas. En el contexto de C++, las extends plantillas se asemejan a la herencia.

Al usar extends plantillas, también puede usar includes en la plantilla y en la canalización final para realizar partes de configuración comunes. Para obtener una referencia completa, consulte la referencia de uso de plantillas.

Extiende las plantillas

Para las canalizaciones más seguras, empiece por usar plantillas de extensión. Estas plantillas definen la estructura externa de la canalización y evitan que el código malintencionado se infiltra en la canalización.

Por ejemplo, el siguiente archivo de plantilla se denomina template.yml.

parameters:
- name: usersteps
  type: stepList
  default: []
steps:
- ${{ each step in parameters.usersteps }}:
  - ${{ step }}

La siguiente canalización amplía la plantilla de template.yml .

# azure-pipelines.yml
resources:
  repositories:
  - repository: templates
    type: git
    name: MyProject/MyTemplates
    ref: refs/tags/v1

extends:
  template: template.yml@templates
  parameters:
    usersteps:
    - script: echo This is my first step
    - script: echo This is my second step

Sugerencia

Al configurar extends plantillas, considere la posibilidad de anclarlas a una rama o etiqueta de Git determinada, por lo que si hay cambios importantes, las canalizaciones existentes no se ven afectadas. En el ejemplo anterior se usa esta característica.

Características de seguridad de canalización de YAML

La sintaxis de la canalización YAML incluye varias protecciones integradas. Extiende la plantilla puede aplicar su uso. Para mejorar la seguridad de la canalización, puede implementar cualquiera de las restricciones siguientes.

Destinos de paso

Puede restringir determinados pasos para ejecutarse en un contenedor en lugar de en el host. Los pasos de los contenedores no tienen acceso al host del agente, lo que impide que estos pasos modifiquen la configuración del agente o salgan de código malintencionado para su ejecución posterior.

Por ejemplo, considere la posibilidad de limitar el acceso a la red. Sin acceso a la red abierta, los pasos de usuario no pueden recuperar paquetes de orígenes no autorizados ni cargar código y secretos en ubicaciones de red externas.

La canalización de ejemplo siguiente ejecuta los pasos en el host del agente antes de ejecutar pasos dentro de un contenedor.

resources:
  containers:
  - container: builder
    image: mysecurebuildcontainer:latest
steps:
- script: echo This step runs on the agent host, and it could use Docker commands to tear down or limit the container's network
- script: echo This step runs inside the builder container
  target: builder

Restricciones de comandos de registro de agentes

Puede restringir los servicios que proporciona el agente de Azure Pipelines a los pasos del usuario. Los pasos del usuario solicitan servicios mediante comandos de registro, que tienen un formato especial de cadenas impresas en la salida estándar. En modo restringido, la mayoría de los servicios del agente, como cargar artefactos y adjuntar resultados de pruebas, no están disponibles.

Se produce un error en la tarea de ejemplo siguiente porque su target propiedad indica al agente que no permita publicar artefactos.

- task: PublishBuildArtifacts@1
  inputs:
    artifactName: myartifacts
  target:
    commands: restricted

En restricted el modo, el setvariable comando sigue siendo permitido, por lo que es necesario tener precaución porque las variables de canalización se exportan como variables de entorno a tareas posteriores. Si las tareas generan datos proporcionados por el usuario, como problemas abiertos recuperados a través de una API REST, podrían ser vulnerables a ataques por inyección. El contenido de usuario malintencionado podría establecer variables de entorno que podrían aprovecharse para poner en peligro el host del agente.

Para mitigar este riesgo, los autores de canalizaciones pueden declarar explícitamente qué variables se pueden establecer mediante el setvariable comando de registro. Al especificar una lista vacía, no se permite ninguna configuración de variable.

Se produce un error en la siguiente tarea de ejemplo porque la tarea solo puede establecer la expectedVar variable o una variable con okel prefijo .

- task: PowerShell@2
  target:
    commands: restricted
    settableVariables:
    - expectedVar
    - ok*
  inputs:
    targetType: 'inline'
    script: |
      Write-Host "##vso[task.setvariable variable=BadVar]myValue"

Fase condicional o ejecución del trabajo

Puede restringir las fases y los trabajos para que solo se ejecuten en condiciones específicas. En el ejemplo siguiente, la condición garantiza que el código restringido se compile solo para la rama principal.

jobs:
- job: buildNormal
  steps:
  - script: echo Building the normal, unsensitive part
- ${{ if eq(variables['Build.SourceBranchName'], 'refs/heads/main') }}:
  - job: buildMainOnly
    steps:
    - script: echo Building the restricted part that only builds for main branch

Modificación de sintaxis

Las plantillas de Azure Pipelines tienen la flexibilidad de iterar y modificar la sintaxis de YAML. Mediante la iteración, puede aplicar características de seguridad yaML específicas.

Una plantilla también puede reescribir los pasos de usuario, lo que permite que solo se ejecuten las tareas aprobadas. Por ejemplo, puede evitar la ejecución de scripts insertados.

La plantilla de ejemplo siguiente impide que se ejecuten los tipos bashde paso , powershell, pwshy script . Para un bloqueo completo de scripts ad hoc, también puede bloquear BatchScript y ShellScript.

# template.yml
parameters:
- name: usersteps
  type: stepList
  default: []
steps:
- ${{ each step in parameters.usersteps }}:
  - ${{ if not(or(startsWith(step.task, 'Bash'),startsWith(step.task, 'CmdLine'),startsWith(step.task, 'PowerShell'))) }}:  
    - ${{ step }}
  # The following lines replace tasks like Bash@3, CmdLine@2, PowerShell@2
  - ${{ else }}:  
    - ${{ each pair in step }}:
        ${{ if eq(pair.key, 'inputs') }}:
          inputs:
            ${{ each attribute in pair.value }}:
              ${{ if eq(attribute.key, 'script') }}:
                script: echo "Script removed by template"
              ${{ else }}:
                ${{ attribute.key }}: ${{ attribute.value }}
        ${{ elseif ne(pair.key, 'displayName') }}:
          ${{ pair.key }}: ${{ pair.value }}

          displayName: 'Disabled by template: ${{ step.displayName }}'

En la siguiente canalización que extiende esta plantilla, los pasos de script se quitan y no se ejecutan.

# azure-pipelines.yml
extends:
  template: template.yml
  parameters:
    usersteps:
    - task: MyTask@1
    - script: echo This step will be stripped out and not run!
    - bash: echo This step will be stripped out and not run!
    - powershell: echo "This step will be stripped out and not run!"
    - pwsh: echo "This step will be stripped out and not run!"
    - script: echo This step will be stripped out and not run!
    - task: CmdLine@2
      displayName: Test - Will be stripped out
      inputs:
        script: echo This step will be stripped out and not run!
    - task: MyOtherTask@2

Parámetros con seguridad de tipos

Antes de que se ejecute una canalización, las plantillas y sus parámetros se transforman en constantes. Los parámetros de plantilla pueden mejorar la seguridad de tipos para los parámetros de entrada.

En la plantilla de ejemplo siguiente, los parámetros restringen las opciones del grupo de canalizaciones disponibles proporcionando una enumeración de opciones específicas en lugar de permitir cadenas de forma libre.

# template.yml
parameters:
- name: userpool
  type: string
  default: Azure Pipelines
  values:
  - Azure Pipelines
  - private-pool-1
  - private-pool-2

pool: ${{ parameters.userpool }}
steps:
- script: # ... removed for clarity

Cuando la canalización extiende la plantilla, tiene que especificar una de las opciones de grupo disponibles.

# azure-pipelines.yml
extends:
  template: template.yml
  parameters:
    userpool: private-pool-1

Pasos de plantilla

Una plantilla puede incluir automáticamente pasos en una canalización. Estos pasos pueden realizar tareas como el examen de credenciales o las comprobaciones de código estático. La plantilla siguiente inserta los pasos antes y después de los pasos del usuario en cada trabajo.

parameters:
  jobs: []

jobs:
- ${{ each job in parameters.jobs }}: 
  - ${{ each pair in job }}:  
      ${{ if ne(pair.key, 'steps') }}:
        ${{ pair.key }}: ${{ pair.value }}
    steps:                            
    - task: CredScan@1 
    - ${{ job.steps }} 
    - task: PublishMyTelemetry@1 
      condition: always()

Aplicación de plantillas

Las plantillas son un mecanismo de seguridad valioso, pero su eficacia se basa en la aplicación. Los puntos de control clave para aplicar el uso de plantillas son recursos protegidos. Puede configurar aprobaciones y comprobaciones para el grupo de agentes u otros recursos protegidos, como repositorios. Para ver un ejemplo, consulte Adición de una comprobación de recursos de repositorio.

Plantillas necesarias

Para aplicar el uso de una plantilla específica, configure la comprobación de plantilla necesaria para un recurso. Esta comprobación solo se aplica cuando la canalización se extiende desde una plantilla.

Al ver el trabajo de canalización, puede supervisar el estado de la comprobación. Si la canalización no se extiende desde la plantilla necesaria, se produce un error en la comprobación. La ejecución se detiene y le notifica la comprobación con errores.

Captura de pantalla que muestra una comprobación de aprobación con errores.

Cuando se usa la plantilla necesaria, la comprobación pasa.

Captura de pantalla que muestra una comprobación de aprobación superada.

Se debe hacer referencia a la siguiente plantilla de params.yml en cualquier canalización que lo extienda.

# params.yml
parameters:
- name: yesNo 
  type: boolean
  default: false
- name: image
  displayName: Pool Image
  type: string
  default: ubuntu-latest
  values:
  - windows-latest
  - ubuntu-latest
  - macOS-latest

steps:
- script: echo ${{ parameters.yesNo }}
- script: echo ${{ parameters.image }}

La canalización de ejemplo siguiente amplía la plantilla de params.yml y la requiere para su aprobación. Para demostrar un error de canalización, comente la referencia a params.yml.

# azure-pipeline.yml

resources:
 containers:
     - container: my-container
       endpoint: my-service-connection
       image: mycontainerimages

extends:
    template: params.yml
    parameters:
        yesNo: true
        image: 'windows-latest'