Udostępnij za pośrednictwem


Używanie szablonów do zabezpieczeń

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

W tym artykule opisano, jak szablony mogą usprawnić zabezpieczenia usługi Azure Pipelines. Szablony mogą definiować zewnętrzną strukturę potoku i zapobiegać infiltracji złośliwego kodu. Szablony mogą również automatycznie dołączać kroki do wykonywania zadań, takich jak skanowanie poświadczeń. Jeśli wiele potoków w zespole lub organizacji współużytkuje tę samą strukturę, rozważ użycie szablonów.

Sprawdzanie zasobów chronionych stanowi podstawową strukturę zabezpieczeń dla usługi Azure Pipelines. Te testy mają zastosowanie niezależnie od struktury potoku, etapów i zadań. Za pomocą szablonów można wymusić te kontrole.

Dołącza i rozszerza szablony

Usługa Azure Pipelines udostępnia szablony i rozszerza je .

  • Zawiera szablony zawierają kod szablonu bezpośrednio w pliku zewnętrznym, który się do niego odwołuje, podobnie jak #include w języku C++. Poniższy przykładowy potok wstawia szablon include-npm-steps.yml do steps sekcji.

      steps:
      - template: templates/include-npm-steps.yml 
    
  • Rozszerza szablony definiują zewnętrzną strukturę potoku i oferują określone punkty dla dostosowań docelowych. W kontekście języka C++ extends szablony przypominają dziedziczenie.

Gdy używasz extends szablonów, możesz również użyć includes go zarówno w szablonie, jak i w końcowym potoku, aby wykonać typowe elementy konfiguracji. Aby uzyskać pełną dokumentację, zobacz dokumentację użycia szablonu.

Rozszerza szablony

W przypadku najbardziej bezpiecznych potoków zacznij od używania szablonów rozszerzeń. Te szablony definiują zewnętrzną strukturę potoku i uniemożliwiają złośliwemu kodowi infiltrowanie potoku.

Na przykład następujący plik szablonu ma nazwę template.yml.

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

Poniższy potok rozszerza szablon 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

Napiwek

Podczas konfigurowania extends szablonów należy rozważyć zakotwiczenie ich w określonej gałęzi lub tagu Usługi Git, więc jeśli wystąpią zmiany powodujące niezgodność, istniejące potoki nie będą miały wpływu. W poprzednim przykładzie użyto tej funkcji.

Funkcje zabezpieczeń potoku YAML

Składnia potoku YAML zawiera kilka wbudowanych zabezpieczeń. Rozszerzenie szablonu może wymuszać ich użycie. Aby zwiększyć bezpieczeństwo potoku, można zaimplementować dowolne z poniższych ograniczeń.

Cele kroków

Niektóre kroki można ograniczyć do uruchamiania w kontenerze, a nie na hoście. Kroki w kontenerach nie mają dostępu do hosta agenta, uniemożliwiając tym krokom modyfikowanie konfiguracji agenta lub pozostawienie złośliwego kodu do późniejszego wykonania.

Rozważ na przykład ograniczenie dostępu do sieci. Bez otwartego dostępu do sieci kroki użytkownika nie mogą pobierać pakietów z nieautoryzowanych źródeł ani przekazywać kodu i wpisów tajnych do zewnętrznych lokalizacji sieciowych.

Poniższy przykładowy potok uruchamia kroki na hoście agenta przed uruchomieniem kroków wewnątrz kontenera.

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

Ograniczenia poleceń rejestrowania agenta

Możesz ograniczyć usługi, które agent usługi Azure Pipelines udostępnia użytkownikowi. Kroki użytkownika żądają usług przy użyciu poleceń rejestrowania, które są specjalnie sformatowanymi ciągami drukowanymi w standardowych danych wyjściowych. W trybie ograniczonym większość usług agenta, takich jak przekazywanie artefaktów i dołączanie wyników testu, jest niedostępna.

Następujące przykładowe zadanie kończy się niepowodzeniem, ponieważ jego target właściwość instruuje agenta, aby nie zezwalał na publikowanie artefaktów.

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

