Partilhar via


Usar modelos para segurança

Serviços de DevOps do Azure | Azure DevOps Server 2022 | Azure DevOps Server 2020

Este artigo descreve como os modelos podem simplificar a segurança para o Azure Pipelines. Os modelos podem definir a estrutura externa do seu pipeline e ajudar a prevenir a infiltração de códigos maliciosos. Os modelos também podem incluir automaticamente etapas para executar tarefas como a verificação de credenciais. Se vários pipelines dentro de sua equipe ou organização compartilharem a mesma estrutura, considere o uso de modelos.

As verificações de recursos protegidos formam a estrutura de segurança fundamental para o Azure Pipelines. Essas verificações se aplicam independentemente da estrutura do pipeline, estágios e trabalhos. Você pode usar modelos para ajudar a impor essas verificações.

Inclui e estende modelos

O Azure Pipelines fornece, inclui e estende modelos.

  • Os modelos incluem o código do modelo diretamente no arquivo externo que faz referência a ele, semelhante ao #include C++. O pipeline de exemplo a seguir insere o modelo include-npm-steps.yml na steps seção.

      steps:
      - template: templates/include-npm-steps.yml 
    
  • Os modelos estendidos definem a estrutura externa do pipeline e oferecem pontos específicos para personalizações direcionadas. No contexto do C++, extends os modelos se assemelham à herança.

Ao usar extends modelos, você também pode usar includes no modelo e no pipeline final para fazer partes de configuração comuns. Para obter uma referência completa, consulte a Referência de uso do modelo.

Estende modelos

Para os pipelines mais seguros, comece usando modelos extendidos. Esses modelos definem a estrutura externa do pipeline e impedem que códigos mal-intencionados se infiltrem no pipeline.

Por exemplo, o seguinte arquivo de modelo é chamado template.yml.

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

O pipeline a seguir estende o modelo 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

Gorjeta

Ao configurar extends modelos, considere ancorá-los a uma ramificação ou tag específica do Git para que, se houver alterações de rutura, os pipelines existentes não sejam afetados. O exemplo anterior usa esse recurso.

Recursos de segurança do pipeline YAML

A sintaxe do pipeline YAML inclui várias proteções internas. O modelo estendido pode impor seu uso. Para melhorar a segurança do pipeline, você pode implementar qualquer uma das restrições a seguir.

Metas graduais

Você pode restringir determinadas etapas para serem executadas em um contêiner em vez de no host. As etapas em contêineres não têm acesso ao host do agente, impedindo que essas etapas modifiquem a configuração do agente ou deixem código mal-intencionado para execução posterior.

Por exemplo, considere limitar o acesso à rede. Sem acesso aberto à rede, as etapas do usuário não podem recuperar pacotes de fontes não autorizadas ou carregar código e segredos para locais de rede externos.

O pipeline de exemplo a seguir executa etapas no host do agente antes de executar etapas dentro de um contêiner.

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

Restrições de comando de log do agente

Você pode restringir os serviços que o agente do Azure Pipelines fornece às etapas do usuário. As etapas do usuário solicitam serviços usando comandos de log, que são cadeias de caracteres especialmente formatadas impressas na saída padrão. No modo restrito, a maioria dos serviços do agente, como carregar artefatos e anexar resultados de testes, não está disponível.

A tarefa de exemplo a seguir falha porque sua target propriedade instrui o agente a não permitir artefatos de publicação.

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

No restricted modo, o setvariable comando permanece permitido, portanto, é necessário cuidado porque as variáveis de pipeline são exportadas como variáveis de ambiente para tarefas subsequentes. Se as tarefas produzirem dados fornecidos pelo usuário, como problemas abertos recuperados por meio de uma API REST, elas poderão estar vulneráveis a ataques de injeção. O conteúdo de usuário mal-intencionado pode definir variáveis de ambiente que podem ser exploradas para comprometer o host do agente.

Para reduzir esse risco, os autores do pipeline podem declarar explicitamente quais variáveis são configuráveis usando o setvariable comando log. Quando você especifica uma lista vazia, todas as configurações variáveis não são permitidas.

A tarefa de exemplo a seguir falha porque a tarefa só tem permissão para definir a variável ou uma variável prefixada expectedVar com ok.

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

Estágio condicional ou execução do trabalho

Você pode restringir estágios e trabalhos para serem executados somente sob condições específicas. No exemplo a seguir, a condição garante que o código restrito seja compilado somente para a ramificação principal.

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ção da sintaxe

Os modelos do Azure Pipelines têm a flexibilidade de iterar e modificar a sintaxe YAML. Usando a iteração, você pode impor recursos de segurança YAML específicos.

Um modelo também pode reescrever as etapas do usuário, permitindo que apenas tarefas aprovadas sejam executadas. Por exemplo, você pode impedir a execução de scripts embutidos.

O modelo de exemplo a seguir impede que os tipos bashde etapa , , powershellpwshe script sejam executados. Para bloqueio completo de scripts ad-hoc, você também pode bloquear 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 }}'

No pipeline a seguir que estende esse modelo, as etapas de script são removidas e não executadas.

# 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

Parâmetros seguros para tipos

Antes de um pipeline ser executado, os modelos e seus parâmetros são transformados em constantes. Os parâmetros do modelo podem aumentar a segurança do tipo para parâmetros de entrada.

No modelo de exemplo a seguir, os parâmetros restringem as opções de pool de pipeline disponíveis fornecendo uma enumeração de opções específicas em vez de permitir cadeias de caracteres de forma livre.

# 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 o pipeline estende o modelo, ele precisa especificar uma das opções de pool disponíveis.

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

Etapas do modelo

Um modelo pode incluir automaticamente etapas em um pipeline. Essas etapas podem executar tarefas como verificação de credenciais ou verificações de código estático. O modelo a seguir insere etapas antes e depois das etapas do usuário em cada trabalho.

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

Aplicação do modelo

Os modelos são um mecanismo de segurança valioso, mas a sua eficácia depende da aplicação. Os principais pontos de controle para impor o uso do modelo são recursos protegidos. Você pode configurar aprovações e verificações para seu pool de agentes ou outros recursos protegidos, como repositórios. Para obter um exemplo, consulte Adicionar uma verificação de recursos do repositório.

Modelos necessários

Para impor o uso de um modelo específico, configure a verificação de modelo necessária para um recurso. Essa verificação se aplica somente quando o pipeline se estende a partir de um modelo.

Ao visualizar o trabalho de pipeline, você pode monitorar o status da verificação. Se o pipeline não se estender a partir do modelo necessário, a verificação falhará. A execução para e notifica-o da verificação falhada.

Captura de ecrã a mostrar uma verificação de aprovação falhada.

Quando você usa o modelo necessário, a verificação é aprovada.

Captura de tela mostrando uma verificação de aprovação aprovada.

O modelo de params.yml a seguir deve ser referenciado em qualquer pipeline que o estenda.

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

O pipeline de exemplo a seguir estende o modelo de params.yml e o requer para aprovação. Para demonstrar uma falha de pipeline, comente a referência 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'