정책 평가하기

정책 평가하기 (Evaluate policies)

docker scout policy는 CLI를 사용해 구성 가능한 정책 집합에 대해 이미지를 평가하게 해 줘요. 내장 기본값을 사용하거나, 요구사항에 맞게 임계값을 조정하거나, Rego로 사용자 지정 정책을 작성할 수 있어요.

동작 방식 (How it works)

docker scout policy를 실행하면 CLI가 이미지를 SBOM으로 인덱싱하고 CVE·VEX 데이터로 보강한 다음 구성된 각 정책을 프로세스 내에서 평가해요. Scout 서비스로 데이터가 전송되지 않고, 대부분의 사용 사례에서 조직이 필요하지 않아요.

정책은 세 가지 소스에서 오며, 결합할 수 있어요.

  • 내장 기본값: CLI에 내장된 큐레이트된 집합으로, 다른 소스를 주지 않았을 때 사용돼요.
  • OCI 정책 번들: OCI 아티팩트로 패키징된 Rego로, --policy-bundle로 레지스트리에서 pull돼요.
  • 로컬 .rego 파일: --policy-file이나 --policy-dir로 사용자 지정 정책을 작성·반복할 때 사용해요.

CI에서 사용하기

워크플로의 일부로 정책을 평가하려면 Docker Scout GitHub Action을 사용하세요.

- name: Evaluate policies
  uses: docker/scout-action@v1
  with:
    command: policy
    image: ${{ env.IMAGE_NAME }}
    organization: <ORG>

다른 CI 플랫폼에서는 러너에 Docker Scout CLI 플러그인을 설치하고 docker scout policy <image> --exit-code를 실행하세요.

환경과 비교해 정책 준수로 빌드를 게이트하려면 정책 구성과 함께 compare 명령을 사용하세요.

- uses: docker/scout-action@v1
  with:
    command: compare
    image: ${{ env.IMAGE_NAME }}
    to-env: production
    exit-on: policy
    policy-config: policies.json
    organization: <ORG>

policy-config 파일 형식은 내장 정책 구성을 참고하세요.

예시 (Examples)

이미지를 내장 정책 집합에 대해 평가하세요.

$ docker scout policy myorg/app:latest

어떤 정책이라도 충족되지 않으면 파이프라인을 실패시키려면 --exit-code를 사용하세요.

$ docker scout policy myorg/app:latest --exit-code

실행할 정책과 임계값을 사용자 지정하려면 policy-config 파일을 전달하세요.

$ docker scout policy myorg/app:latest --policy-config policies.json

정책 결과는 docker scout quickviewdocker scout compare에서도 표시되며, 이들도 같은 --policy-file, --policy-dir, --policy-bundle, --policy-config 플래그를 받아요.

유용한 다른 플래그:

# 멀티 플랫폼 이미지의 특정 플랫폼 평가
$ docker scout policy myorg/app:latest --platform linux/arm64

# 특정 정책의 결과만 표시
$ docker scout policy myorg/app:latest --only-policy "No copyleft licenses"

# 보고서를 파일로 저장
$ docker scout policy myorg/app:latest --output report.txt

건강 점수 (Health score)

docker scout policy, docker scout quickview, docker scout compare는 정책 결과와 함께 건강 점수도 보고해요. 숫자 백분율과 A-F 문자 등급으로, 전적으로 로컬 정책 평가에서 계산돼요. 이를 계산하기 위해 Scout 서비스로 데이터가 전송되지 않아요.

$ docker scout policy myorg/app:latest
...
Health score  B (83%)

docker scout compare는 두 이미지의 점수를 보여 줘요.

Health score  Analyzed B (83%)  Comparison C (65%)

점수 계산 방식 (How the score is calculated)

점수는 가중 통과 비율이에요.

  • 각 정책은 custom.weight 메타데이터 주석( 메타데이터 주석 참고)이나 policy-config 파일의 weight 재정의에서 가져온 가중치를 총합에 기여해요. 선언된 가중치가 없는 정책은 기본값 10이에요.
  • 통과(위반 0 보고)하는 정책은 전체 가중치를 채점 점수에 기여해요.
  • 실패하는 정책도 가중치를 총합에 세지만 채점 점수에는 아무것도 기여하지 않아, 점수를 낮춰요.
  • 평가할 데이터가 없는 정책(unknown)도 채점 점수에는 기여하지 않고 총합에만 세요.
  • 가중치가 0인 정책은 점수에서 완전히 제외돼요.

백분율은 scored / total * 100이고, 엄격한 초과 임계값으로 문자 등급에 매핑돼요.

점수 (Score) 등급 (Grade)
> 90% A
> 70% B
> 50% C
> 30% D
> 10% E
<= 10% F

