템플릿을 통한 보안

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

보호된 리소스에 대한 검사는 Azure Pipelines 에 대한 기본 보안 구성 요소입니다. 파이프라인의 구조(단계 및 작업)에 관계없이 검사가 작동합니다. 팀 또는 organization 여러 파이프라인의 구조가 동일한 경우 템플릿을 사용하여 보안을 더욱 간소화할 수 있습니다.

Azure Pipelines는 및 확장이라는 두 가지 종류의 템플릿 제공합니다. 포함된 템플릿은 C++에서처럼 #include 동작합니다. 템플릿의 코드를 외부 파일에 바로 붙여넣는 것처럼 표시됩니다. 이 파일은 참조합니다. 예를 들어 여기에 포함 템플릿(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 구문에는 몇 가지 보호 기능이 기본 제공되어 있으며 확장 템플릿은 일부 또는 전부의 사용을 강제할 수 있습니다.

단계 대상

호스트 대신 컨테이너에서 실행되도록 일부 단계를 제한합니다. 에이전트의 호스트에 액세스할 수 없으면 사용자 단계는 에이전트 구성을 수정하거나 나중에 실행하기 위해 악성 코드를 남길 수 없습니다. 먼저 호스트에서 코드를 실행하여 컨테이너를 보다 안전하게 만듭니다. instance 경우 네트워크에 대한 액세스를 제한하는 것이 좋습니다. 네트워크에 대한 열린 액세스 권한이 없으면 사용자 단계는 권한 없는 원본의 패키지에 액세스하거나 코드와 비밀을 네트워크 위치에 업로드할 수 없습니다.

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

extends 템플릿을 사용하여 특정 구문 필요

템플릿은 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

형식이 안전한 매개 변수

템플릿 및 해당 매개 변수는 파이프라인이 실행되기 전에 상수로 변환됩니다. 템플릿 매개 변수는 입력 매개 변수 에 대한 형식 보안을 제공합니다. instance 경우 자유형 문자열이 아닌 가능한 옵션의 열거형을 제공하여 파이프라인에서 사용할 수 있는 풀을 제한할 수 있습니다.

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

템플릿 적용

템플릿은 적용할 수 있는 경우에만 보안 메커니즘입니다. 템플릿 사용을 적용하는 제어 지점은 보호된 리소스입니다. 에이전트 풀 또는 리포지토리와 같은 기타 보호된 리소스에 대한 승인 및 검사를 구성할 수 있습니다. 예제는 리포지토리 리소스 검사 추가를 참조하세요.

다음 단계

다음으로 변수 및 매개 변수를 통해 입력을 안전하게 수행하는 방법을 알아봅니다.