Sicherheit durch Vorlagen

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

Überprüfungen geschützter Ressourcen sind der grundlegende Baustein der Sicherheit für Azure Pipelines. Überprüfungen funktionieren unabhängig von der Struktur - den Phasen und Aufträgen - Ihrer Pipeline. Wenn mehrere Pipelines in Ihrem Team oder Ihrer Organisation dieselbe Struktur aufweisen, können Sie die Sicherheit mithilfe von Vorlagen weiter vereinfachen.

Azure Pipelines bietet zwei Arten von Vorlagen: umfasst und erweitert. Enthaltene Vorlagen verhalten sich wie #include in C++: Es ist so, als ob Sie den Code der Vorlage direkt in die äußere Datei einfügen, die darauf verweist. Hier wird beispielsweise eine includes-Vorlage (include-npm-steps.yml) in stepseingefügt.

  steps:
  - template: templates/include-npm-steps.yml 

Um die C++-Metapher fortzusetzen, extends ähneln Vorlagen eher der Vererbung: Die Vorlage stellt die äußere Struktur der Pipeline und eine Reihe von Stellen bereit, an denen der Vorlagenconsumer gezielte Änderungen vornehmen kann.

Verwenden von erweiterten Vorlagen

Für die sichersten Pipelines wird empfohlen, mit extends Vorlagen zu beginnen. Durch die Bereitstellung der äußeren Struktur kann eine Vorlage verhindern, dass bösartiger Code in Ihre Pipeline gelangt. Sie können weiterhin sowohl in der Vorlage als auch in der endgültigen Pipeline verwenden includes, um allgemeine Konfigurationselemente zu berücksichtigen. Wenn Sie eine Erweiterungsvorlage verwenden möchten, sieht Ihre Pipeline möglicherweise wie im folgenden Beispiel aus.

# template.yml
parameters:
- name: usersteps
  type: stepList
  default: []
steps:
- ${{ each step in parameters.usersteps }}:
  - ${{ step }}
# 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

Wenn Sie Vorlagen einrichten extends , sollten Sie sie in einem bestimmten Git-Branch oder -Tag verankern. Auf diese Weise sind vorhandene Pipelines nicht betroffen, wenn Breaking Changes vorgenommen werden müssen. In den obigen Beispielen wird dieses Feature verwendet.

Über YAML erzwungene Sicherheitsfeatures

In die YAML-Syntax sind mehrere Schutzfunktionen integriert, und eine erweiterte Vorlage kann die Verwendung eines oder aller dieser Elemente erzwingen.

Schrittziele

Schränken Sie einige Schritte auf die Ausführung in einem Container anstelle des Hosts ein. Ohne Zugriff auf den Host des Agents können Benutzerschritte die Agentkonfiguration nicht ändern oder schädlichen Code für die spätere Ausführung belassen. Führen Sie zuerst Code auf dem Host aus, um den Container sicherer zu machen. Es wird beispielsweise empfohlen, den Zugriff auf das Netzwerk einzuschränken. Ohne offenen Zugriff auf das Netzwerk können Benutzerschritte nicht auf Pakete aus nicht autorisierten Quellen zugreifen oder Code und Geheimnisse an einen Netzwerkspeicherort hochladen.

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

Einschränkungen für Agent-Protokollierungsbefehle

Schränken Sie die Dienste ein, die der Azure Pipelines-Agent für Benutzerschritte bereitstellt. Schritte zum Anfordern von Diensten mithilfe von "Protokollierungsbefehlen" (speziell formatierte Zeichenfolgen, die in stdout gedruckt werden). Im eingeschränkten Modus sind die meisten Dienste des Agents wie das Hochladen von Artefakten und das Anfügen von Testergebnissen nicht verfügbar.

# this task will fail because its `target` property instructs the agent not to allow publishing artifacts
- task: PublishBuildArtifacts@1
  inputs:
    artifactName: myartifacts
  target:
    commands: restricted

Einer der Befehle, die im eingeschränkten Modus weiterhin zulässig sind, ist der setvariable Befehl. Da Pipelinevariablen als Umgebungsvariablen in nachfolgende Aufgaben exportiert werden, können Aufgaben, die vom Benutzer bereitgestellte Daten ausgeben (z. B. der Inhalt offener Probleme, die von einer REST-API abgerufen werden) anfällig für Injektionsangriffe sein. Solche Benutzerinhalte können Umgebungsvariablen festlegen, die wiederum zum Ausnutzen des Agenthosts verwendet werden können. Um dies zu verhindern, können Pipelineautoren über den setvariable Protokollierungsbefehl explizit deklarieren, welche Variablen festgelegt werden können. Das Angeben einer leeren Liste lässt das Festlegen aller Variablen nicht zu.