임계값은 하한에서 배타적이므로 정확히 경계값이면 등급이 내려가요. 정확히 90%면 A가 아니라 B이고, 정확히 70%면 C이며, 이런 식이에요.

모든 정책이 점수에서 제외되면(예: 모든 정책이 weight: 0으로 구성), 건강 점수가 전혀 표시되지 않아요.

정책의 점수 기여를 바꾸려면 정책 Rego 메타데이터에 custom.weight를 설정하거나 policy-config 파일에서 정책별로 재정의하세요.

{
  "policies": [
    {
      "name": "copyleft-license",
      "weight": 0
    }
  ]
}

내장 정책 (Built-in policies)

다음 정책이 기본적으로 사용 가능해요.

정책 (Policy) 검사 내용 (What it checks)
No fixable critical or high vulnerabilities 수정이 가능한 critical/high CVE
No high-profile vulnerabilities 잘 알려진 CVE 큐레이트된 목록 (Log4Shell, XZ backdoor 등)
No copyleft licenses AGPL, GPL, LGPL, MPL 및 유사 라이선스 아래의 패키지
No outdated base images 베이스 이미지가 태그의 최신 다이제스트보다 뒤처짐
Supply chain attestations Provenance와 SBOM 인증이 첨부됨
Default non-root user 이미지가 비-루트 사용자로 실행되도록 구성됨
No unapproved base images 베이스 이미지가 구성 가능한 허용 목록과 일치

내장 정책 구성 (Configure built-in policies)

JSON policy-config 파일은 어떤 정책이 실행되고 어떤 임계값을 갖는지 제어해요. --policy-config로 전달하세요.

{
  "policies": [
    {
      "name": "fixable-vulnerabilities",
      "config": {
        "severities": ["CRITICAL"],
        "grace_period_days": 14
      }
    },
    {
      "name": "no-stale-base-images",
      "enabled": false
    }
  ]
}
  • policies[].name: 정책의 안정적인 ID (아래 표 참고).
  • policies[].enabled: 정책을 건너뛰려면 false로 설정. 나열되지 않은 정책은 기본적으로 활성화돼요.
  • policies[].weight: 정책의 custom.weight 메타데이터 주석을 재정의하며, 건강 점수에 대한 기여도를 결정해요. 가중치 0은 정책을 점수에서 제외해요. 생략하면 정책 자체의 주석이 사용되고 없으면 10이 돼요.
  • policies[].config: data.config로 정책에 전달되는 객체.

구성 참조 (Configuration reference)

다음 표는 각 내장 정책의 구성 가능한 키를 나열해요.

정책 (안정 ID) config 키 기본값 (Default) 설명 (Description)
fixable-vulnerabilities severities ["CRITICAL","HIGH"] 위반으로 치는 심각도 수준
fixable-vulnerabilities fixable_only true true면 알려진 수정이 있는 취약점만 셈
fixable-vulnerabilities package_types [] 고려할 PURL 패키지 유형 허용 목록; 빈 값은 모두
fixable-vulnerabilities grace_period_days 0 새로 공개된 CVE가 면제되는 일수
high-profile-vulnerabilities cves 기본 고위험 CVE 고위험으로 간주되는 CVE ID
high-profile-vulnerabilities ignored_cves [] 실패를 일으키지 않도록 제외된 CVE ID
high-profile-vulnerabilities include_cisa_kev true CISA KEV 카탈로그의 취약점도 플래그
copyleft-license licenses AGPL/GPL/LGPL/MPL/… copyleft로 처리되는 SPDX 라이선스 ID
copyleft-license ignored_packages [] 검사에서 면제되는 패키지 URL
approved-base-images allowed_base_images ["*"] 허용된 베이스 이미지 참조의 glob 패턴
approved-base-images allowed_distros_only true 활성화하면 베이스 이미지가 허용된 OS 배포판을 사용해야 함
approved-base-images allowed_distros 큐레이트된 목록 허용으로 간주되는 OS 배포판
supply-chain-attestations required_attestations provenance·SBOM predicate 유형 반드시 존재해야 하는 인증 predicate 유형

기본 고위험 CVE (Default high-profile CVEs)

내장 cves 목록에는 다음 CVE가 포함돼요. Docker는 새 고위험 취약점이 공개됨에 따라 이 목록을 갱신해요.

CVE ID 일반 이름 (Common name)
CVE-2014-0160 Heartbleed
CVE-2014-6271 Shellshock
CVE-2021-44228 Log4Shell
CVE-2021-45046 Log4j 후속 (follow-up)
CVE-2022-22965 Spring4Shell
CVE-2023-38545 curl SOCKS5 힙 오버플로
CVE-2023-44487 HTTP/2 Rapid Reset
CVE-2024-3094 XZ Utils 백도어

목록을 재정의하려면 policy-config 파일에 cves를 설정하세요.

