Поделиться через


Шаблоны для безопасности

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

Шаблоны Azure Pipelines позволяют определять повторное использование содержимого, логики и параметров в конвейерах YAML. В этой статье описывается, как шаблоны помогают повысить безопасность конвейера, выполнив следующие действия.

  • Определение внешней структуры конвейера для предотвращения проникновения вредоносного кода.
  • Автоматическое включение шагов для выполнения таких задач, как сканирование учетных данных.
  • Помогая применять проверки защищенных ресурсов, которые образуют фундаментальную платформу безопасности для Azure Pipelines и применяются ко всем структурам конвейеров и компонентам.

Эта статья является частью серии, которая помогает реализовать меры безопасности для Azure Pipelines. Дополнительные сведения см. в статье "Защита Azure Pipelines".

Предпосылки

Категория Требования
Azure DevOps — Реализуйте рекомендации в "Обеспечьте безопасность Azure DevOps" и "Защита Azure Pipelines".
— Базовые знания о YAML и Azure Pipelines. Дополнительные сведения см. в статье "Создание первого конвейера".
Разрешения — Чтобы изменить разрешения конвейеров: член группы "Администраторы проектов".
Чтобы изменить разрешения организации, необходимо быть членом группы администраторов коллекции проектов.

Включает и расширяет шаблоны

Azure Pipelines предоставляет шаблоны, которые включают и расширяют.

  • Шаблон includes содержит код шаблона непосредственно в файле верхнего уровня, который ссылается на шаблон, аналогично #include в C++. В следующем примере конвейер вставляет шаблон include-npm-steps.yml в раздел steps.

      steps:
      - template: templates/include-npm-steps.yml 
    
  • Шаблон extends определяет внешнюю структуру конвейера и предлагает определенные точки для целевых настроек. В контексте C++ extends шаблоны похожи на наследование.

При использовании extends шаблонов можно также использовать includes для выполнения общих частей конфигурации как в шаблоне, так и в окончательном конвейере. Дополнительные сведения см. в разделе "Использование шаблонов YAML в конвейерах для повторного использования и безопасных процессов".

Расширение шаблонов

Для наиболее безопасных конвейеров начните с шаблонов extends . Эти шаблоны определяют внешнюю структуру конвейера и помогают предотвратить проникновение вредоносного кода.

В следующем примере показан файл шаблона с именем template.yml.

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

В следующем примере конвейер расширяет шаблон 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

Совет

При настройке extends шаблонов рекомендуется привязать их к определенной ветви Git или тегу, чтобы любые критические изменения не влияли на существующие конвейеры. В предыдущем примере эта функция используется.

Функции безопасности конвейера

Синтаксис конвейера YAML включает несколько встроенных защит. Extends шаблоны могут быть использованы для повышения безопасности пайплайна. Вы можете реализовать любое из следующих ограничений.

Целевые объекты шага

Вы можете ограничить указанные шаги для выполнения в контейнере, а не на узле. Шаги в контейнерах не могут получить доступ к узлу агента, поэтому они не могут изменить конфигурацию агента или оставлять вредоносный код на будущее выполнение.

Например, можно выполнить действия пользователя в контейнере, чтобы предотвратить доступ к сети, чтобы они не могли получать пакеты из несанкционированных источников или отправлять код и секреты во внешние расположения.

В следующем примере конвейер выполняет шаг на узле агента, который может изменить сеть узла, а затем шаг внутри контейнера, который ограничивает доступ к сети.

resources:
  containers:
  - container: builder
    image: mysecurebuildcontainer:latest
steps:
- script: echo This step runs on the agent host
- script: echo This step runs inside the builder container
  target: builder

Типобезопасные параметры

Перед запуском конвейера шаблоны и их параметры преобразуются в константы. Параметры шаблона могут повысить безопасность типов для входных параметров.

В следующем примере шаблона параметры ограничивают доступные параметры пула конвейеров, перечисляя определенные варианты вместо того, чтобы разрешить любую строку.

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

pool: ${{ parameters.userpool }}
steps:
- script: echo Hello world

Чтобы расширить шаблон, конвейер должен указать один из доступных вариантов пула.

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

Ограничения команд ведения журнала агента

Шаги пользователя запрашивают службы с помощью команд ведения журнала, которые специально отформатированы строки, напечатанные в стандартные выходные данные. Вы можете ограничить службы, предоставляемые командами ведения журнала для действий пользователя. В restricted режиме большинство служб агентов, таких как отправка артефактов и присоединение результатов теста, недоступны для команд ведения журнала.

В следующем примере свойство target инструктирует агента ограничить публикацию артефактов, поэтому задача публикации артефактов завершается сбоем.

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

Переменные в командах ведения журналирования

Команда setvariable остается допустимой в restricted режиме, поэтому задачи, которые выводят предоставленные пользователем данные, такие как открытые проблемы, полученные через REST API, могут быть уязвимы для атак внедрения. Содержимое, созданное злоумышленником, может установить переменные, которые экспортируются в последующие задачи как переменные среды, и может скомпрометировать хост-агента.

Чтобы устранить этот риск, можно явно объявить переменные, которые задаются с помощью setvariable команды ведения журнала. Если вы укажете пустой список в settableVariables, установка всех переменных будет запрещена.

Следующий пример ограничивает использование settableVariables и expectedVar, а также любой переменной с префиксом ok. Задача завершается ошибкой, так как она пытается задать другую переменную BadVar.

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

Условный этап или выполнение задания

Этапы и задания можно ограничить только в определенных условиях. Следующий пример гарантирует, что сборки ограниченного кода создаются только для main ветви.

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

Изменение синтаксиса

Шаблоны Azure Pipelines имеют гибкость для итерации и изменения синтаксиса YAML. С помощью итерации можно применить определенные функции безопасности YAML.

Шаблон также может переписать пользовательские шаги, позволяя выполнять только утвержденные задачи. Например, шаблон может предотвратить встроенное выполнение скрипта.

В следующем примере шаблона предотвращается выполнение типов шагов скрипта bash, powershell, pwsh и script. Для полной блокировки сценариев можно также заблокировать BatchScript и 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 }}'

В следующем примере конвейера, расширяющего предыдущий шаблон, шаги скрипта удаляются и не выполняются.

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

Шаги шаблона

Шаблон может автоматически включать шаги в конвейер, например для проверки учетных данных или статических проверок кода. Следующий шаблон вставляет шаги до и после действий пользователя в каждом задании.

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()

Принудительное применение шаблона

Эффективность шаблонов в качестве механизма безопасности зависит от принудительного применения. Основные контрольные точки для соблюдения использования шаблона - это защищённые ресурсы.

Вы можете настроить утверждения и проверки для вашего пула агентов или других защищенных ресурсов, таких как репозитории. Пример см. в разделе "Добавление проверки ресурса репозитория".

Обязательные шаблоны

Чтобы применить использование определенного шаблона, настройте необходимую проверку шаблона для подключения службы к ресурсу. Эта проверка применяется только в том случае, если конвейер расширяется из шаблона.

При просмотре задания конвейера можно отслеживать состояние проверки. Если конвейер не расширяется из требуемого шаблона, проверка завершается ошибкой.

Снимок экрана: сбой проверки утверждения.

При использовании обязательного шаблона проверка проходит.

Снимок экрана: пройденная проверка утверждения.

Например, в любом конвейере, расширяющем его, необходимо ссылаться на следующий шаблон params.yml.

# 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 }}

В следующем примере конвейер расширяет шаблон params.yml и требует его утверждения. Чтобы продемонстрировать сбой конвейера, закомментируйте ссылку extends на 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'