Utiliser des modèles pour la sécurité
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2020
Cet article décrit comment les modèles peuvent simplifier la sécurité pour Azure Pipelines. Les modèles peuvent définir la structure externe de votre pipeline et empêcher l’infiltration de code malveillante. Les modèles peuvent également inclure automatiquement des étapes pour effectuer des tâches telles que l’analyse des informations d’identification. Si plusieurs pipelines au sein de votre équipe ou organisation partagent la même structure, envisagez d’utiliser des modèles.
Les vérifications sur les ressources protégées forment l’infrastructure de sécurité fondamentale pour Azure Pipelines. Ces vérifications s’appliquent indépendamment de la structure, des étapes et des travaux du pipeline. Vous pouvez utiliser des modèles pour vous aider à appliquer ces vérifications.
Inclut et étend les modèles
Azure Pipelines fournit des modèles inclus et étendus .
Inclut les modèles incluent le code du modèle directement dans le fichier externe qui le référence, comme
#include
dans C++. L’exemple de pipeline suivant insère le modèle include-npm-steps.yml dans lasteps
section.steps: - template: templates/include-npm-steps.yml
Étend les modèles définissent la structure externe du pipeline et offrent des points spécifiques pour les personnalisations ciblées. Dans le contexte de C++,
extends
les modèles ressemblent à l’héritage.
Lorsque vous utilisez extends
des modèles, vous pouvez également utiliser includes
dans le modèle et le pipeline final pour effectuer des éléments de configuration courants. Pour obtenir une référence complète, consultez la référence d’utilisation du modèle.
Étend les modèles
Pour les pipelines les plus sécurisés, commencez par utiliser des modèles étendus. Ces modèles définissent la structure externe du pipeline et empêchent le code malveillant d’infiltrer le pipeline.
Par exemple, le fichier de modèle suivant est nommé template.yml.
parameters:
- name: usersteps
type: stepList
default: []
steps:
- ${{ each step in parameters.usersteps }}:
- ${{ step }}
Le pipeline suivant étend le modèle 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
Conseil
Lorsque vous configurez extends
des modèles, envisagez de les ancrer dans une branche ou une balise Git particulière. Par conséquent, s’il existe des modifications cassantes, les pipelines existants ne sont pas affectés. L’exemple précédent utilise cette fonctionnalité.
Fonctionnalités de sécurité du pipeline YAML
La syntaxe du pipeline YAML comprend plusieurs protections intégrées. Étend le modèle peut appliquer son utilisation. Pour améliorer la sécurité du pipeline, vous pouvez implémenter l’une des restrictions suivantes.
Cibles d’étape
Vous pouvez restreindre certaines étapes à exécuter dans un conteneur plutôt que sur l’hôte. Les étapes des conteneurs n’ont pas accès à l’hôte de l’agent, ce qui empêche ces étapes de modifier la configuration de l’agent ou de laisser du code malveillant pour une exécution ultérieure.
Par exemple, envisagez de limiter l’accès réseau. Sans accès réseau ouvert, les étapes utilisateur ne peuvent pas récupérer des packages à partir de sources non autorisées ou charger du code et des secrets vers des emplacements réseau externes.
L’exemple de pipeline suivant exécute les étapes sur l’hôte de l’agent avant d’exécuter des étapes à l’intérieur d’un conteneur.
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
Restrictions de la commande de journalisation de l’agent
Vous pouvez restreindre les services fournis par l’agent Azure Pipelines aux étapes utilisateur. Les étapes utilisateur demandent des services à l’aide de commandes de journalisation, qui sont des chaînes spécialement mises en forme imprimées en sortie standard. En mode restreint, la plupart des services de l’agent, tels que le chargement d’artefacts et l’attachement des résultats des tests, ne sont pas disponibles.
L’exemple de tâche suivant échoue, car sa target
propriété indique à l’agent de ne pas autoriser la publication d’artefacts.
- task: PublishBuildArtifacts@1
inputs:
artifactName: myartifacts
target:
commands: restricted
En restricted
mode, la setvariable
commande reste autorisée, de sorte que la prudence est nécessaire, car les variables de pipeline sont exportées en tant que variables d’environnement vers les tâches suivantes. Si les tâches génèrent des données fournies par l’utilisateur, telles que des problèmes ouverts récupérés via une API REST, elles peuvent être vulnérables aux attaques par injection. Le contenu utilisateur malveillant peut définir des variables d’environnement qui peuvent être exploitées pour compromettre l’hôte de l’agent.
Pour atténuer ce risque, les auteurs de pipelines peuvent déclarer explicitement les variables définies à l’aide de la setvariable
commande de journalisation. Lorsque vous spécifiez une liste vide, tous les paramètres de variable ne sont pas autorisés.
L’exemple de tâche suivant échoue, car la tâche est uniquement autorisée à définir la expectedVar
variable ou une variable préfixée avec ok
.
- task: PowerShell@2
target:
commands: restricted
settableVariables:
- expectedVar
- ok*
inputs:
targetType: 'inline'
script: |
Write-Host "##vso[task.setvariable variable=BadVar]myValue"
Étape conditionnelle ou exécution du travail
Vous pouvez restreindre les étapes et les travaux à exécuter uniquement dans des conditions spécifiques. Dans l’exemple suivant, la condition garantit que le code restreint est généré uniquement pour la branche principale.
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
Modification de la syntaxe
Les modèles Azure Pipelines ont la possibilité d’itérer et de modifier la syntaxe YAML. En utilisant l’itération, vous pouvez appliquer des fonctionnalités de sécurité YAML spécifiques.
Un modèle peut également réécrire les étapes utilisateur, ce qui autorise uniquement les tâches approuvées à s’exécuter. Par exemple, vous pouvez empêcher l’exécution du script inline.
L’exemple de modèle suivant empêche l’exécution des types bash
d’étapes, powershell
pwsh
et script
de l’exécution. Pour un verrouillage complet des scripts ad hoc, vous pouvez également bloquer BatchScript
et 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 }}'
Dans le pipeline suivant qui étend ce modèle, les étapes de script sont supprimées et non exécutées.
# 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
Paramètres de type sécurisé
Avant l’exécution d’un pipeline, les modèles et leurs paramètres sont transformés en constantes. Les paramètres de modèle peuvent améliorer la sécurité des types pour les paramètres d’entrée.
Dans l’exemple de modèle suivant, les paramètres limitent les options de pool de pipelines disponibles en fournissant une énumération de choix spécifiques au lieu d’autoriser les chaînes de forme 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
Lorsque le pipeline étend le modèle, il doit spécifier l’un des choix de pool disponibles.
# azure-pipelines.yml
extends:
template: template.yml
parameters:
userpool: private-pool-1
Étapes du modèle
Un modèle peut inclure automatiquement des étapes dans un pipeline. Ces étapes peuvent effectuer des tâches telles que l’analyse des informations d’identification ou les vérifications de code statique. Le modèle suivant insère des étapes avant et après les étapes de l’utilisateur dans chaque travail.
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()
Application des modèles
Les modèles sont un mécanisme de sécurité précieux, mais leur efficacité dépend de l’application. Les points de contrôle clés pour appliquer l’utilisation du modèle sont des ressources protégées. Vous pouvez configurer des approbations et des vérifications pour votre pool d’agents ou d’autres ressources protégées telles que des dépôts. Pour obtenir un exemple, consultez Ajouter une vérification de ressource de référentiel.
Modèles obligatoires
Pour appliquer l’utilisation d’un modèle spécifique, configurez la vérification de modèle requise pour une ressource. Cette vérification s’applique uniquement lorsque le pipeline s’étend à partir d’un modèle.
Lorsque vous affichez la tâche de pipeline, vous pouvez surveiller l’état de la vérification. Si le pipeline ne s’étend pas à partir du modèle requis, la vérification échoue. L’exécution s’arrête et vous avertit de l’échec de la vérification.
Lorsque vous utilisez le modèle requis, la vérification passe.
Le modèle params.yml suivant doit être référencé dans n’importe quel pipeline qui l’étend.
# 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 }}
L’exemple de pipeline suivant étend le modèle params.yml et nécessite son approbation. Pour illustrer une défaillance du pipeline, commentez la référence à 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'