{
  "policies": [
    {
      "name": "high-profile-vulnerabilities",
      "config": {
        "cves": ["CVE-2021-44228", "CVE-2024-3094"]
      }
    }
  ]
}

사용자 지정 정책 작성 (Write custom policies)

정책은 docker.scout 패키지의 Rego 모듈이에요. 정책은 불리언 pass 규칙과 violation 집합을 선언해요. 단일 파일에는 --policy-file을, 디렉토리를 재귀적으로 로드하려면 --policy-dir를 사용하세요.

# METADATA
# title: No packages from internal registry
# description: Flags packages sourced from registry.internal.example.com.
# custom:
#   name: no-internal-registry
#   result_type: generic
#   weight: 5
#   not_compliant_title: Packages from internal registry found
#   details_order:
#   - purl
#   - reason
package docker.scout

import rego.v1

default pass := false

pass if {
    count(violation) == 0
}

violation contains v if {
    att := oci.referrer("https://scout.docker.com/sbom/v0.1")
    some pkg in att.statement.predicate.artifacts
    contains(pkg.purl, "registry.internal.example.com")
    v := {
        "message": sprintf("Package %s sourced from internal registry", [pkg.purl]),
        "detail": {
            "purl": pkg.purl,
            "reason": "matches registry.internal.example.com",
        },
    }
}
# 단일 파일
$ docker scout policy myorg/app:latest --policy-file ./no-internal-registry.rego

# 정책 디렉토리
$ docker scout policy myorg/app:latest --policy-dir ./rego

# 구성 파일과 결합한 사용자 지정 정책
$ docker scout policy myorg/app:latest \
  --policy-dir ./rego \
  --policy-config ./policies.json

--policy-file--policy-dir 둘 다 반복할 수 있어요. 어느 쪽이든 제공하면 내장 기본값은 자동으로 로드되지 않아요. 내장 정책과 사용자 지정 정책을 함께 실행하려면 docker scout policy publish로 내장 집합을 레지스트리에 게시한 다음 --policy-bundle로 두 번들을 모두 전달하세요.

$ docker scout policy myorg/app:latest \
  --policy-bundle registry.example.com/default-policies:latest \
  --policy-bundle registry.example.com/dhi-policies:latest \
  --policy-file ./custom.rego

--policy-bundle은 반복할 수 있어서 로컬 정책 파일과 함께 필요한 만큼 번들을 결합할 수 있어요.

메타데이터 주석 (Metadata annotations)

CLI는 결과를 렌더링하기 위해 OPA 메타데이터 주석을 읽어요. package 선언 바로 위의 # METADATA 블록에 배치하세요.

주석 (Annotation) 용도 (Purpose)
title 보고서에 표시되는 인간이 읽을 수 있는 정책 이름
description 더 긴 설명
custom.name --policy-config 항목과 일치하는 데 사용되는 안정 ID. 생략하면 패키지 경로 기본값
custom.result_type 위반 렌더링 방식: vulnerability, license, boolean, generic (기본값)
custom.weight 채점 가중치와 표시 정렬 순서. 가중치가 높을수록 보고서에서 먼저 정렬되고 건강 점수에 더 기여. 생략하면 10 기본값; 가중치 0은 정책을 점수에서 제외
custom.not_compliant_title 정책이 실패할 때 표시되는 상태 라벨
custom.details_order 열로 표시할 detail 키의 순서 목록

출력 계약 (Output contract)

  • pass: 정책이 충족되면 true. 표준 형식은 pass if { count(violation) == 0 }.
  • violation: 객체 집합. 각 객체는 message 문자열과 custom.details_order와 일치하는 키를 가진 detail 객체를 가져야 해요. 선택적 remediation 문자열은 시정 안내로 표시돼요.

입력과 내장 함수 (Input and built-in functions)

평가 입력은 보강된 SBOM이에요. 주요 진입점:

  • input.source.image: input.source.image.config.config.User, input.source.image.name, input.source.image.digest를 포함한 이미지 메타데이터.
  • data.config: policy-config 파일의 정책별 config 객체.

정책 Rego에서 다음 내장 함수를 사용할 수 있어요.

함수 (Function) 설명 (Description)
oci.referrer(predicateType) predicate 유형별 인증 조회
oci.canonical_name(ref) 이미지 참조 정규화, 예: "node:25""docker.io/library/node"
oci.image_digest(ref) 레지스트리에서 태그의 현재 다이제스트 해석
oci.index(ref, digest) 이미지의 OCI 이미지 인덱스 가져오기
oci.referrer_index(ref, digest) 이미지의 OCI referrer 인덱스 가져오기
oci.referrer_by_digest(ref, digest) 다이제스트로 이미지 referrer 가져오기
scout.parse_purl(purl) PURL을 구성 요소로 파싱
scout.package_provenance(purl) SBOM에서 패키지의 출처(provenance)
scout.vulnerabilities(purls) 주어진 PURL의 취약점
scout.package_recommendation(purl) 패키지의 권장(수정) 버전
scout.base_image() SBOM에 기록된 베이스 이미지 일치
cosign.verify_dsse(envelope, opts) in-toto DSSE 봉투의 cosign 서명 확인
cosign.verify_image(ref, opts) 이미지의 cosign 서명 확인
gpg.verify_commit(...) 분리(대상) 커밋 서명 확인