# this task will fail because the task is only allowed to set the 'expectedVar' variable, or a variable prefixed with "ok"
- task: PowerShell@2
  target:
    commands: restricted
    settableVariables:
    - expectedVar
    - ok*
  inputs:
    targetType: 'inline'
    script: |
      Write-Host "##vso[task.setvariable variable=BadVar]myValue"

Bedingtes Einfügen von Phasen oder Aufträgen

Schränken Sie Phasen und Aufträge auf die Ausführung unter bestimmten Bedingungen ein. Bedingungen können beispielsweise helfen, sicherzustellen, dass Sie nur bestimmte Branches erstellen.

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

Erfordern einer bestimmten Syntax mit erweiterten Vorlagen

Vorlagen können eine beliebige YAML-Syntax durchlaufen und ändern/nicht zulassen. Iteration kann die Verwendung einer bestimmten YAML-Syntax erzwingen, einschließlich der oben genannten Features.

Eine Vorlage kann Benutzerschritte umschreiben und nur bestimmte genehmigte Aufgaben ausführen lassen. Sie können beispielsweise die Ausführung von Inlineskripts verhindern.

Warnung

Im folgenden Beispiel werden die Schritte vom Typ "bash", "powershell", "pwsh" und "script" an der Ausführung gehindert. Für eine vollständige Sperrung von Ad-hoc-Skripts müssen Sie auch "BatchScript" und "ShellScript" blockieren.

# 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 lines below will 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

Typsichere Parameter

Vorlagen und ihre Parameter werden vor der Ausführung der Pipeline in Konstanten umgewandelt. Vorlagenparameter bieten Typsicherheit für Eingabeparameter. Sie kann beispielsweise einschränken, welche Pools in einer Pipeline verwendet werden können, indem eine Enumeration möglicher Optionen anstelle einer Freihandformzeichenfolge angeboten wird.

# 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

Festlegen erforderlicher Vorlagen

Damit eine bestimmte Vorlage verwendet wird, können Sie die erforderliche Vorlagenüberprüfung für eine Ressource oder Umgebung festlegen. Die erforderliche Vorlagenprüfung kann verwendet werden, wenn sie von einer Vorlage aus erweitert wird.

Sie können den Status einer Überprüfung überprüfen, wenn Sie einen Pipelineauftrag anzeigen. Wenn eine Pipeline nicht über die Vorlage erforderlich erweitert wird, schlägt die Überprüfung fehl, und die Ausführung wird beendet. Sie werden sehen, dass bei der Überprüfung ein Fehler aufgetreten ist.

Fehler bei der Genehmigungsprüfung

Wenn die erforderliche Vorlage verwendet wird, sehen Sie, dass Ihre Überprüfung erfolgreich war.

Genehmigungsprüfung besteht

Hier ist die Vorlage params.yml mit einer Genehmigung für die Ressource erforderlich. Um einen Fehler bei der Pipeline auszulösen, kommentieren Sie den Verweis auf params.ymlaus.

# 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 }}
# azure-pipeline.yml

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

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

Zusätzliche Schritte

Eine Vorlage kann Schritte hinzufügen, ohne dass der Pipelineautor sie einbeziehen muss. Diese Schritte können verwendet werden, um die Überprüfung von Anmeldeinformationen oder statische Codeüberprüfungen auszuführen.

# template to insert a step before and after user steps in every job
parameters:
  jobs: []

jobs:
- ${{ each job in parameters.jobs }}: # Each job
  - ${{ each pair in job }}:  # Insert all properties other than "steps"
      ${{ if ne(pair.key, 'steps') }}:
        ${{ pair.key }}: ${{ pair.value }}
    steps:                            # Wrap the steps
    - task: CredScan@1                # Pre steps
    - ${{ job.steps }}                # Users steps
    - task: PublishMyTelemetry@1      # Post steps
      condition: always()

Erzwingung von Vorlagen

Eine Vorlage ist nur dann ein Sicherheitsmechanismus, wenn Sie sie erzwingen können. Der Kontrollpunkt zum Erzwingen der Verwendung von Vorlagen ist eine geschützte Ressource. Sie können Genehmigungen und Überprüfungen für Ihren Agent-Pool oder andere geschützte Ressourcen wie Repositorys konfigurieren. Ein Beispiel finden Sie unter Hinzufügen einer Repositoryressourcenüberprüfung.

Nächste Schritte

Als Nächstes erfahren Sie, wie Sie Eingaben sicher über Variablen und Parameter verwenden.