W restricted trybie setvariable polecenie pozostaje dopuszczalne, dlatego należy zachować ostrożność, ponieważ zmienne potoku są eksportowane jako zmienne środowiskowe do kolejnych zadań. Jeśli zadania wyjściowe danych dostarczanych przez użytkownika, takich jak otwarte problemy pobierane za pośrednictwem interfejsu API REST, mogą być narażone na ataki iniekcyjne. Złośliwa zawartość użytkownika może ustawić zmienne środowiskowe, które mogą zostać wykorzystane w celu naruszenia zabezpieczeń hosta agenta.

Aby ograniczyć to ryzyko, autorzy potoków mogą jawnie zadeklarować, które zmienne można ustawić przy użyciu polecenia rejestrowania setvariable . Po określeniu pustej listy wszystkie ustawienia zmiennych są niedozwolone.

Następujące przykładowe zadanie kończy się niepowodzeniem, ponieważ zadanie może ustawić expectedVar zmienną lub zmienną poprzedzoną prefiksem ok.

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

Etap warunkowy lub wykonywanie zadania

Można ograniczyć etapy i zadania do uruchamiania tylko w określonych warunkach. W poniższym przykładzie warunek gwarantuje, że ograniczony kod kompiluje tylko dla gałęzi głównej.

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

Modyfikowanie składni

Szablony usługi Azure Pipelines mają elastyczność iteracji i modyfikowania składni YAML. Za pomocą iteracji można wymusić określone funkcje zabezpieczeń YAML.

Szablon może również przepisać kroki użytkownika, zezwalając na uruchamianie tylko zatwierdzonych zadań. Można na przykład uniemożliwić wykonywanie skryptów wbudowanych.

Poniższy przykładowy szablon uniemożliwia uruchamianie typów kroków bash, powershell, pwshi script . Aby uzyskać pełną blokadę skryptów ad hoc, można również zablokować BatchScript i 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 }}'

W poniższym potoku, który rozszerza ten szablon, kroki skryptu są usuwane i nie są uruchamiane.

# 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

Parametry bezpieczne dla typu

Przed uruchomieniem potoku szablony i ich parametry są przekształcane w stałe. Parametry szablonu mogą zwiększyć bezpieczeństwo typów dla parametrów wejściowych.

W poniższym przykładowym szablonie parametry ograniczają dostępne opcje puli potoków, udostępniając wyliczenie określonych opcji zamiast zezwalania na ciągi wolnych kształtów.

# 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

Po rozszerzeniu szablonu potok musi określić jedną z dostępnych opcji puli.

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

Kroki szablonu

Szablon może automatycznie uwzględniać kroki w potoku. Te kroki mogą wykonywać zadania, takie jak skanowanie poświadczeń lub sprawdzanie kodu statycznego. Poniższy szablon wstawia kroki przed i po wykonaniu kroków użytkownika w każdym zadaniu.

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

Wymuszanie szablonu

Szablony są cennym mechanizmem zabezpieczeń, ale ich skuteczność opiera się na wymuszaniu. Kluczowymi punktami kontrolnymi wymuszania użycia szablonu są chronione zasoby. Możesz skonfigurować zatwierdzenia i sprawdzanie puli agentów lub innych chronionych zasobów, takich jak repozytoria. Aby zapoznać się z przykładem, zobacz Dodawanie sprawdzania zasobów repozytorium.

Wymagane szablony

Aby wymusić użycie określonego szablonu, skonfiguruj wymagany szablon sprawdzania zasobu. Ta kontrola ma zastosowanie tylko wtedy, gdy potok rozszerza się z szablonu.

Podczas wyświetlania zadania potoku można monitorować stan sprawdzania. Jeśli potok nie rozszerza się z wymaganego szablonu, sprawdzanie zakończy się niepowodzeniem. Przebieg zatrzymuje się i powiadamia o nieudanym sprawdzeniu.

Zrzut ekranu przedstawiający sprawdzanie zatwierdzenia, które zakończyło się niepowodzeniem.

Jeśli używasz wymaganego szablonu, sprawdzanie jest sprawdzane.

Zrzut ekranu przedstawiający sprawdzanie przekazanego zatwierdzenia.

Poniższy szablon params.yml należy odwołać się do dowolnego potoku, który go rozszerza.

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

Poniższy przykładowy potok rozszerza szablon params.yml i wymaga zatwierdzenia. Aby zademonstrować błąd potoku, oznacz jako komentarz odwołanie do 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'