Usare i modelli per la sicurezza

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

Questo articolo descrive come i modelli possono semplificare la sicurezza per Azure Pipelines. I modelli possono definire la struttura esterna della pipeline e prevenire l'infiltrazione di codice dannoso. I modelli possono anche includere automaticamente i passaggi per eseguire attività come l'analisi delle credenziali. Se più pipeline all'interno del team o dell'organizzazione condividono la stessa struttura, è consigliabile usare i modelli.

I controlli sulle risorse protette costituiscono il framework di sicurezza fondamentale per Azure Pipelines. Questi controlli si applicano indipendentemente dalla struttura della pipeline, dalle fasi e dai processi. È possibile usare i modelli per applicare questi controlli.

Include ed estende i modelli

Azure Pipelines include ed estende i modelli.

  • I modelli includono il codice del modello direttamente nel file esterno che vi fa riferimento, simile a #include in C++. La pipeline di esempio seguente inserisce il modello di include-npm-steps.yml nella steps sezione .

      steps:
      - template: templates/include-npm-steps.yml 
    
  • Estende i modelli definiscono la struttura esterna della pipeline e offrono punti specifici per le personalizzazioni mirate. Nel contesto di C++, extends i modelli sono simili all'ereditarietà.

Quando si usano extends modelli, è anche possibile usare includes sia nel modello che nella pipeline finale per eseguire parti di configurazione comuni. Per informazioni di riferimento complete, vedere informazioni di riferimento sull'utilizzo del modello.

Estende i modelli

Per le pipeline più sicure, iniziare con l'uso di modelli di estensione. Questi modelli definiscono la struttura esterna della pipeline e impediscono l'infiltrazione della pipeline da parte di codice dannoso.

Ad esempio, il file modello seguente è denominato template.yml.

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

La pipeline seguente estende il modello di 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

Suggerimento

Quando si configurano extends i modelli, è consigliabile ancorarli a un determinato ramo Git o a un tag, quindi se sono presenti modifiche di rilievo, le pipeline esistenti non sono interessate. Nell'esempio precedente viene usata questa funzionalità.

Funzionalità di sicurezza della pipeline YAML

La sintassi della pipeline YAML include diverse protezioni predefinite. Estende il modello può imporre l'uso. Per migliorare la sicurezza della pipeline, è possibile implementare una delle restrizioni seguenti.

Destinazioni passaggio

È possibile limitare determinati passaggi per l'esecuzione in un contenitore anziché nell'host. I passaggi nei contenitori non hanno accesso all'host dell'agente, impedendo a questi passaggi di modificare la configurazione dell'agente o di lasciare codice dannoso per un'esecuzione successiva.

Si consideri ad esempio la limitazione dell'accesso alla rete. Senza accesso alla rete aperta, i passaggi utente non possono recuperare pacchetti da origini non autorizzate o caricare codice e segreti in percorsi di rete esterni.

La pipeline di esempio seguente esegue i passaggi nell'host dell'agente prima di eseguire i passaggi all'interno di un contenitore.

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

Restrizioni dei comandi di registrazione agente

È possibile limitare i servizi forniti dall'agente di Azure Pipelines ai passaggi utente. I passaggi utente richiedono servizi usando i comandi di registrazione, che sono stringhe appositamente formattate stampate nell'output standard. In modalità con restrizioni, la maggior parte dei servizi dell'agente, ad esempio il caricamento di artefatti e l'associazione dei risultati dei test, non sono disponibili.

L'attività di esempio seguente ha esito negativo perché la relativa target proprietà indica all'agente di non consentire gli artefatti di pubblicazione.

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

In restricted modalità, il setvariable comando rimane consentito, quindi è necessario prestare attenzione perché le variabili della pipeline vengono esportate come variabili di ambiente nelle attività successive. Se le attività generano dati forniti dall'utente, ad esempio problemi aperti recuperati tramite un'API REST, potrebbero essere vulnerabili agli attacchi injection. Il contenuto utente malintenzionato potrebbe impostare variabili di ambiente che potrebbero essere sfruttate per compromettere l'host dell'agente.

Per attenuare questo rischio, gli autori di pipeline possono dichiarare in modo esplicito quali variabili sono impostabili usando il setvariable comando di registrazione. Quando si specifica un elenco vuoto, tutte le impostazioni delle variabili non sono consentite.

L'attività di esempio seguente ha esito negativo perché l'attività è consentita solo per impostare la expectedVar variabile o una variabile preceduta da ok.

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

Fase condizionale o esecuzione del processo

È possibile limitare le fasi e i processi per l'esecuzione solo in condizioni specifiche. Nell'esempio seguente, la condizione garantisce che il codice con restrizioni venga compilato solo per il ramo 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

Modifica della sintassi

I modelli di Azure Pipelines hanno la flessibilità necessaria per scorrere e modificare la sintassi YAML. Usando l'iterazione, è possibile applicare funzionalità di sicurezza YAML specifiche.

Un modello può anche riscrivere i passaggi utente, consentendo l'esecuzione solo delle attività approvate. Ad esempio, è possibile impedire l'esecuzione di script inline.

Il modello di esempio seguente impedisce l'esecuzione dei tipi di bashpassaggio , powershell, pwshe script . Per il blocco completo degli script ad hoc, è anche possibile bloccare BatchScript e 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 }}'

Nella pipeline seguente che estende questo modello, i passaggi dello script vengono rimossi e non vengono eseguiti.

# 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

Parametri indipendenti dai tipi

Prima dell'esecuzione di una pipeline, i modelli e i relativi parametri vengono trasformati in costanti. I parametri del modello possono migliorare la sicurezza dei tipi per i parametri di input.

Nel modello di esempio seguente i parametri limitano le opzioni del pool di pipeline disponibili fornendo un'enumerazione di scelte specifiche anziché consentire stringhe a mano libera.

# 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

Quando la pipeline estende il modello, deve specificare una delle opzioni del pool disponibili.

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

Passaggi del modello

Un modello può includere automaticamente i passaggi in una pipeline. Questi passaggi possono eseguire attività come l'analisi delle credenziali o i controlli del codice statico. Il modello seguente inserisce i passaggi prima e dopo i passaggi dell'utente in ogni processo.

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

Applicazione del modello

I modelli sono un meccanismo di sicurezza prezioso, ma la loro efficacia si basa sull'imposizione. I punti di controllo chiave per l'applicazione dell'utilizzo del modello sono risorse protette. È possibile configurare le approvazioni e verificare la presenza del pool di agenti o di altre risorse protette, ad esempio i repository. Per un esempio, vedere Aggiungere un controllo delle risorse del repository.

Modelli obbligatori

Per applicare l'uso di un modello specifico, configurare il controllo del modello richiesto per una risorsa. Questo controllo si applica solo quando la pipeline si estende da un modello.

Quando si visualizza il processo della pipeline, è possibile monitorare lo stato del controllo. Se la pipeline non si estende dal modello richiesto, il controllo ha esito negativo. L'esecuzione si arresta e invia una notifica del controllo non riuscito.

Screenshot che mostra un controllo di approvazione non riuscito.

Quando si usa il modello richiesto, il controllo viene superato.

Screenshot che mostra un controllo di approvazione superato.

È necessario fare riferimento al modello di params.yml seguente in qualsiasi pipeline che la estende.

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

La pipeline di esempio seguente estende il modello di params.yml e ne richiede l'approvazione. Per illustrare un errore della pipeline, impostare come commento il riferimento a 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'