oci.referrer의 공통 predicate 유형:

Predicate 유형 내용 (Content)
https://scout.docker.com/vulnerabilities/v0.1 패키지별 CVE
https://scout.docker.com/sbom/v0.1 purllicenses가 있는 SBOM 아티팩트
https://scout.docker.com/provenance/v0.1 base_image를 포함한 빌드 출처
https://openvex.dev/ns/v0.2.0 VEX 문

정책 디버깅 (Debug policies)

Rego에 print() 문을 추가하고 policy-config 파일에서 "debug": true를 설정해 디버그 출력을 활성화하세요.

violation contains v if {
    att := oci.referrer("https://scout.docker.com/sbom/v0.1")
    some pkg in att.statement.predicate.artifacts
    print("checking", pkg.purl)
    contains(pkg.purl, blocked)
    # ...
}
{
  "debug": true,
  "policies": [
    { "name": "no-internal-registry" }
  ]
}

출력은 정책 이름과 소스 줄로 접두사가 붙어요.

no-internal-registry#28: checking pkg:deb/debian/[email protected]

[!NOTE]

policy-config의 debug 필드는 Rego의 print() 출력을 제어해요. 전역 --debug 플래그는 별개예요: 번들 로딩, 레지스트리 해석 등과 같은 CLI 수준 디버그 로깅을 활성화해요.

원시 평가 결과 검사 (Inspect raw evaluation results)

--result-file로 모든 정책에 대한 전체 평가 결과를 JSON 파일로 쓰세요. 사용자 지정 정책을 반복할 때 중간 값을 검사하는 데 유용해요.

$ docker scout policy myorg/app:latest \
  --policy-file ./no-internal-registry.rego \
  --result-file result.json

출력의 각 항목에는 다음이 포함돼요.

  • pass: 정책의 불리언 결과.
  • violations: 보고된 각 위반의 detail 객체.
  • bindings: violation 집합과 다른 모든 완전 규칙을 포함한 원시 data.docker.scout 문서, 중간 값 검사용.
  • metrics: OPA 평가 지표 (타이머와 카운터).
{
  "no-internal-registry": {
    "pass": false,
    "violations": [
      { "purl": "pkg:deb/debian/[email protected]", "reason": "matches \"registry.internal.example.com\"" }
    ],
    "bindings": {
      "blocked": "registry.internal.example.com",
      "violation": [
        {
          "message": "Package pkg:deb/debian/[email protected] sourced from internal registry",
          "detail": {
            "purl": "pkg:deb/debian/[email protected]",
            "reason": "matches \"registry.internal.example.com\""
          }
        }
      ]
    },
    "metrics": {
      "timer_rego_query_eval_ns": 1234567
    }
  }
}

정책을 OCI 번들로 공유하기 (Share policies as OCI bundles)

.rego 파일을 OCI 아티팩트로 패키징하고 모든 레지스트리를 통해 배포하세요.

번들 게시 (Publish a bundle)

# 정책 디렉토리 게시
$ docker scout policy publish \
  --policy-dir ./rego \
  registry.example.com/my-policies:latest

# 특정 파일 게시
$ docker scout policy publish \
  --policy-file fixable.rego \
  --policy-file licenses.rego \
  registry.example.com/my-policies:latest

# 내장 기본 집합 게시
$ docker scout policy publish registry.example.com/my-policies:latest

각 모듈의 메타데이터는 게시 전에 검증돼요. 이 명령은 결과 다이제스트와 번들된 정책 목록을 출력해요.

번들 사용 (Use a bundle)

$ docker scout policy myorg/app:latest \
  --policy-bundle registry.example.com/my-policies:latest

# 번들을 로컬 파일·구성과 결합
$ docker scout policy myorg/app:latest \
  --policy-bundle registry.example.com/my-policies:latest \
  --policy-file ./extra.rego \
  --policy-config ./policies.json

--policy-bundle은 반복할 수 있어요. 인증은 기존 Docker 레지스트리 자격 증명을 사용해요. 번들은 다이제스트별로 캐시되므로 같은 번들에 대해 다시 실행해도 다시 다운로드하지 않아요. 새 다이제스트(예: :latest 재게시 후)는 자동으로 가져와요.