透過範本的安全性

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

檢查受保護的資源 是 Azure Pipelines 安全性的基本建置組塊。 不論管線的階段和作業結構為何,檢查工作。 如果小組或組織中的數個管線具有相同的結構,您可以進一步簡化使用 範本的安全性。

Azure Pipelines 提供兩種範本: 包括擴充。 包含的範本在 C++ 中的行為就像 #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 }}
# 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 代理程式將提供給使用者步驟的服務。 步驟會使用「記錄命令」要求服務 (列印至 stdout) 的特殊格式字串。 在受限制模式中,大部分的代理程式服務,例如上傳成品和附加測試結果都無法使用。

# 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

在受限制模式中仍允許的其中一個命令是 setvariable 命令。 由於管線變數會匯出為環境變數至後續工作,因此輸出使用者提供資料的工作 (例如,從 REST) API 擷取的開啟問題內容可能會容易受到插入式攻擊。 這類使用者內容可以設定環境變數,進而用來惡意探索代理程式主機。 若要不允許這種情況,管線作者可以透過記錄命令明確宣告哪些變數可 setvariable 設定。 指定空白清單不允許設定所有變數。

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

階段或作業的條件式插入

限制階段和作業在特定條件下執行。 例如,條件有助於確保您只建置特定分支。

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

需要具有擴充範本的特定語法

範本可以逐一查看並改變/不允許任何 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 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

型別安全參數

管線執行之前,範本及其參數會轉換成常數。 範本參數 提供輸入參數的型別安全性。 例如,它可以藉由提供可能選項的列舉,而不是手繪多邊形字串,來限制管線中可以使用的集區。

# 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

設定必要的範本

若要要求使用特定範本,您可以設定資源或環境 的必要範本檢查 。 從範本擴充時,可以使用必要的範本檢查。

您可以在檢視管線作業時檢查檢查的狀態。 當管線未從需要範本擴充時,檢查將會失敗,且執行將會停止。 您會看到您的檢查失敗。

核准檢查失敗

使用必要的範本時,您會看到已通過檢查。

核准檢查通過

在這裡,需要範本 params.yml ,並核准資源。 若要觸發管線失敗,請將 的參考批註化。 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 }}
# azure-pipeline.yml

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

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

其他步驟

範本可以新增步驟,而不需要管線作者包含這些步驟。 這些步驟可用來執行認證掃描或靜態程式碼檢查。

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

範本強制執行

如果您可以強制執行範本,則範本只是安全性機制。 強制使用範本的控制點是 受保護的資源。 您可以在代理程式組件區或其他受保護的資源上設定核准和檢查,例如存放庫。 如需範例,請參閱 新增存放庫資源檢查

下一步

接下來,瞭解如何透過 變數和參數安全地取得輸入。