Использование шаблонов для безопасности
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2020
В этой статье описывается, как шаблоны могут упростить безопасность для Azure Pipelines. Шаблоны могут определять внешнюю структуру конвейера и предотвращать проникновение вредоносного кода. Шаблоны также могут автоматически включать шаги для выполнения таких задач, как сканирование учетных данных. Если несколько конвейеров в команде или организации используют одну и ту же структуру, рекомендуется использовать шаблоны.
Проверка защищенных ресурсов формирует базовую платформу безопасности для Azure Pipelines. Эти проверки применяются независимо от структуры конвейера, этапов и заданий. Вы можете использовать шаблоны для применения этих проверок.
Включает и расширяет шаблоны
Azure Pipelines предоставляет шаблоны и расширяет шаблоны.
Включает шаблоны включают код шаблона непосредственно в внешний файл, который ссылается на него, как
#include
и в C++. В следующем примере конвейер вставляет шаблон include-npm-steps.yml вsteps
раздел.steps: - template: templates/include-npm-steps.yml
Расширяет шаблоны определяют внешнюю структуру конвейера и предлагают определенные точки для целевых настроек. В контексте C++
extends
шаблоны похожи на наследование.
При использовании extends
шаблонов можно также использовать includes
как в шаблоне, так и в последнем конвейере для выполнения общих частей конфигурации. Полный справочник см. в справочнике по использованию шаблона.
Расширение шаблонов
Для наиболее безопасных конвейеров начните с расширения шаблонов. Эти шаблоны определяют внешнюю структуру конвейера и препятствуют инфильтрации конвейера вредоносным кодом.
Например, следующий файл шаблона называется 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
Синтаксис конвейера YAML включает несколько встроенных защит. Расширение шаблона может применять их использование. Чтобы повысить безопасность конвейера, можно реализовать любое из следующих ограничений.
Целевые объекты шага
Вы можете ограничить выполнение определенных шагов в контейнере, а не на узле. Действия в контейнерах не имеют доступа к узлу агента, предотвращая изменение конфигурации агента или выход вредоносного кода для последующего выполнения.
Например, рекомендуется ограничить доступ к сети. Без открытого сетевого доступа действия пользователя не могут извлекать пакеты из несанкционированных источников или отправлять код и секреты во внешние сетевые расположения.
В следующем примере конвейер выполняет шаги на узле агента перед выполнением шагов внутри контейнера.
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
Ограничения команд ведения журнала агента
Вы можете ограничить службы, предоставляемые агентом Azure Pipelines, для выполнения действий пользователя. Шаги пользователя запрашивают службы с помощью команд ведения журнала, которые специально отформатированы строки, напечатанные в стандартные выходные данные. В ограниченном режиме большинство служб агента, таких как отправка артефактов и присоединение результатов теста, недоступны.
В следующем примере задача завершается сбоем, так как его target
свойство указывает агенту не разрешать публикацию артефактов.
- task: PublishBuildArtifacts@1
inputs:
artifactName: myartifacts
target:
commands: restricted
В restricted
режиме команда остается допустимой setvariable
, поэтому осторожность необходима, так как переменные конвейера экспортируются в виде переменных среды в последующие задачи. Если задачи выводят предоставленные пользователем данные, такие как открытые проблемы, полученные через REST API, они могут быть уязвимы для атак на внедрение. Содержимое вредоносного пользователя может задать переменные среды, которые могут быть использованы для компрометации узла агента.
Чтобы устранить этот риск, авторы конвейера могут явно объявить, какие переменные задаются с помощью setvariable
команды ведения журнала. При указании пустого списка все параметры переменной запрещены.
Следующий пример задачи завершается сбоем, так как задача разрешена только для задания expectedVar
переменной или префикса ok
переменной.
- task: PowerShell@2
target:
commands: restricted
settableVariables:
- expectedVar
- ok*
inputs:
targetType: 'inline'
script: |
Write-Host "##vso[task.setvariable variable=BadVar]myValue"
Условный этап или выполнение задания
Этапы и задания можно ограничить только в определенных условиях. В следующем примере условие гарантирует, что ограниченный код выполняет сборку только для основной ветви.
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 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
Типобезопасные параметры
Перед запуском конвейера шаблоны и их параметры преобразуются в константы. Параметры шаблона могут повысить безопасность типов для входных параметров.
В следующем примере шаблона параметры ограничивают доступные параметры пула конвейеров, предоставляя перечисление определенных вариантов, а не разрешать строки свободной формы.
# 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
Когда конвейер расширяет шаблон, он должен указать один из доступных вариантов пула.
# azure-pipelines.yml
extends:
template: template.yml
parameters:
userpool: private-pool-1
Шаги шаблона
Шаблон может автоматически включать шаги в конвейер. Эти действия могут выполнять такие задачи, как сканирование учетных данных или статические проверки кода. Следующий шаблон вставляет шаги до и после действий пользователя в каждом задании.
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 и требует его утверждения. Чтобы продемонстрировать сбой конвейера, закомментируйте ссылку на 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'