InfoGrab DocsInfoGrab Docs

Sec 섹션 분석기 개발

요약

분석기(analyzer)는 CI 파이프라인 환경에서 실행되도록 Docker 이미지로 제공됩니다. 분석기 전반에서 공통 동작과 인터페이스를 위해 공유하는 Go 모듈이 여러 개 있습니다. 분석기는 Docker 이미지로 제공됩니다.

분석기(analyzer)는 CI 파이프라인 환경에서 실행되도록 Docker 이미지로 제공됩니다. 이 가이드에서는 분석기 전반의 개발과 테스트 방법을 설명합니다.

공유 모듈#

분석기 전반에서 공통 동작과 인터페이스를 위해 공유하는 Go 모듈이 여러 개 있습니다.

  • command Go 패키지는 CLI 인터페이스를 구현합니다.
  • common 프로젝트는 로깅, 인증서 처리, 디렉터리 검색 기능을 위한 기타 공유 모듈을 제공합니다.
  • report Go 패키지의 Report·Finding 구조체는 JSON 리포트를 마샬링합니다.
  • template 프로젝트는 새 분석기의 스캐폴드를 생성합니다.

분석기 사용 방법#

분석기는 Docker 이미지로 제공됩니다. 예를 들어 Semgrep Docker 이미지를 실행해 작업 디렉터리를 스캔하는 방법은 다음과 같습니다.

  1. 스캔할 소스 코드가 있는 디렉터리로 cd 합니다.

  2. docker login registry.gitlab.com을 실행하고 사용자 이름과 개인 또는 프로젝트 액세스 토큰(read_registry 스코프 이상)을 입력합니다.

  3. Docker 이미지를 실행합니다.

    docker run \
        --interactive --tty --rm \
        --volume "$PWD":/tmp/app \
        --env CI_PROJECT_DIR=/tmp/app \
        -w /tmp/app \
        registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep:latest /analyzer run
    
  4. Docker 컨테이너는 마운트된 프로젝트 디렉터리에 분석기 카테고리에 해당하는 파일 이름으로 리포트를 생성합니다. 예를 들어 SAST는 gl-sast-report.json 이라는 파일을 생성합니다.

분석기 개발#

분석기를 업데이트하려면 다음을 수행합니다.

  1. Go 소스 코드를 수정합니다.
  2. 새 Docker 이미지를 빌드합니다.
  3. 테스트 프로젝트를 대상으로 분석기를 실행합니다.
  4. 생성된 리포트를 예상 결과와 비교합니다.

analyzer 라는 이름의 Docker 이미지를 생성하는 방법은 다음과 같습니다.

docker build -t analyzer .

예를 들어 시크릿 탐지를 테스트하려면 다음을 실행합니다.

wget https://gitlab.com/gitlab-org/security-products/ci-templates/-/raw/master/scripts/compare_reports.sh
sh ./compare_reports.sh sd test/fixtures/gl-secret-detection-report.json test/expect/gl-secret-detection-report.json \
| patch -Np1 test/expect/gl-secret-detection-report.json && git commit -m 'Update expectation' test/expect/gl-secret-detection-report.json
rm compare_reports.sh

직접 환경에서 바이너리를 컴파일해 로컬로 실행할 수도 있지만, 분석기의 런타임 의존성이 없기 때문에 analyze와 run은 대부분 동작하지 않습니다.

SpotBugs를 기반으로 한 예시는 다음과 같습니다.

go build -o analyzer
./analyzer search test/fixtures
./analyzer convert test/fixtures/app/spotbugsXml.Xml > ./gl-sast-report.json

Secure 스테이지 CI/CD 템플릿 및 컴포넌트#

Secure 스테이지는 다음 CI/CD 템플릿과 컴포넌트의 유지 관리를 담당합니다.

변경 사항은 항상 해당 그룹의 CI/CD 템플릿과 컴포넌트 양쪽에 모두 반영해야 하며, 최신 CI/CD 템플릿에도 적용해야 하는지 판단해야 합니다.

분석기는 오프라인 환경을 위한 Secure-Binaries.gitlab-ci.yml 파일에도 참조되어 있습니다. 변경 작업을 할 때는 이 파일도 함께 동기화되도록 합니다.

실행 기준#

SAST 활성화에는 GitLab CI/CD 구성에 사전 정의된 템플릿을 포함해야 합니다.

다음의 독립적인 기준에 따라 프로젝트에서 실행할 분석기가 결정됩니다.

  1. SAST 템플릿은 rules:exists를 사용해 특정 파일의 존재 여부로 실행할 분석기를 결정합니다. 예를 들어 Brakeman 분석기는 .rb 파일과 Gemfile 이 있을 때 실행됩니다.
  2. 각 분석기는 실제 분석을 수행하기 전에 사용자 정의가 가능한 매치 인터페이스를 실행합니다. 예를 들어 Flawfinder는 C/C++ 파일을 확인합니다.
  3. 범용 파일 확장자를 대상으로 실행되는 일부 분석기는 CI/CD 변수를 기준으로 확인합니다. 예를 들어 Kubernetes 매니페스트는 YAML로 작성되므로, Kubesec는 SCAN_KUBERNETES_MANIFESTS가 true로 설정된 경우에만 실행됩니다.

1단계는 프로젝트에 적합하지 않은 분석기를 실행하는 데 드는 컴퓨팅 할당량 낭비를 막는 데 도움이 됩니다. 다만 기술적 제약 때문에 대규모 프로젝트에는 사용할 수 없습니다. 따라서 2단계가 최종 확인 역할을 하여, 맞지 않는 분석기가 조기에 종료될 수 있도록 합니다.

분석기 테스트 방법#

의존성 스캐닝 분석기가 테스트 프로젝트를 사용해 분석기를 테스트할 때 다운스트림 파이프라인 기능을 어떻게 활용하는지 보여주는 영상입니다.

Sec 섹션이 GitLab의 다운스트림 파이프라인 기능을 활용해 분석기를 엔드투엔드로 테스트하는 방법

로컬 변경 사항 테스트#

분석기의 공유 모듈(command나 report 등)에서 로컬 변경 사항을 테스트하려면, 원격에 태그된 command 버전 대신 로컬 변경 사항이 적용된 command를 불러오도록 go mod replace 지시자를 사용할 수 있습니다. 예를 들면 다음과 같습니다.

go mod edit -replace gitlab.com/gitlab-org/security-products/analyzers/command/v3=/local/path/to/command

또는 go.mod 파일을 직접 수정해 같은 결과를 얻을 수도 있습니다.

module gitlab.com/gitlab-org/security-products/analyzers/awesome-analyzer/v2

replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /path/to/command

require (
    ...
    gitlab.com/gitlab-org/security-products/analyzers/command/v3 v2.19.0
)

Docker에서 로컬 변경 사항 테스트#

go.mod 파일의 replace를 Docker와 함께 사용하려면 다음을 수행합니다.

  1. command의 내용을 분석기 디렉터리로 복사합니다. cp -r /path/to/command path/to/analyzer/command.
  2. 분석기의 Dockerfile에 복사 문을 추가합니다. COPY command /command.
  3. 위 단계의 COPY 문 대상과 일치하도록 replace 문을 업데이트합니다. replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /command

컨테이너 오케스트레이션 호환성 테스트#

사용자는 컨테이너를 오케스트레이션하고 분석기를 실행하는 데 Docker가 아닌 containerd, Podman, skopeo 같은 다른 도구를 사용할 수도 있습니다. 이러한 도구와의 호환성을 보장하기 위해, 예약된 파이프라인으로 모든 분석기를 주기적으로 테스트합니다. 테스트가 실패하면 Slack 알림이 발생합니다.

분석기 Docker 이미지를 빌드할 때 호환성 문제를 피하려면, 기본 Docker 독점 미디어 유형 대신 OCI 미디어 유형을 사용합니다.

주기적 테스트 외에도, ci-templates 리포지터리 사용자를 위한 호환성도 보장합니다.

  1. ci-templates의 docker-test.yml 템플릿을 사용하는 분석기는 지원되는 Docker 도구에서 Docker 이미지가 올바르게 동작하는지 확인하기 위한 tests를 포함합니다.

    이 테스트는 머지 리퀘스트 파이프라인과 예약된 파이프라인에서 실행되며, 지원되는 Docker 도구를 손상시키는 이미지가 릴리스되지 않도록 막습니다.

  2. ci-templates의 docker.yml 템플릿은 분석기 이미지를 빌드할 때 docker buildx 명령에 oci-mediatypes=true를 지정합니다. 이렇게 하면 Docker 독점 미디어 유형이 아니라 OCI 미디어 유형을 사용해 이미지를 빌드합니다.

새 분석기를 만들거나 기존 분석기 이미지의 위치를 변경할 때는 주기적 테스트에 추가하거나, 자동화된 테스트가 포함된 공유 ci-templates 사용을 고려합니다.

분석기 스크립트#

analyzer-scripts 리포지터리에는 대부분의 분석기와 상호 작용할 때 사용할 수 있는 스크립트가 있습니다. 이 스크립트를 사용하면 GitLab CI와 유사한 환경에서 분석기를 빌드, 실행, 디버깅할 수 있으며, 분석기 변경 사항을 로컬에서 검증할 때 특히 유용합니다.

자세한 내용은 프로젝트 README를 참고합니다.

버전 관리 및 릴리스 프로세스#

GitLab Security Products는 GitLab의 MAJOR.MINOR와는 별개의 독립적인 버전 관리 체계를 사용합니다. 모든 제품은 시맨틱 버저닝의 변형을 사용하며 Docker 이미지로 제공됩니다.

Major는 주요 변경이 허용되는 GitLab의 새로운 메이저 릴리스마다 올라갑니다. Minor는 새 기능이 추가될 때 올라가고, Patch는 버그 수정용으로 예약되어 있습니다.

분석기는 다음 체계에 따라 Docker 이미지로 릴리스됩니다.

  • 기본 브랜치로의 모든 푸시는 edge 이미지 태그를 덮어씁니다
  • awesome-feature 브랜치로의 모든 푸시는 그에 대응하는 awesome-feature 이미지 태그를 생성합니다
  • 모든 Git 태그는 그에 대응하는 Major.Minor.Patch 이미지 태그를 생성합니다. 수동 job을 사용하면 해당 Major 및 latest 이미지 태그가 이 Major.Minor.Patch를 가리키도록 재정의할 수 있습니다.

대부분의 경우 최신 권고 사항이나 도구 패치가 자동으로 반영되는 MAJOR 이미지를 사용하는 것이 좋습니다. 포함된 CI 템플릿은 메이저 버전으로 고정되어 있지만, 필요하면 사용자가 버전을 직접 재정의할 수 있습니다.

새 분석기 Docker 이미지를 릴리스하는 방법에는 두 가지가 있습니다.

다음 다이어그램은 새 분석기 버전이 릴리스될 때 생성되는 Docker 태그를 보여줍니다.

Mermaid 다이어그램 (16줄)
소스 코드 보기
graph LR

A1[git tag v1.1.0]--> B1(run CI pipeline) B1 -->|build and tag patch| D1[1.1.0] B1 -->|tag minor| E1[1.1] B1 -->|retag major| F1[1] B1 -->|retag latest| G1[latest]

A2[git tag v1.1.1]--> B2(run CI pipeline) B2 -->|build and tag patch| D2[1.1.1] B2 -->|retag minor| E2[1.1] B2 -->|retag major| F2[1] B2 -->|retag latest| G2[latest]

A3[push to default branch]--> B3(run CI pipeline) B3 -->|build and tag edge| D3[edge]

지속적 배포(Continuous Deployment) 흐름에 따라, GitLab Rails 애플리케이션에 대응하는 항목이 없는 새 컴포넌트는 언제든 릴리스할 수 있습니다. 컴포넌트가 기존 애플리케이션에 통합되기 전까지는 표준 릴리스 사이클과 프로세스 때문에 반복 작업이 지연되어서는 안 됩니다.

수동 릴리스 프로세스#

  1. 새 분석기의 CHANGELOG.md 항목이 올바른지 확인합니다.
  2. 릴리스 소스(일반적으로 master 또는 main 브랜치)의 파이프라인이 통과했는지 확인합니다.
  3. 프로젝트 창 왼쪽의 Deployments 메뉴를 선택한 다음 Releases 하위 메뉴를 선택해 분석기 프로젝트의 새 릴리스를 생성합니다.
  4. New release를 선택해 New Release 페이지를 엽니다.
    1. Tag name 드롭다운에 CHANGELOG.md에서 사용한 것과 같은 버전(예: v2.4.2)을 입력하고, 태그를 생성하는 옵션(여기서는 Create tag v2.4.2)을 선택합니다.
    2. Release title 텍스트 박스에 위에서 사용한 것과 같은 버전(예: v2.4.2)을 입력합니다.
    3. Release notes 텍스트 박스에 CHANGELOG.md의 해당 버전 노트를 복사해 붙여넣습니다.
    4. 다른 설정은 모두 기본값으로 둡니다.
    5. Create release를 선택합니다.

위 과정을 따라 새 릴리스를 만들면, 위에서 지정한 Tag name으로 새 Git 태그가 생성됩니다. 이렇게 하면 해당 태그 버전으로 새 파이프라인이 트리거되고 새로운 분석기 Docker 이미지가 빌드됩니다.

분석기가 analyzer.yml 템플릿을 사용하는 경우, 위의 New release 과정에서 트리거된 파이프라인이 분석기 Docker 이미지의 새 버전을 자동으로 태깅하고 배포합니다.

분석기가 analyzer.yml 템플릿을 사용하지 않는 경우, 분석기 Docker 이미지의 새 버전을 수동으로 태깅하고 배포해야 합니다.

  1. 프로젝트 창 왼쪽의 CI/CD 메뉴를 선택한 다음 Pipelines 하위 메뉴를 선택합니다.
  2. 이전에 사용한 것과 같은 태그(예: v2.4.2)로 새 파이프라인이 현재 실행 중이어야 합니다.
  3. 파이프라인이 완료되면 blocked 상태가 됩니다.
  4. 창 오른쪽의 Manual job 재생 버튼을 선택하고 tag version을 선택해 분석기 Docker 이미지의 새 버전을 태깅 및 배포합니다.

Git 태그를 생성해 릴리스 job을 트리거할 시점은 각자의 판단에 따라 결정합니다. 판단하기 어려우면 다른 사람의 의견을 구합니다.

자동 릴리스 프로세스#

자동 릴리스 프로세스를 사용하기 전에 다음을 수행해야 합니다.

  1. CI/CD 환경 변수로 CREATE_GIT_TAG: true를 구성합니다.

  2. CI/CD 프로젝트 설정의 Variables를 확인합니다.

위 단계를 완료하면 자동 릴리스 프로세스는 다음과 같이 실행됩니다.

  1. 프로젝트 메인테이너가 MR을 기본 브랜치에 머지합니다.
  2. 기본 파이프라인이 트리거되고 upsert git tag job이 실행됩니다.
    • CHANGELOG.md의 최신 버전이 기존 Git 태그 중 하나와 일치하면 이 job은 아무 동작도 하지 않습니다.
    • 그렇지 않으면 이 job이 릴리스 API를 사용해 새 릴리스와 Git 태그를 자동으로 생성합니다. 버전과 메시지는 해당 프로젝트의 CHANGELOG.md 파일에서 가장 최근 항목을 사용합니다.
  3. 새 Git 태그에 대해 파이프라인이 자동으로 트리거됩니다. 이 파이프라인은 분석기의 latest, major, minor, patch Docker 이미지를 릴리스합니다.

자동 릴리스 프로세스에서 사용하는 서비스 계정#

키 값
계정 이름 @gl-service-dev-secure-analyzers-automation
용도 릴리스·태그 생성에 사용합니다
소속 gitlab-org/security-products
최대 권한 Developer
연결된 GITLAB_TOKEN의 스코프 api
GITLAB_TOKEN의 만료일 November 11, 2026
Warning

서비스 계정의 액세스 토큰 스코프나 GITLAB_TOKEN 변수 권한을 변경할 때는 반드시 섹션의 Slack 채널에 공지해야 합니다.

서비스 계정 토큰 교체#

@gl-service-dev-secure-analyzers-automation 서비스 계정의 GITLAB_TOKEN은 위에 표시된 Expiry Date 이전에 다음과 같이 교체해야 합니다.

  1. gl-service-dev-secure-analyzers-automation 사용자로 로그인합니다.

    이 계정의 자격 증명을 보유한 관리자 목록은 서비스 계정 액세스 요청에서 확인할 수 있습니다.

    관리자는 공유 GitLab 1password 볼트에서 로그인 자격 증명을 확인할 수 있습니다.

  2. gl-service-dev-secure-analyzers-automation 서비스 계정을 위해 api 스코프를 가진 새 개인 액세스 토큰을 생성합니다.

  3. 공유 GitLab 1password 볼트에서 GitLab API Token - gl-service-dev-secure-analyzers-automation 계정의 password 필드를 위의 2단계에서 생성한 새 개인 액세스 토큰으로 업데이트하고, Expires at 필드에 토큰 만료 시점을 설정합니다.

  4. 자동 릴리스 프로세스에서 사용하는 서비스 계정 표에서 GITLAB_TOKEN 필드의 만료일을 업데이트합니다.

  5. 다음 변수를 위의 2단계에서 생성한 새 개인 액세스 토큰으로 설정합니다.

    [!note] 다음 변수는 반드시 마스킹 및 숨김 처리해야 합니다.

    변수 프로젝트/그룹 이유
    GITLAB_TOKEN gitlab-org/security-products/analyzers gitlab-org/security-products/analyzers 네임스페이스 아래의 모든 프로젝트가 이 GITLAB_TOKEN 값을 상속받을 수 있게 합니다.
    gitlab-org/security-products/license-db 이 프로젝트/그룹은 gitlab-org/security-products/analyzers 네임스페이스 아래에 있지 않으므로 상속받지 못합니다. 따라서 GITLAB_TOKEN을 명시적으로 구성해야 합니다.
    gitlab-org/security-products/dependency-management
    gitlab-org/security-products/post-analyzers/tracking-calculator1
    gitlab-org/security-products/ci-templates2
    SEC_REGISTRY_PASSWORD gitlab-advanced-sast 이를 통해 태깅 스크립트가 개발 프로젝트의 프라이빗 컨테이너 레지스트리 registry.gitlab.com/gitlab-org/security-products/analyzers/<analyzer-name>/tmp에서 가져와, 공개 컨테이너 레지스트리 registry.gitlab.com/security-products/<analyzer-name>로 푸시할 수 있습니다.

    각주:

    1. 분석기 네임스페이스로 post-analyzer 프로젝트 이동(#582004)이 완료되면 이 프로젝트의 GITLAB_TOKEN 명시적 설정을 제거할 수 있습니다.
    2. ci-templates 프로젝트는 upsert git tag job이 새 릴리스를 생성할 수 있도록 GITLAB_TOKEN이 필요합니다.

교체가 필요한 다른 토큰#

토큰 프로젝트 만료일 비고
VERIFY_CI_TEMPLATE_TOKEN ci-templates January 22, 2027 verify ci templates job에서 사용합니다. CI/lint 엔드포인트에 JOB-TOKEN 액세스 허용(#438781)이 완료되면 이 변수의 명시적 설정을 제거할 수 있습니다.

분석기 릴리스 후 수행할 단계#

  1. 분석기 Docker 이미지의 새 버전이 태깅되고 배포된 후, 해당 테스트 프로젝트로 테스트합니다.

  2. 관련 그룹의 Slack 채널에 릴리스를 공지합니다. 메시지 예시:

    FYI I've just released ANALYZER_NAME ANALYZER_VERSION. LINK_TO_RELEASE

이미 푸시된 Git 태그는 Go 패키지 레지스트리에서 사용되거나 캐시되어 있을 가능성이 크므로, 절대로 삭제하지 않습니다.

긴급 수정이나 패치 백포팅#

이전 버전에 긴급 수정이나 패치를 백포팅하려면 다음 단계를 따릅니다.

  1. 수정 사항을 백포팅할 태그에서 새 브랜치를 생성합니다(브랜치가 없는 경우).
    • 예를 들어 최신 안정 태그가 v4이고 v3에 수정 사항을 백포팅한다면, v3라는 브랜치를 생성합니다.
  2. 방금 생성한 브랜치를 대상으로 머지 리퀘스트를 제출합니다.
  3. 승인되면 머지 리퀘스트를 해당 브랜치에 머지합니다.
  4. 해당 브랜치에 새 태그를 생성합니다.
  5. 분석기에 자동 릴리스 프로세스가 활성화되어 있으면 새 버전이 릴리스됩니다.
  6. 그렇지 않으면 수동 릴리스 프로세스를 따라 새 버전을 릴리스해야 합니다.
  7. 참고: 릴리스 파이프라인은 최신 edge 태그를 덮어쓰므로, 리그레션을 방지하려면 가장 최근 릴리스 파이프라인의 tag edge job을 다시 실행해야 할 수도 있습니다.

메이저 버전 릴리스를 위한 분석기 준비#

이 프로세스는 다음 그룹에 적용됩니다.

다른 그룹은 자체 메이저 버전 릴리스 프로세스를 문서화할 책임이 있습니다.

메이저 버전 릴리스에 주요 변경(breaking change)이 포함되는지에 따라 다음 시나리오 중 하나를 선택합니다.

  1. 주요 변경 없는 메이저 버전 릴리스
  2. 주요 변경이 있는 메이저 버전 릴리스

주요 변경 없는 메이저 버전 릴리스#

현재 분석기 릴리스가 v{N}이라고 가정합니다.

  1. 보호된 태그와 브랜치를 구성합니다.
  2. 메이저 릴리스 마일스톤 중 default 브랜치에 더 이상 머지할 변경 사항이 없을 때:
    1. default 브랜치에서 v{N} 브랜치를 생성합니다.

    2. default 브랜치에 CHANGELOG.md 파일의 다음 변경 사항만 담은 새 머지 리퀘스트를 생성하고 머지합니다.

      ## v{N+1}.0.0
      - Major version release (!<MR-ID>)
      
    3. 예약된 파이프라인을 구성합니다.

    4. CI/CD 템플릿과 컴포넌트의 분석기 메이저 버전을 올립니다

주요 변경이 있는 메이저 버전 릴리스#

현재 분석기 릴리스가 v{N}이라고 가정합니다.

  1. 보호된 태그와 브랜치를 구성합니다.

  2. 주요 변경 사항을 "스테이징"하기 위한 새 브랜치 v{N+1}을 생성합니다.

  3. 메이저 릴리스 마일스톤에 이르기까지의 마일스톤 동안:

    • 주요 변경이 아닌 사항은 default 브랜치(master 또는 main)에 머지합니다

    • 주요 변경 사항은 v{N+1} 브랜치에 머지하고, 변경마다 CHANGELOG.md 파일에 별도의 release candidate 항목을 생성합니다.

      ## v{N+1}.0.0-rc.0
      - some breaking change (!123)
      

      release candidates를 사용하면 모든 주요 변경을 한 번의 메이저 버전 상승으로 릴리스할 수 있으며, 이는 메이저 버전 업데이트에서만 주요 변경을 하라는 semver 가이드를 따르는 방식입니다.

  4. 메이저 릴리스 마일스톤 중 default 또는 v{N+1} 브랜치에 더 이상 머지할 변경 사항이 없을 때:

    1. default 브랜치에서 v{N} 브랜치를 생성합니다.

    2. v{N+1} 브랜치에 머지 리퀘스트를 생성해 모든 release candidate 체인지로그 항목을 v{N+1}에 대한 단일 항목으로 통합합니다.

      예를 들어 CHANGELOG.md에 버전 v{N+1}에 대한 다음 3개의 release candidate 항목이 있다면:

      ## v{N+1}.0.0-rc.2
      - yet another breaking change (!125)
      
      ## v{N+1}.0.0-rc.1
      - another breaking change (!124)
      
      ## v{N+1}.0.0-rc.0
      - some breaking change (!123)
      

      이때 새 머지 리퀘스트는 모든 release candidate 항목을 하나로 합쳐 v{N+1}에 대한 단일 메이저 릴리스 항목이 되도록 CHANGELOG.md를 업데이트해야 합니다.

      ## v{N+1}.0.0
      - yet another breaking change (!125)
      - another breaking change (!124)
      - some breaking change (!123)
      
    3. v{N+1} 브랜치의 모든 주요 변경 사항을 default 브랜치에 머지하는 머지 리퀘스트를 생성합니다.

    4. default 브랜치에 v{N+1} 브랜치의 모든 변경 사항이 반영되었으므로, 더 이상 필요 없는 v{N+1} 브랜치를 삭제합니다.

    5. 예약된 파이프라인을 구성합니다.

    6. CI/CD 템플릿과 컴포넌트의 분석기 메이저 버전을 올립니다.

보호된 태그와 브랜치 구성#
  1. 프로젝트에서 와일드카드 v*가 보호된 태그와 보호된 브랜치로 모두 설정되어 있는지 확인합니다.

  2. gl-service-dev-secure-analyzers-automation 서비스 계정이 보호된 태그를 Allowed to create 상태인지 확인합니다.

    자세한 내용은 공식 지원 이미지 절의 3.1 단계를 참고합니다.

예약된 파이프라인 구성#
  1. 세 개의 예약된 파이프라인이 있는지 확인하고, 없으면 생성한 다음 모두 PUBLISH_IMAGES: true로 설정합니다.
    • Republish images v{N}(v{N} 브랜치 대상)

      이 예약된 파이프라인은 새로 생성해야 합니다

    • Daily build(default 브랜치 대상)

      이 예약된 파이프라인은 이미 있어야 합니다

    • Republish images v{N-1}(v{N-1} 브랜치 대상)

      이 예약된 파이프라인은 이미 있어야 합니다

  2. 지원되는 이전 메이저 버전은 두 개까지이므로, v{N-2} 브랜치용 예약된 파이프라인이 있다면 삭제합니다.
CI/CD 템플릿과 컴포넌트의 분석기 메이저 버전 올리기#

모든 v{N+1} 분석기 이미지가 registry.gitlab.com/security-products/:에서 사용 가능해지면, 소속 그룹의 Secure 스테이지 CI/CD 템플릿 및 컴포넌트에서 각 분석기의 메이저 버전을 올리는 새 머지 리퀘스트를 생성합니다.

새 분석기 개발#

새로운 프레임워크와 도구를 지원하기 위해 새 분석기 프로젝트를 구축해야 할 때가 있습니다. 이때는 라이선스와 코드 표준을 포함한 엔지니어링 오픈소스 가이드라인을 따라야 합니다.

또한 GitLab 애플리케이션에 통합될 커스텀 분석기를 작성하려면 최소한의 기능 세트가 필요합니다.

체크리스트#

기반 도구에 다음 항목이 있는지 확인합니다.

Dockerfile#

Dockerfile은 GitLab이라는 이름의 비권한(unprivileged) 사용자를 사용해야 합니다. 이는 컨테이너를 관리자(root) 사용자로 실행할 수 없는 Red Hat OpenShift 인스턴스와의 호환성을 위해 필요합니다. 비권한 사용자로 컨테이너를 실행할 때는 몇 가지 제약을 고려해야 하는데, 예를 들어 Docker 파일 시스템에 기록해야 하는 모든 파일에는 GitLab 사용자에 맞는 권한이 필요합니다. 자세한 내용은 다음 머지 리퀘스트를 참고합니다. Docker 이미지에서 root 대신 GitLab 사용자 사용.

최소 취약점 데이터#

필수 필드의 전체 목록은 security-report-schemas를 참고합니다.

security-report-schema 리포지터리에는 각 리포트 유형별 필수 필드를 나열하는 JSON 스키마가 있습니다.

리포트 스키마와의 호환성#

GitLab에 아티팩트로 업로드된 보안 리포트는 수집되기 전에 검증됩니다.

보안 리포트 스키마는 SchemaVer(MODEL-REVISION-ADDITION)로 버전이 관리됩니다. Sec 섹션은 GitLab과 스키마 버전 간의 호환성을 포함해 security-report-schemas 프로젝트를 담당합니다. 스키마 변경은 제품 전반의 지원 종료 가이드라인을 따라야 합니다.

새 MODEL 버전이 도입되면, 새 스키마를 채택한 분석기는 이 새 스키마 버전을 포함하지 않은 GitLab 배포본에서도 보안 리포트를 오류나 경고 없이 계속 수집할 수 있도록 보장할 책임이 있습니다.

이는 여러 방식으로 구현할 수 있습니다.

  1. 분석기에 여러 스키마 버전 지원을 구현합니다. GitLab 버전에 따라 분석기는 GitLab이 지원하는 최신 스키마 버전으로 보안 리포트를 생성합니다.
    • 장점: 분석기가 런타임에 사용할 최적의 버전을 결정할 수 있습니다.
    • 단점: 구현 노력이 들고 복잡성이 늘어납니다.
  2. 새 분석기 메이저 버전을 릴리스합니다. 최신 MODEL 스키마 버전을 포함하지 않은 인스턴스는 MODEL-1 버전으로 리포트를 생성하는 분석기 버전을 계속 사용합니다.
    • 장점: 분석기 코드를 단순하게 유지합니다.
    • 단점: 유지 관리해야 할 분석기 버전이 늘어납니다.
  3. 새 스키마 사용을 지연시킵니다. 이 방식은 스키마에 없는 속성도 리포트에 포함할 수 있게 하는 additionalProperties=true를 사용합니다. 새 분석기 메이저 버전은 평소와 같은 주기로 릴리스됩니다.
    • 장점: 추가로 유지 관리할 분석기가 없고 분석기 코드가 단순하게 유지됩니다.
    • 단점: 스키마가 검증되지 않는 위험이 커지거나, 그 위험을 줄이기 위한 노력이 늘어납니다.

어떤 방식을 따라야 할지 확신이 없다면 security-report-schemas 메인테이너에게 문의합니다.

컨테이너 이미지 위치#

Secure 분석기의 컨테이너 이미지는 두 곳에 게시됩니다.

  • registry.gitlab.com/security-products 네임스페이스의 공식 지원 이미지. 예를 들면 다음과 같습니다.

    registry.gitlab.com/security-products/semgrep:5
    
  • 프로젝트 네임스페이스의 임시 개발 이미지. 예를 들면 다음과 같습니다.

    registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep/tmp:d27d44a9b33cacff0c54870a40515ec5f2698475
    

공식 지원 이미지#

Secure 템플릿에서 참조하는 공식 지원 이미지의 위치는 다음과 같습니다.

registry.gitlab.com/security-products/:

예를 들어 SAST.gitlab-ci.yml 템플릿의 semgrep-sast job은 컨테이너 이미지 registry.gitlab.com/security-products/semgrep:5를 참조합니다.

이 위치로 이미지를 푸시하려면 다음을 수행합니다.

  1. https://gitlab.com/security-products/에 새 프로젝트를 생성합니다.

    예: https://gitlab.com/security-products/semgrep

    이 프로젝트의 이미지는 registry.gitlab.com/security-products/:에 게시됩니다.

    예: registry.gitlab.com/security-products/semgrep:5

  2. https://gitlab.com/security-products/ 프로젝트를 다음과 같이 구성합니다.

    1. 다음 권한을 추가합니다.

    2. 다음 프로젝트 설정을 구성합니다.

      • Settings -> Packages and registries
        • Protected container image tags
          • 보호된 컨테이너 이미지 태그가 없는지 확인합니다. 설정에는 No container image tags are protected.로 표시되어야 합니다.

            이 설정의 근거에 대한 설명은 이 댓글을 참고합니다.

      • Settings -> General -> Visibility, project features, permissions
        • Project visibility
          • Public
        • Additional options
          • Users can request access
            • Disabled
        • Issues
          • Disabled
        • Repository
          • Only Project Members
          • Merge Requests
            • Disabled
          • Forks
            • Disabled
          • Git Large File Storage (LFS)
            • Disabled
          • CI/CD
            • Disabled
        • Container Registry
          • Everyone with access
        • Analytics, Requirements, Security and compliance, Wiki, Snippets, Package registry, Model experiments, Model registry, Pages, Monitor, Environments, Feature flags, Infrastructure, Releases, GitLab Duo
          • Disabled
  3. https://gitlab.com/gitlab-org/security-products/analyzers/에 있는 _분석기 프로젝트_에서 다음 옵션을 구성합니다.

    1. 와일드카드 v*를 보호된 태그로 추가합니다.

      gl-service-dev-secure-analyzers-automation 서비스 계정이 보호된 태그를 Allowed to create할 수 있는 계정 목록에 명시적으로 추가되어 있는지 확인합니다. 이는 upsert git tag job이 분석기 프로젝트의 새 릴리스를 생성할 수 있도록 하기 위해 필요합니다.

    2. 와일드카드 v*를 보호된 브랜치로 추가합니다.

    3. CI/CD 환경 변수

      [!note] SEC_REGISTRY_PASSWORD 변수는 반드시 마스킹 및 숨김 처리해야 합니다.

      키 값
      SEC_REGISTRY_IMAGE registry.gitlab.com/security-products/$CI_PROJECT_NAME
      SEC_REGISTRY_USER gl-service-dev-secure-analyzers-automation
      SEC_REGISTRY_PASSWORD gl-service-dev-secure-analyzers-automation 사용자의 개인 액세스 토큰입니다. 이 토큰 값 구성은 관리자에게 요청합니다.

      위 변수는 ci-templates 프로젝트의 tag_image.sh 스크립트가 컨테이너 이미지를 registry.gitlab.com/security-products/:에 푸시할 때 사용됩니다.

      예시는 semgrep CI/CD 변수를 참고합니다.

임시 개발 이미지#

임시 개발 이미지의 위치는 다음과 같습니다.

registry.gitlab.com/gitlab-org/security-products/analyzers//tmp:

예를 들어 semgrep 분석기의 개발 이미지 중 하나는 다음과 같습니다.

registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep/tmp:7580d6b037d93646774de601be5f39c46707bf04

컨테이너 레지스트리에 쓰기 액세스 권한을 가진 사람의 수를 제한하기 위해, https://gitlab.com/gitlab-org/security-products/analyzers/에 있는 프로젝트의 다음 프로젝트 기능 및 권한 설정을 구성해 개발 프로젝트의 컨테이너 레지스트리를 비공개로 전환해야 합니다.

  • Settings -> General -> Visibility, project features, permissions
    • Container Registry
      • Only Project Members

Sec 섹션의 각 그룹은 다음을 책임집니다.

  1. 자체 아티팩트의 지원 종료 및 제거 일정을 관리하고, 이를 위한 이슈를 생성합니다.
  2. 새 위치 아래에 프로젝트를 생성하고 구성합니다.
  3. 릴리스 아티팩트를 새 위치로 푸시하도록 빌드를 구성합니다.
  4. 각자의 지원 계약에 따라 기존 위치의 이미지를 제거하거나 유지합니다.

컨테이너 이미지 일일 재빌드#

분석기 이미지는 사용 중인 베이스 이미지 제공업체가 제공하는 패치를 자주 자동으로 반영하기 위해 매일 재빌드됩니다.

이 프로세스는 현재 MAJOR 릴리스에 해당하는 GitLab 버전에서 사용하는 이미지에만 적용됩니다. 매일 새 버전을 릴리스하려는 것이 아니라, 이미지의 각 활성 변형을 재빌드하고 해당 태그를 덮어쓰는 것이 목적입니다.

  • MAJOR.MINOR.PATCH 이미지 태그(예: 4.1.7)
  • MAJOR.MINOR 이미지 태그(예: 4.1)
  • MAJOR 이미지 태그(예: 4)
  • latest 이미지 태그

재빌드 프로세스의 구현은 프로젝트에 따라 다를 수 있지만, 이를 지원하기 위한 공유 CI 구성이 개발용 ci-templates 프로젝트에 있습니다.

GitLab Advanced SAST(GLAS)에 새 언어 지원 추가#

이 가이드는 엔지니어가 GLAS에 새 언어 지원을 평가하고 추가하는 데 도움을 줍니다. 이 가이드라인은 엄격한 요구 사항이 아니라, 언어 범위를 확장할 때 일관된 품질을 보장하기 위한 것입니다.

언어 지원 준비 기준#

분석기 품질 표준을 유지하면서 이 가이드라인을 각 언어의 특성에 맞게 조정합니다.

이 가이드라인은 GLAS에 PHP 지원을 추가한 경험(이슈 #514210 참고)에서 나온 것으로, 새 언어 지원이 프로덕션에 사용할 준비가 되었는지 판단하는 데 도움을 줍니다.

품질 준비도#

파일 간 분석 기능#
  • 대상 언어에서 가장 일반적인 의존성 관리 패턴을 지원합니다
  • 해당 언어 특유의 일반적인 포함(include) 메커니즘을 지원합니다
탐지 품질#
  • 지원되는 모든 CWE에서 정밀도(Precision Rate) 80% 이상
  • 지원되는 각 CWE에 대한 포괄적인 테스트 코퍼스
  • 해당 언어 생태계의 인기 프레임워크를 대상으로 테스트

커버리지 준비도#

우선순위 기반 커버리지#
  • 해당 언어와 관련된 치명적인 인젝션 취약점을 다뤄야 합니다
  • 흔히 발생하는 보안 설정 오류를 다뤄야 합니다
  • 업계 표준(OWASP Top 10, SANS CWE Top 25)에 부합해야 합니다
  • 해당 언어에서 흔히 발견되는 영향도가 큰 취약점에 집중합니다

지원 준비도#

문서화 요구 사항#
  • 지원 언어 문서에 해당 언어가 등재되고 설명되어 있습니다
  • CWE 커버리지 표에 새 언어 열이 업데이트되어 있습니다
  • 지원되는 모든 CWE가 올바르게 표시되어 있습니다
  • 알려진 제약 사항이 명확히 문서화되어 있습니다

성능 준비도#

표준 성능 기준#
  • 중간 규모 애플리케이션: 10분 미만
  • 매우 큰 애플리케이션: 멀티코어 옵션 사용 시 30분 미만
벤치마크 정의#
  • 벤치마킹에 사용할 대표 코드베이스를 정의합니다
  • 일반적인 프레임워크와 라이브러리를 포함합니다

Go의 보안 및 빌드 수정#

Go로 구현된 Secure 분석기의 Dockerfile은 MINOR 리비전이 아니라 Go의 MAJOR 릴리스를 참조해야 합니다. 이렇게 하면 분석기를 컴파일할 때 사용하는 Go 버전에 당시 사용 가능한 모든 보안 수정 사항이 포함됩니다. 예를 들어 분석기의 멀티스테이지 Dockerfile은 분석기 CLI를 빌드할 때 golang:1.15-alpine 이미지를 사용해야 하며, golang:1.15.4-alpine을 사용하면 안 됩니다.

Go의 MINOR 리비전이 릴리스되고 여기에 보안 수정 사항이 포함되어 있으면, 프로젝트 메인테이너는 Secure 분석기를 재빌드해야 하는지 확인해야 합니다. 빌드에 사용된 Go 버전은 해당 릴리스에 대응하는 build job의 로그에 나타나며, strings 명령으로 Go 바이너리에서 추출할 수도 있습니다.

분석기의 최신 이미지가 영향을 받는 Go 버전으로 빌드되었다면 재빌드해야 합니다. 이미지를 재빌드하려면 메인테이너는 다음 중 하나를 수행할 수 있습니다.

  • 안정 릴리스에 대응하는 Git 태그로 새 파이프라인을 트리거합니다
  • BUILD 번호를 올린 새 Git 태그를 생성합니다
  • PUBLISH_IMAGES 변수를 비어 있지 않은 값으로 설정하고 기본 브랜치에 대한 파이프라인을 트리거합니다

어느 방법을 사용하든 새 Docker 이미지가 빌드되며, 동일한 이미지 태그(MAJOR.MINOR.PATCH, MAJOR)로 게시됩니다.

이 워크플로는 같은 MAJOR 릴리스의 MINOR 리비전 간에 완전한 호환성이 있다고 가정합니다. 호환성 문제가 있으면 테스트 실행 시 프로젝트 파이프라인이 실패합니다. 이 경우 Dockerfile에서 Go의 MINOR 리비전을 참조하고, 호환성 문제가 해결될 때까지 그 예외 사항을 문서화해야 할 수도 있습니다.

Dockerfile에서 참조되지 않으므로, Go의 MINOR 리비전은 프로젝트 체인지로그에 언급되지 않습니다.

변경 사항이 빌드와 관련되어 있고 체인지로그 항목이 필요 없는 경우에는 빌드 태그를 사용하는 것이 적절할 때가 있습니다. 예를 들어 Docker 이미지를 새 레지스트리 위치로 푸시하는 경우가 그렇습니다.

재빌드용 Git 태그#

분석기를 재빌드하기 위해 새 Git 태그를 생성할 때, 새 태그는 이전과 같은 MAJOR.MINOR.PATCH 버전을 유지하지만 (semver에서 정의한) BUILD 번호는 증가합니다.

예를 들어 분석기의 최신 릴리스가 v1.2.3이고 해당 Docker 이미지가 영향을 받는 Go 버전으로 빌드되었다면, 메인테이너는 이미지를 재빌드하기 위해 Git 태그 v1.2.3+1을 생성합니다. 최신 릴리스가 v1.2.3+1이라면 v1.2.3+2를 생성합니다.

빌드 번호는 이미지 태그에서 자동으로 제거됩니다. 예를 들어 gemnasium 프로젝트에서 Git 태그 v1.2.3+1을 생성하면 파이프라인이 이미지를 재빌드하고 gemnasium:1.2.3으로 푸시합니다.

재빌드를 위해 생성하는 Git 태그에는 새 빌드가 필요한 이유를 설명하는 간단한 메시지를 남깁니다. 예: Rebuild with Go 1.15.6. 이 태그에는 릴리스 노트가 없으며 릴리스도 생성되지 않습니다.

분석기를 재빌드하기 위한 새 Git 태그를 생성하려면 다음 단계를 따릅니다.

  1. 새 Git 태그를 생성하고 메시지를 입력합니다

    git tag -a v1.2.3+1 -m "Rebuild with Go 1.15.6"
    
  2. 태그를 리포지터리에 푸시합니다

    git push origin --tags
    
  3. Git 태그에 대한 새 파이프라인이 트리거되고 새 이미지가 빌드되어 태깅됩니다.

  4. 전체 테스트 스위트를 실행하고 새로 태깅된 이미지에 대한 새 취약점 리포트를 생성하려면 master 브랜치에 대해 새 파이프라인을 실행합니다. 위 3. 단계에서 트리거된 릴리스 파이프라인은 테스트의 일부만 실행하며, 예를 들어 container scanning 분석은 수행하지 않으므로 이 단계가 필요합니다.

월간 릴리스 프로세스#

이 작업은 매월 18일에 수행해야 합니다. 다만 이는 유연한 기한이므로 며칠 늦게 진행해도 문제되지 않습니다.

먼저 이 리포지터리의 스크립트로 릴리스용 새 이슈를 생성합니다. ./scripts/release_issue.rb MAJOR.MINOR 이 이슈는 전체 릴리스 프로세스를 안내합니다. 일반적으로 다음 작업을 수행해야 합니다.

의존성 업데이트#

분석기 소스 코드에서 사용하는 의존성과 (있는 경우) 업스트림 스캐너는 분석기 유형에 따라 다른 방식으로 업데이트됩니다.

Renovate를 사용한 SAST 자동 의존성 업데이트#

SAST는 Renovate GitLab Bot을 사용해 의존성 업데이트에 대한 머지 리퀘스트와 체인지로그 항목을 자동으로 생성합니다.

Renovate GitLab Bot으로 새 분석기의 자동 의존성 업데이트를 활성화하려면, SAST 분석기 추가에 나온 패턴을 따라 머지 리퀘스트를 제출해 분석기를 추가합니다.

체인지로그 자동 업데이트

의존성 업데이트가 포함된 머지 리퀘스트의 체인지로그 항목은 다음과 같이 자동으로 생성됩니다.

  1. 머지 리퀘스트를 생성하기 전에, Renovate GitLab Bot이 postUpgradeTasks에 나열된 명령을 실행합니다.

    1. postUpgradeTasks는 changelogParserCommand를 실행하며, 이는 changelog-parser 명령줄 도구를 실행합니다.

      changelog-parser 명령줄 도구는 {{MERGE_REQUEST_ID}} 자리표시자 텍스트가 포함된 새 마이너 체인지로그 항목을 자동으로 삽입합니다. 예를 들면 다음과 같습니다.

      ## v1.1.0
      - Update `report` module from `1.2.3` to `1.2.4` (!{{MERGE_REQUEST_ID}})
      
    2. Renovate GitLab Bot이 의존성 업데이트와 체인지로그 항목이 포함된 새 머지 리퀘스트를 생성합니다.

  2. 머지 리퀘스트에서 새 파이프라인이 트리거되며, 이 파이프라인은 analyzer.yml 템플릿에 포함된 update changelog mrid job을 실행합니다.

    update changelog mrid job은 {{MERGE_REQUEST_ID}} 자리표시자 텍스트를 실제 머지 리퀘스트 ID로 바꾸는 커밋을 생성합니다.

SastBot을 사용한 시크릿 탐지 자동 의존성 업데이트#

시크릿 탐지 팀은 파이프라인 기반 시크릿 탐지 분석기의 의존성 관리를 자동화하기 위해 내부 도구(SastBot)를 사용합니다. SastBot은 매월 8일에 MR을 생성하고, 리뷰를 진행할 팀원들에게 담당을 배분합니다. 프로세스에 대한 자세한 내용은 의존성 업데이트 자동화를 참고합니다.

SastBot은 job마다 서로 다른 액세스 토큰이 필요합니다. 예약된 파이프라인 job을 실행할 때 DEP_GITLAB_TOKEN 환경 변수를 사용해 토큰을 가져옵니다.

예약된 파이프라인 토큰 소스 권한 스코프 DEP_GITLAB_TOKEN 토큰 구성 위치 토큰 만료일
Merge Request Metadata Update security-products/analyzers 그룹 developer api Settings > CI/CI Variables 섹션(Masked, Protected, Hidden) Jul 25, 2026
Release Issue Creation security-products/release 프로젝트 planner api 예약된 파이프라인 job의 Configuration 섹션 Jul 28, 2026
Analyzers sast-bot 그룹 developer api 예약된 파이프라인 job의 Configuration 섹션 Jul 28, 2026

Sec 섹션 분석기 개발

GitLab v19.4
원문 보기

요약

분석기(analyzer)는 CI 파이프라인 환경에서 실행되도록 Docker 이미지로 제공됩니다. 분석기 전반에서 공통 동작과 인터페이스를 위해 공유하는 Go 모듈이 여러 개 있습니다. 분석기는 Docker 이미지로 제공됩니다.

분석기(analyzer)는 CI 파이프라인 환경에서 실행되도록 Docker 이미지로 제공됩니다. 이 가이드에서는 분석기 전반의 개발과 테스트 방법을 설명합니다.

공유 모듈#

분석기 전반에서 공통 동작과 인터페이스를 위해 공유하는 Go 모듈이 여러 개 있습니다.

  • command Go 패키지는 CLI 인터페이스를 구현합니다.
  • common 프로젝트는 로깅, 인증서 처리, 디렉터리 검색 기능을 위한 기타 공유 모듈을 제공합니다.
  • report Go 패키지의 Report·Finding 구조체는 JSON 리포트를 마샬링합니다.
  • template 프로젝트는 새 분석기의 스캐폴드를 생성합니다.

분석기 사용 방법#

분석기는 Docker 이미지로 제공됩니다. 예를 들어 Semgrep Docker 이미지를 실행해 작업 디렉터리를 스캔하는 방법은 다음과 같습니다.

  1. 스캔할 소스 코드가 있는 디렉터리로 cd 합니다.

  2. docker login registry.gitlab.com을 실행하고 사용자 이름과 개인 또는 프로젝트 액세스 토큰(read_registry 스코프 이상)을 입력합니다.

  3. Docker 이미지를 실행합니다.

    docker run \
        --interactive --tty --rm \
        --volume "$PWD":/tmp/app \
        --env CI_PROJECT_DIR=/tmp/app \
        -w /tmp/app \
        registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep:latest /analyzer run
    
  4. Docker 컨테이너는 마운트된 프로젝트 디렉터리에 분석기 카테고리에 해당하는 파일 이름으로 리포트를 생성합니다. 예를 들어 SAST는 gl-sast-report.json 이라는 파일을 생성합니다.

분석기 개발#

분석기를 업데이트하려면 다음을 수행합니다.

  1. Go 소스 코드를 수정합니다.
  2. 새 Docker 이미지를 빌드합니다.
  3. 테스트 프로젝트를 대상으로 분석기를 실행합니다.
  4. 생성된 리포트를 예상 결과와 비교합니다.

analyzer 라는 이름의 Docker 이미지를 생성하는 방법은 다음과 같습니다.

docker build -t analyzer .

예를 들어 시크릿 탐지를 테스트하려면 다음을 실행합니다.

wget https://gitlab.com/gitlab-org/security-products/ci-templates/-/raw/master/scripts/compare_reports.sh
sh ./compare_reports.sh sd test/fixtures/gl-secret-detection-report.json test/expect/gl-secret-detection-report.json \
| patch -Np1 test/expect/gl-secret-detection-report.json && git commit -m 'Update expectation' test/expect/gl-secret-detection-report.json
rm compare_reports.sh

직접 환경에서 바이너리를 컴파일해 로컬로 실행할 수도 있지만, 분석기의 런타임 의존성이 없기 때문에 analyze와 run은 대부분 동작하지 않습니다.

SpotBugs를 기반으로 한 예시는 다음과 같습니다.

go build -o analyzer
./analyzer search test/fixtures
./analyzer convert test/fixtures/app/spotbugsXml.Xml > ./gl-sast-report.json

Secure 스테이지 CI/CD 템플릿 및 컴포넌트#

Secure 스테이지는 다음 CI/CD 템플릿과 컴포넌트의 유지 관리를 담당합니다.

변경 사항은 항상 해당 그룹의 CI/CD 템플릿과 컴포넌트 양쪽에 모두 반영해야 하며, 최신 CI/CD 템플릿에도 적용해야 하는지 판단해야 합니다.

분석기는 오프라인 환경을 위한 Secure-Binaries.gitlab-ci.yml 파일에도 참조되어 있습니다. 변경 작업을 할 때는 이 파일도 함께 동기화되도록 합니다.

실행 기준#

SAST 활성화에는 GitLab CI/CD 구성에 사전 정의된 템플릿을 포함해야 합니다.

다음의 독립적인 기준에 따라 프로젝트에서 실행할 분석기가 결정됩니다.

  1. SAST 템플릿은 rules:exists를 사용해 특정 파일의 존재 여부로 실행할 분석기를 결정합니다. 예를 들어 Brakeman 분석기는 .rb 파일과 Gemfile 이 있을 때 실행됩니다.
  2. 각 분석기는 실제 분석을 수행하기 전에 사용자 정의가 가능한 매치 인터페이스를 실행합니다. 예를 들어 Flawfinder는 C/C++ 파일을 확인합니다.
  3. 범용 파일 확장자를 대상으로 실행되는 일부 분석기는 CI/CD 변수를 기준으로 확인합니다. 예를 들어 Kubernetes 매니페스트는 YAML로 작성되므로, Kubesec는 SCAN_KUBERNETES_MANIFESTS가 true로 설정된 경우에만 실행됩니다.

1단계는 프로젝트에 적합하지 않은 분석기를 실행하는 데 드는 컴퓨팅 할당량 낭비를 막는 데 도움이 됩니다. 다만 기술적 제약 때문에 대규모 프로젝트에는 사용할 수 없습니다. 따라서 2단계가 최종 확인 역할을 하여, 맞지 않는 분석기가 조기에 종료될 수 있도록 합니다.

분석기 테스트 방법#

의존성 스캐닝 분석기가 테스트 프로젝트를 사용해 분석기를 테스트할 때 다운스트림 파이프라인 기능을 어떻게 활용하는지 보여주는 영상입니다.

Sec 섹션이 GitLab의 다운스트림 파이프라인 기능을 활용해 분석기를 엔드투엔드로 테스트하는 방법

로컬 변경 사항 테스트#

분석기의 공유 모듈(command나 report 등)에서 로컬 변경 사항을 테스트하려면, 원격에 태그된 command 버전 대신 로컬 변경 사항이 적용된 command를 불러오도록 go mod replace 지시자를 사용할 수 있습니다. 예를 들면 다음과 같습니다.

go mod edit -replace gitlab.com/gitlab-org/security-products/analyzers/command/v3=/local/path/to/command

또는 go.mod 파일을 직접 수정해 같은 결과를 얻을 수도 있습니다.

module gitlab.com/gitlab-org/security-products/analyzers/awesome-analyzer/v2

replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /path/to/command

require (
    ...
    gitlab.com/gitlab-org/security-products/analyzers/command/v3 v2.19.0
)

Docker에서 로컬 변경 사항 테스트#

go.mod 파일의 replace를 Docker와 함께 사용하려면 다음을 수행합니다.

  1. command의 내용을 분석기 디렉터리로 복사합니다. cp -r /path/to/command path/to/analyzer/command.
  2. 분석기의 Dockerfile에 복사 문을 추가합니다. COPY command /command.
  3. 위 단계의 COPY 문 대상과 일치하도록 replace 문을 업데이트합니다. replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /command

컨테이너 오케스트레이션 호환성 테스트#

사용자는 컨테이너를 오케스트레이션하고 분석기를 실행하는 데 Docker가 아닌 containerd, Podman, skopeo 같은 다른 도구를 사용할 수도 있습니다. 이러한 도구와의 호환성을 보장하기 위해, 예약된 파이프라인으로 모든 분석기를 주기적으로 테스트합니다. 테스트가 실패하면 Slack 알림이 발생합니다.

분석기 Docker 이미지를 빌드할 때 호환성 문제를 피하려면, 기본 Docker 독점 미디어 유형 대신 OCI 미디어 유형을 사용합니다.

주기적 테스트 외에도, ci-templates 리포지터리 사용자를 위한 호환성도 보장합니다.

  1. ci-templates의 docker-test.yml 템플릿을 사용하는 분석기는 지원되는 Docker 도구에서 Docker 이미지가 올바르게 동작하는지 확인하기 위한 tests를 포함합니다.

    이 테스트는 머지 리퀘스트 파이프라인과 예약된 파이프라인에서 실행되며, 지원되는 Docker 도구를 손상시키는 이미지가 릴리스되지 않도록 막습니다.

  2. ci-templates의 docker.yml 템플릿은 분석기 이미지를 빌드할 때 docker buildx 명령에 oci-mediatypes=true를 지정합니다. 이렇게 하면 Docker 독점 미디어 유형이 아니라 OCI 미디어 유형을 사용해 이미지를 빌드합니다.

새 분석기를 만들거나 기존 분석기 이미지의 위치를 변경할 때는 주기적 테스트에 추가하거나, 자동화된 테스트가 포함된 공유 ci-templates 사용을 고려합니다.

분석기 스크립트#

analyzer-scripts 리포지터리에는 대부분의 분석기와 상호 작용할 때 사용할 수 있는 스크립트가 있습니다. 이 스크립트를 사용하면 GitLab CI와 유사한 환경에서 분석기를 빌드, 실행, 디버깅할 수 있으며, 분석기 변경 사항을 로컬에서 검증할 때 특히 유용합니다.

자세한 내용은 프로젝트 README를 참고합니다.

버전 관리 및 릴리스 프로세스#

GitLab Security Products는 GitLab의 MAJOR.MINOR와는 별개의 독립적인 버전 관리 체계를 사용합니다. 모든 제품은 시맨틱 버저닝의 변형을 사용하며 Docker 이미지로 제공됩니다.

Major는 주요 변경이 허용되는 GitLab의 새로운 메이저 릴리스마다 올라갑니다. Minor는 새 기능이 추가될 때 올라가고, Patch는 버그 수정용으로 예약되어 있습니다.

분석기는 다음 체계에 따라 Docker 이미지로 릴리스됩니다.

  • 기본 브랜치로의 모든 푸시는 edge 이미지 태그를 덮어씁니다
  • awesome-feature 브랜치로의 모든 푸시는 그에 대응하는 awesome-feature 이미지 태그를 생성합니다
  • 모든 Git 태그는 그에 대응하는 Major.Minor.Patch 이미지 태그를 생성합니다. 수동 job을 사용하면 해당 Major 및 latest 이미지 태그가 이 Major.Minor.Patch를 가리키도록 재정의할 수 있습니다.

대부분의 경우 최신 권고 사항이나 도구 패치가 자동으로 반영되는 MAJOR 이미지를 사용하는 것이 좋습니다. 포함된 CI 템플릿은 메이저 버전으로 고정되어 있지만, 필요하면 사용자가 버전을 직접 재정의할 수 있습니다.

새 분석기 Docker 이미지를 릴리스하는 방법에는 두 가지가 있습니다.

다음 다이어그램은 새 분석기 버전이 릴리스될 때 생성되는 Docker 태그를 보여줍니다.

Mermaid 다이어그램 (16줄)
소스 코드 보기
graph LR

A1[git tag v1.1.0]--> B1(run CI pipeline) B1 -->|build and tag patch| D1[1.1.0] B1 -->|tag minor| E1[1.1] B1 -->|retag major| F1[1] B1 -->|retag latest| G1[latest]

A2[git tag v1.1.1]--> B2(run CI pipeline) B2 -->|build and tag patch| D2[1.1.1] B2 -->|retag minor| E2[1.1] B2 -->|retag major| F2[1] B2 -->|retag latest| G2[latest]

A3[push to default branch]--> B3(run CI pipeline) B3 -->|build and tag edge| D3[edge]

지속적 배포(Continuous Deployment) 흐름에 따라, GitLab Rails 애플리케이션에 대응하는 항목이 없는 새 컴포넌트는 언제든 릴리스할 수 있습니다. 컴포넌트가 기존 애플리케이션에 통합되기 전까지는 표준 릴리스 사이클과 프로세스 때문에 반복 작업이 지연되어서는 안 됩니다.

수동 릴리스 프로세스#

  1. 새 분석기의 CHANGELOG.md 항목이 올바른지 확인합니다.
  2. 릴리스 소스(일반적으로 master 또는 main 브랜치)의 파이프라인이 통과했는지 확인합니다.
  3. 프로젝트 창 왼쪽의 Deployments 메뉴를 선택한 다음 Releases 하위 메뉴를 선택해 분석기 프로젝트의 새 릴리스를 생성합니다.
  4. New release를 선택해 New Release 페이지를 엽니다.
    1. Tag name 드롭다운에 CHANGELOG.md에서 사용한 것과 같은 버전(예: v2.4.2)을 입력하고, 태그를 생성하는 옵션(여기서는 Create tag v2.4.2)을 선택합니다.
    2. Release title 텍스트 박스에 위에서 사용한 것과 같은 버전(예: v2.4.2)을 입력합니다.
    3. Release notes 텍스트 박스에 CHANGELOG.md의 해당 버전 노트를 복사해 붙여넣습니다.
    4. 다른 설정은 모두 기본값으로 둡니다.
    5. Create release를 선택합니다.

위 과정을 따라 새 릴리스를 만들면, 위에서 지정한 Tag name으로 새 Git 태그가 생성됩니다. 이렇게 하면 해당 태그 버전으로 새 파이프라인이 트리거되고 새로운 분석기 Docker 이미지가 빌드됩니다.

분석기가 analyzer.yml 템플릿을 사용하는 경우, 위의 New release 과정에서 트리거된 파이프라인이 분석기 Docker 이미지의 새 버전을 자동으로 태깅하고 배포합니다.

분석기가 analyzer.yml 템플릿을 사용하지 않는 경우, 분석기 Docker 이미지의 새 버전을 수동으로 태깅하고 배포해야 합니다.

  1. 프로젝트 창 왼쪽의 CI/CD 메뉴를 선택한 다음 Pipelines 하위 메뉴를 선택합니다.
  2. 이전에 사용한 것과 같은 태그(예: v2.4.2)로 새 파이프라인이 현재 실행 중이어야 합니다.
  3. 파이프라인이 완료되면 blocked 상태가 됩니다.
  4. 창 오른쪽의 Manual job 재생 버튼을 선택하고 tag version을 선택해 분석기 Docker 이미지의 새 버전을 태깅 및 배포합니다.

Git 태그를 생성해 릴리스 job을 트리거할 시점은 각자의 판단에 따라 결정합니다. 판단하기 어려우면 다른 사람의 의견을 구합니다.

자동 릴리스 프로세스#

자동 릴리스 프로세스를 사용하기 전에 다음을 수행해야 합니다.

  1. CI/CD 환경 변수로 CREATE_GIT_TAG: true를 구성합니다.

  2. CI/CD 프로젝트 설정의 Variables를 확인합니다.

위 단계를 완료하면 자동 릴리스 프로세스는 다음과 같이 실행됩니다.

  1. 프로젝트 메인테이너가 MR을 기본 브랜치에 머지합니다.
  2. 기본 파이프라인이 트리거되고 upsert git tag job이 실행됩니다.
    • CHANGELOG.md의 최신 버전이 기존 Git 태그 중 하나와 일치하면 이 job은 아무 동작도 하지 않습니다.
    • 그렇지 않으면 이 job이 릴리스 API를 사용해 새 릴리스와 Git 태그를 자동으로 생성합니다. 버전과 메시지는 해당 프로젝트의 CHANGELOG.md 파일에서 가장 최근 항목을 사용합니다.
  3. 새 Git 태그에 대해 파이프라인이 자동으로 트리거됩니다. 이 파이프라인은 분석기의 latest, major, minor, patch Docker 이미지를 릴리스합니다.

자동 릴리스 프로세스에서 사용하는 서비스 계정#

키 값
계정 이름 @gl-service-dev-secure-analyzers-automation
용도 릴리스·태그 생성에 사용합니다
소속 gitlab-org/security-products
최대 권한 Developer
연결된 GITLAB_TOKEN의 스코프 api
GITLAB_TOKEN의 만료일 November 11, 2026
Warning

서비스 계정의 액세스 토큰 스코프나 GITLAB_TOKEN 변수 권한을 변경할 때는 반드시 섹션의 Slack 채널에 공지해야 합니다.

서비스 계정 토큰 교체#

@gl-service-dev-secure-analyzers-automation 서비스 계정의 GITLAB_TOKEN은 위에 표시된 Expiry Date 이전에 다음과 같이 교체해야 합니다.

  1. gl-service-dev-secure-analyzers-automation 사용자로 로그인합니다.

    이 계정의 자격 증명을 보유한 관리자 목록은 서비스 계정 액세스 요청에서 확인할 수 있습니다.

    관리자는 공유 GitLab 1password 볼트에서 로그인 자격 증명을 확인할 수 있습니다.

  2. gl-service-dev-secure-analyzers-automation 서비스 계정을 위해 api 스코프를 가진 새 개인 액세스 토큰을 생성합니다.

  3. 공유 GitLab 1password 볼트에서 GitLab API Token - gl-service-dev-secure-analyzers-automation 계정의 password 필드를 위의 2단계에서 생성한 새 개인 액세스 토큰으로 업데이트하고, Expires at 필드에 토큰 만료 시점을 설정합니다.

  4. 자동 릴리스 프로세스에서 사용하는 서비스 계정 표에서 GITLAB_TOKEN 필드의 만료일을 업데이트합니다.

  5. 다음 변수를 위의 2단계에서 생성한 새 개인 액세스 토큰으로 설정합니다.

    [!note] 다음 변수는 반드시 마스킹 및 숨김 처리해야 합니다.

    변수 프로젝트/그룹 이유
    GITLAB_TOKEN gitlab-org/security-products/analyzers gitlab-org/security-products/analyzers 네임스페이스 아래의 모든 프로젝트가 이 GITLAB_TOKEN 값을 상속받을 수 있게 합니다.
    gitlab-org/security-products/license-db 이 프로젝트/그룹은 gitlab-org/security-products/analyzers 네임스페이스 아래에 있지 않으므로 상속받지 못합니다. 따라서 GITLAB_TOKEN을 명시적으로 구성해야 합니다.
    gitlab-org/security-products/dependency-management
    gitlab-org/security-products/post-analyzers/tracking-calculator1
    gitlab-org/security-products/ci-templates2
    SEC_REGISTRY_PASSWORD gitlab-advanced-sast 이를 통해 태깅 스크립트가 개발 프로젝트의 프라이빗 컨테이너 레지스트리 registry.gitlab.com/gitlab-org/security-products/analyzers/<analyzer-name>/tmp에서 가져와, 공개 컨테이너 레지스트리 registry.gitlab.com/security-products/<analyzer-name>로 푸시할 수 있습니다.

    각주:

    1. 분석기 네임스페이스로 post-analyzer 프로젝트 이동(#582004)이 완료되면 이 프로젝트의 GITLAB_TOKEN 명시적 설정을 제거할 수 있습니다.
    2. ci-templates 프로젝트는 upsert git tag job이 새 릴리스를 생성할 수 있도록 GITLAB_TOKEN이 필요합니다.

교체가 필요한 다른 토큰#

토큰 프로젝트 만료일 비고
VERIFY_CI_TEMPLATE_TOKEN ci-templates January 22, 2027 verify ci templates job에서 사용합니다. CI/lint 엔드포인트에 JOB-TOKEN 액세스 허용(#438781)이 완료되면 이 변수의 명시적 설정을 제거할 수 있습니다.

분석기 릴리스 후 수행할 단계#

  1. 분석기 Docker 이미지의 새 버전이 태깅되고 배포된 후, 해당 테스트 프로젝트로 테스트합니다.

  2. 관련 그룹의 Slack 채널에 릴리스를 공지합니다. 메시지 예시:

    FYI I've just released ANALYZER_NAME ANALYZER_VERSION. LINK_TO_RELEASE

이미 푸시된 Git 태그는 Go 패키지 레지스트리에서 사용되거나 캐시되어 있을 가능성이 크므로, 절대로 삭제하지 않습니다.

긴급 수정이나 패치 백포팅#

이전 버전에 긴급 수정이나 패치를 백포팅하려면 다음 단계를 따릅니다.

  1. 수정 사항을 백포팅할 태그에서 새 브랜치를 생성합니다(브랜치가 없는 경우).
    • 예를 들어 최신 안정 태그가 v4이고 v3에 수정 사항을 백포팅한다면, v3라는 브랜치를 생성합니다.
  2. 방금 생성한 브랜치를 대상으로 머지 리퀘스트를 제출합니다.
  3. 승인되면 머지 리퀘스트를 해당 브랜치에 머지합니다.
  4. 해당 브랜치에 새 태그를 생성합니다.
  5. 분석기에 자동 릴리스 프로세스가 활성화되어 있으면 새 버전이 릴리스됩니다.
  6. 그렇지 않으면 수동 릴리스 프로세스를 따라 새 버전을 릴리스해야 합니다.
  7. 참고: 릴리스 파이프라인은 최신 edge 태그를 덮어쓰므로, 리그레션을 방지하려면 가장 최근 릴리스 파이프라인의 tag edge job을 다시 실행해야 할 수도 있습니다.

메이저 버전 릴리스를 위한 분석기 준비#

이 프로세스는 다음 그룹에 적용됩니다.

다른 그룹은 자체 메이저 버전 릴리스 프로세스를 문서화할 책임이 있습니다.

메이저 버전 릴리스에 주요 변경(breaking change)이 포함되는지에 따라 다음 시나리오 중 하나를 선택합니다.

  1. 주요 변경 없는 메이저 버전 릴리스
  2. 주요 변경이 있는 메이저 버전 릴리스

주요 변경 없는 메이저 버전 릴리스#

현재 분석기 릴리스가 v{N}이라고 가정합니다.

  1. 보호된 태그와 브랜치를 구성합니다.
  2. 메이저 릴리스 마일스톤 중 default 브랜치에 더 이상 머지할 변경 사항이 없을 때:
    1. default 브랜치에서 v{N} 브랜치를 생성합니다.

    2. default 브랜치에 CHANGELOG.md 파일의 다음 변경 사항만 담은 새 머지 리퀘스트를 생성하고 머지합니다.

      ## v{N+1}.0.0
      - Major version release (!<MR-ID>)
      
    3. 예약된 파이프라인을 구성합니다.

    4. CI/CD 템플릿과 컴포넌트의 분석기 메이저 버전을 올립니다

주요 변경이 있는 메이저 버전 릴리스#

현재 분석기 릴리스가 v{N}이라고 가정합니다.

  1. 보호된 태그와 브랜치를 구성합니다.

  2. 주요 변경 사항을 "스테이징"하기 위한 새 브랜치 v{N+1}을 생성합니다.

  3. 메이저 릴리스 마일스톤에 이르기까지의 마일스톤 동안:

    • 주요 변경이 아닌 사항은 default 브랜치(master 또는 main)에 머지합니다

    • 주요 변경 사항은 v{N+1} 브랜치에 머지하고, 변경마다 CHANGELOG.md 파일에 별도의 release candidate 항목을 생성합니다.

      ## v{N+1}.0.0-rc.0
      - some breaking change (!123)
      

      release candidates를 사용하면 모든 주요 변경을 한 번의 메이저 버전 상승으로 릴리스할 수 있으며, 이는 메이저 버전 업데이트에서만 주요 변경을 하라는 semver 가이드를 따르는 방식입니다.

  4. 메이저 릴리스 마일스톤 중 default 또는 v{N+1} 브랜치에 더 이상 머지할 변경 사항이 없을 때:

    1. default 브랜치에서 v{N} 브랜치를 생성합니다.

    2. v{N+1} 브랜치에 머지 리퀘스트를 생성해 모든 release candidate 체인지로그 항목을 v{N+1}에 대한 단일 항목으로 통합합니다.

      예를 들어 CHANGELOG.md에 버전 v{N+1}에 대한 다음 3개의 release candidate 항목이 있다면:

      ## v{N+1}.0.0-rc.2
      - yet another breaking change (!125)
      
      ## v{N+1}.0.0-rc.1
      - another breaking change (!124)
      
      ## v{N+1}.0.0-rc.0
      - some breaking change (!123)
      

      이때 새 머지 리퀘스트는 모든 release candidate 항목을 하나로 합쳐 v{N+1}에 대한 단일 메이저 릴리스 항목이 되도록 CHANGELOG.md를 업데이트해야 합니다.

      ## v{N+1}.0.0
      - yet another breaking change (!125)
      - another breaking change (!124)
      - some breaking change (!123)
      
    3. v{N+1} 브랜치의 모든 주요 변경 사항을 default 브랜치에 머지하는 머지 리퀘스트를 생성합니다.

    4. default 브랜치에 v{N+1} 브랜치의 모든 변경 사항이 반영되었으므로, 더 이상 필요 없는 v{N+1} 브랜치를 삭제합니다.

    5. 예약된 파이프라인을 구성합니다.

    6. CI/CD 템플릿과 컴포넌트의 분석기 메이저 버전을 올립니다.

보호된 태그와 브랜치 구성#
  1. 프로젝트에서 와일드카드 v*가 보호된 태그와 보호된 브랜치로 모두 설정되어 있는지 확인합니다.

  2. gl-service-dev-secure-analyzers-automation 서비스 계정이 보호된 태그를 Allowed to create 상태인지 확인합니다.

    자세한 내용은 공식 지원 이미지 절의 3.1 단계를 참고합니다.

예약된 파이프라인 구성#
  1. 세 개의 예약된 파이프라인이 있는지 확인하고, 없으면 생성한 다음 모두 PUBLISH_IMAGES: true로 설정합니다.
    • Republish images v{N}(v{N} 브랜치 대상)

      이 예약된 파이프라인은 새로 생성해야 합니다

    • Daily build(default 브랜치 대상)

      이 예약된 파이프라인은 이미 있어야 합니다

    • Republish images v{N-1}(v{N-1} 브랜치 대상)

      이 예약된 파이프라인은 이미 있어야 합니다

  2. 지원되는 이전 메이저 버전은 두 개까지이므로, v{N-2} 브랜치용 예약된 파이프라인이 있다면 삭제합니다.
CI/CD 템플릿과 컴포넌트의 분석기 메이저 버전 올리기#

모든 v{N+1} 분석기 이미지가 registry.gitlab.com/security-products/:에서 사용 가능해지면, 소속 그룹의 Secure 스테이지 CI/CD 템플릿 및 컴포넌트에서 각 분석기의 메이저 버전을 올리는 새 머지 리퀘스트를 생성합니다.

새 분석기 개발#

새로운 프레임워크와 도구를 지원하기 위해 새 분석기 프로젝트를 구축해야 할 때가 있습니다. 이때는 라이선스와 코드 표준을 포함한 엔지니어링 오픈소스 가이드라인을 따라야 합니다.

또한 GitLab 애플리케이션에 통합될 커스텀 분석기를 작성하려면 최소한의 기능 세트가 필요합니다.

체크리스트#

기반 도구에 다음 항목이 있는지 확인합니다.

Dockerfile#

Dockerfile은 GitLab이라는 이름의 비권한(unprivileged) 사용자를 사용해야 합니다. 이는 컨테이너를 관리자(root) 사용자로 실행할 수 없는 Red Hat OpenShift 인스턴스와의 호환성을 위해 필요합니다. 비권한 사용자로 컨테이너를 실행할 때는 몇 가지 제약을 고려해야 하는데, 예를 들어 Docker 파일 시스템에 기록해야 하는 모든 파일에는 GitLab 사용자에 맞는 권한이 필요합니다. 자세한 내용은 다음 머지 리퀘스트를 참고합니다. Docker 이미지에서 root 대신 GitLab 사용자 사용.

최소 취약점 데이터#

필수 필드의 전체 목록은 security-report-schemas를 참고합니다.

security-report-schema 리포지터리에는 각 리포트 유형별 필수 필드를 나열하는 JSON 스키마가 있습니다.

리포트 스키마와의 호환성#

GitLab에 아티팩트로 업로드된 보안 리포트는 수집되기 전에 검증됩니다.

보안 리포트 스키마는 SchemaVer(MODEL-REVISION-ADDITION)로 버전이 관리됩니다. Sec 섹션은 GitLab과 스키마 버전 간의 호환성을 포함해 security-report-schemas 프로젝트를 담당합니다. 스키마 변경은 제품 전반의 지원 종료 가이드라인을 따라야 합니다.

새 MODEL 버전이 도입되면, 새 스키마를 채택한 분석기는 이 새 스키마 버전을 포함하지 않은 GitLab 배포본에서도 보안 리포트를 오류나 경고 없이 계속 수집할 수 있도록 보장할 책임이 있습니다.

이는 여러 방식으로 구현할 수 있습니다.

  1. 분석기에 여러 스키마 버전 지원을 구현합니다. GitLab 버전에 따라 분석기는 GitLab이 지원하는 최신 스키마 버전으로 보안 리포트를 생성합니다.
    • 장점: 분석기가 런타임에 사용할 최적의 버전을 결정할 수 있습니다.
    • 단점: 구현 노력이 들고 복잡성이 늘어납니다.
  2. 새 분석기 메이저 버전을 릴리스합니다. 최신 MODEL 스키마 버전을 포함하지 않은 인스턴스는 MODEL-1 버전으로 리포트를 생성하는 분석기 버전을 계속 사용합니다.
    • 장점: 분석기 코드를 단순하게 유지합니다.
    • 단점: 유지 관리해야 할 분석기 버전이 늘어납니다.
  3. 새 스키마 사용을 지연시킵니다. 이 방식은 스키마에 없는 속성도 리포트에 포함할 수 있게 하는 additionalProperties=true를 사용합니다. 새 분석기 메이저 버전은 평소와 같은 주기로 릴리스됩니다.
    • 장점: 추가로 유지 관리할 분석기가 없고 분석기 코드가 단순하게 유지됩니다.
    • 단점: 스키마가 검증되지 않는 위험이 커지거나, 그 위험을 줄이기 위한 노력이 늘어납니다.

어떤 방식을 따라야 할지 확신이 없다면 security-report-schemas 메인테이너에게 문의합니다.

컨테이너 이미지 위치#

Secure 분석기의 컨테이너 이미지는 두 곳에 게시됩니다.

  • registry.gitlab.com/security-products 네임스페이스의 공식 지원 이미지. 예를 들면 다음과 같습니다.

    registry.gitlab.com/security-products/semgrep:5
    
  • 프로젝트 네임스페이스의 임시 개발 이미지. 예를 들면 다음과 같습니다.

    registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep/tmp:d27d44a9b33cacff0c54870a40515ec5f2698475
    

공식 지원 이미지#

Secure 템플릿에서 참조하는 공식 지원 이미지의 위치는 다음과 같습니다.

registry.gitlab.com/security-products/:

예를 들어 SAST.gitlab-ci.yml 템플릿의 semgrep-sast job은 컨테이너 이미지 registry.gitlab.com/security-products/semgrep:5를 참조합니다.

이 위치로 이미지를 푸시하려면 다음을 수행합니다.

  1. https://gitlab.com/security-products/에 새 프로젝트를 생성합니다.

    예: https://gitlab.com/security-products/semgrep

    이 프로젝트의 이미지는 registry.gitlab.com/security-products/:에 게시됩니다.

    예: registry.gitlab.com/security-products/semgrep:5

  2. https://gitlab.com/security-products/ 프로젝트를 다음과 같이 구성합니다.

    1. 다음 권한을 추가합니다.

    2. 다음 프로젝트 설정을 구성합니다.

      • Settings -> Packages and registries
        • Protected container image tags
          • 보호된 컨테이너 이미지 태그가 없는지 확인합니다. 설정에는 No container image tags are protected.로 표시되어야 합니다.

            이 설정의 근거에 대한 설명은 이 댓글을 참고합니다.

      • Settings -> General -> Visibility, project features, permissions
        • Project visibility
          • Public
        • Additional options
          • Users can request access
            • Disabled
        • Issues
          • Disabled
        • Repository
          • Only Project Members
          • Merge Requests
            • Disabled
          • Forks
            • Disabled
          • Git Large File Storage (LFS)
            • Disabled
          • CI/CD
            • Disabled
        • Container Registry
          • Everyone with access
        • Analytics, Requirements, Security and compliance, Wiki, Snippets, Package registry, Model experiments, Model registry, Pages, Monitor, Environments, Feature flags, Infrastructure, Releases, GitLab Duo
          • Disabled
  3. https://gitlab.com/gitlab-org/security-products/analyzers/에 있는 _분석기 프로젝트_에서 다음 옵션을 구성합니다.

    1. 와일드카드 v*를 보호된 태그로 추가합니다.

      gl-service-dev-secure-analyzers-automation 서비스 계정이 보호된 태그를 Allowed to create할 수 있는 계정 목록에 명시적으로 추가되어 있는지 확인합니다. 이는 upsert git tag job이 분석기 프로젝트의 새 릴리스를 생성할 수 있도록 하기 위해 필요합니다.

    2. 와일드카드 v*를 보호된 브랜치로 추가합니다.

    3. CI/CD 환경 변수

      [!note] SEC_REGISTRY_PASSWORD 변수는 반드시 마스킹 및 숨김 처리해야 합니다.

      키 값
      SEC_REGISTRY_IMAGE registry.gitlab.com/security-products/$CI_PROJECT_NAME
      SEC_REGISTRY_USER gl-service-dev-secure-analyzers-automation
      SEC_REGISTRY_PASSWORD gl-service-dev-secure-analyzers-automation 사용자의 개인 액세스 토큰입니다. 이 토큰 값 구성은 관리자에게 요청합니다.

      위 변수는 ci-templates 프로젝트의 tag_image.sh 스크립트가 컨테이너 이미지를 registry.gitlab.com/security-products/:에 푸시할 때 사용됩니다.

      예시는 semgrep CI/CD 변수를 참고합니다.

임시 개발 이미지#

임시 개발 이미지의 위치는 다음과 같습니다.

registry.gitlab.com/gitlab-org/security-products/analyzers//tmp:

예를 들어 semgrep 분석기의 개발 이미지 중 하나는 다음과 같습니다.

registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep/tmp:7580d6b037d93646774de601be5f39c46707bf04

컨테이너 레지스트리에 쓰기 액세스 권한을 가진 사람의 수를 제한하기 위해, https://gitlab.com/gitlab-org/security-products/analyzers/에 있는 프로젝트의 다음 프로젝트 기능 및 권한 설정을 구성해 개발 프로젝트의 컨테이너 레지스트리를 비공개로 전환해야 합니다.

  • Settings -> General -> Visibility, project features, permissions
    • Container Registry
      • Only Project Members

Sec 섹션의 각 그룹은 다음을 책임집니다.

  1. 자체 아티팩트의 지원 종료 및 제거 일정을 관리하고, 이를 위한 이슈를 생성합니다.
  2. 새 위치 아래에 프로젝트를 생성하고 구성합니다.
  3. 릴리스 아티팩트를 새 위치로 푸시하도록 빌드를 구성합니다.
  4. 각자의 지원 계약에 따라 기존 위치의 이미지를 제거하거나 유지합니다.

컨테이너 이미지 일일 재빌드#

분석기 이미지는 사용 중인 베이스 이미지 제공업체가 제공하는 패치를 자주 자동으로 반영하기 위해 매일 재빌드됩니다.

이 프로세스는 현재 MAJOR 릴리스에 해당하는 GitLab 버전에서 사용하는 이미지에만 적용됩니다. 매일 새 버전을 릴리스하려는 것이 아니라, 이미지의 각 활성 변형을 재빌드하고 해당 태그를 덮어쓰는 것이 목적입니다.

  • MAJOR.MINOR.PATCH 이미지 태그(예: 4.1.7)
  • MAJOR.MINOR 이미지 태그(예: 4.1)
  • MAJOR 이미지 태그(예: 4)
  • latest 이미지 태그

재빌드 프로세스의 구현은 프로젝트에 따라 다를 수 있지만, 이를 지원하기 위한 공유 CI 구성이 개발용 ci-templates 프로젝트에 있습니다.

GitLab Advanced SAST(GLAS)에 새 언어 지원 추가#

이 가이드는 엔지니어가 GLAS에 새 언어 지원을 평가하고 추가하는 데 도움을 줍니다. 이 가이드라인은 엄격한 요구 사항이 아니라, 언어 범위를 확장할 때 일관된 품질을 보장하기 위한 것입니다.

언어 지원 준비 기준#

분석기 품질 표준을 유지하면서 이 가이드라인을 각 언어의 특성에 맞게 조정합니다.

이 가이드라인은 GLAS에 PHP 지원을 추가한 경험(이슈 #514210 참고)에서 나온 것으로, 새 언어 지원이 프로덕션에 사용할 준비가 되었는지 판단하는 데 도움을 줍니다.

품질 준비도#

파일 간 분석 기능#
  • 대상 언어에서 가장 일반적인 의존성 관리 패턴을 지원합니다
  • 해당 언어 특유의 일반적인 포함(include) 메커니즘을 지원합니다
탐지 품질#
  • 지원되는 모든 CWE에서 정밀도(Precision Rate) 80% 이상
  • 지원되는 각 CWE에 대한 포괄적인 테스트 코퍼스
  • 해당 언어 생태계의 인기 프레임워크를 대상으로 테스트

커버리지 준비도#

우선순위 기반 커버리지#
  • 해당 언어와 관련된 치명적인 인젝션 취약점을 다뤄야 합니다
  • 흔히 발생하는 보안 설정 오류를 다뤄야 합니다
  • 업계 표준(OWASP Top 10, SANS CWE Top 25)에 부합해야 합니다
  • 해당 언어에서 흔히 발견되는 영향도가 큰 취약점에 집중합니다

지원 준비도#

문서화 요구 사항#
  • 지원 언어 문서에 해당 언어가 등재되고 설명되어 있습니다
  • CWE 커버리지 표에 새 언어 열이 업데이트되어 있습니다
  • 지원되는 모든 CWE가 올바르게 표시되어 있습니다
  • 알려진 제약 사항이 명확히 문서화되어 있습니다

성능 준비도#

표준 성능 기준#
  • 중간 규모 애플리케이션: 10분 미만
  • 매우 큰 애플리케이션: 멀티코어 옵션 사용 시 30분 미만
벤치마크 정의#
  • 벤치마킹에 사용할 대표 코드베이스를 정의합니다
  • 일반적인 프레임워크와 라이브러리를 포함합니다

Go의 보안 및 빌드 수정#

Go로 구현된 Secure 분석기의 Dockerfile은 MINOR 리비전이 아니라 Go의 MAJOR 릴리스를 참조해야 합니다. 이렇게 하면 분석기를 컴파일할 때 사용하는 Go 버전에 당시 사용 가능한 모든 보안 수정 사항이 포함됩니다. 예를 들어 분석기의 멀티스테이지 Dockerfile은 분석기 CLI를 빌드할 때 golang:1.15-alpine 이미지를 사용해야 하며, golang:1.15.4-alpine을 사용하면 안 됩니다.

Go의 MINOR 리비전이 릴리스되고 여기에 보안 수정 사항이 포함되어 있으면, 프로젝트 메인테이너는 Secure 분석기를 재빌드해야 하는지 확인해야 합니다. 빌드에 사용된 Go 버전은 해당 릴리스에 대응하는 build job의 로그에 나타나며, strings 명령으로 Go 바이너리에서 추출할 수도 있습니다.

분석기의 최신 이미지가 영향을 받는 Go 버전으로 빌드되었다면 재빌드해야 합니다. 이미지를 재빌드하려면 메인테이너는 다음 중 하나를 수행할 수 있습니다.

  • 안정 릴리스에 대응하는 Git 태그로 새 파이프라인을 트리거합니다
  • BUILD 번호를 올린 새 Git 태그를 생성합니다
  • PUBLISH_IMAGES 변수를 비어 있지 않은 값으로 설정하고 기본 브랜치에 대한 파이프라인을 트리거합니다

어느 방법을 사용하든 새 Docker 이미지가 빌드되며, 동일한 이미지 태그(MAJOR.MINOR.PATCH, MAJOR)로 게시됩니다.

이 워크플로는 같은 MAJOR 릴리스의 MINOR 리비전 간에 완전한 호환성이 있다고 가정합니다. 호환성 문제가 있으면 테스트 실행 시 프로젝트 파이프라인이 실패합니다. 이 경우 Dockerfile에서 Go의 MINOR 리비전을 참조하고, 호환성 문제가 해결될 때까지 그 예외 사항을 문서화해야 할 수도 있습니다.

Dockerfile에서 참조되지 않으므로, Go의 MINOR 리비전은 프로젝트 체인지로그에 언급되지 않습니다.

변경 사항이 빌드와 관련되어 있고 체인지로그 항목이 필요 없는 경우에는 빌드 태그를 사용하는 것이 적절할 때가 있습니다. 예를 들어 Docker 이미지를 새 레지스트리 위치로 푸시하는 경우가 그렇습니다.

재빌드용 Git 태그#

분석기를 재빌드하기 위해 새 Git 태그를 생성할 때, 새 태그는 이전과 같은 MAJOR.MINOR.PATCH 버전을 유지하지만 (semver에서 정의한) BUILD 번호는 증가합니다.

예를 들어 분석기의 최신 릴리스가 v1.2.3이고 해당 Docker 이미지가 영향을 받는 Go 버전으로 빌드되었다면, 메인테이너는 이미지를 재빌드하기 위해 Git 태그 v1.2.3+1을 생성합니다. 최신 릴리스가 v1.2.3+1이라면 v1.2.3+2를 생성합니다.

빌드 번호는 이미지 태그에서 자동으로 제거됩니다. 예를 들어 gemnasium 프로젝트에서 Git 태그 v1.2.3+1을 생성하면 파이프라인이 이미지를 재빌드하고 gemnasium:1.2.3으로 푸시합니다.

재빌드를 위해 생성하는 Git 태그에는 새 빌드가 필요한 이유를 설명하는 간단한 메시지를 남깁니다. 예: Rebuild with Go 1.15.6. 이 태그에는 릴리스 노트가 없으며 릴리스도 생성되지 않습니다.

분석기를 재빌드하기 위한 새 Git 태그를 생성하려면 다음 단계를 따릅니다.

  1. 새 Git 태그를 생성하고 메시지를 입력합니다

    git tag -a v1.2.3+1 -m "Rebuild with Go 1.15.6"
    
  2. 태그를 리포지터리에 푸시합니다

    git push origin --tags
    
  3. Git 태그에 대한 새 파이프라인이 트리거되고 새 이미지가 빌드되어 태깅됩니다.

  4. 전체 테스트 스위트를 실행하고 새로 태깅된 이미지에 대한 새 취약점 리포트를 생성하려면 master 브랜치에 대해 새 파이프라인을 실행합니다. 위 3. 단계에서 트리거된 릴리스 파이프라인은 테스트의 일부만 실행하며, 예를 들어 container scanning 분석은 수행하지 않으므로 이 단계가 필요합니다.

월간 릴리스 프로세스#

이 작업은 매월 18일에 수행해야 합니다. 다만 이는 유연한 기한이므로 며칠 늦게 진행해도 문제되지 않습니다.

먼저 이 리포지터리의 스크립트로 릴리스용 새 이슈를 생성합니다. ./scripts/release_issue.rb MAJOR.MINOR 이 이슈는 전체 릴리스 프로세스를 안내합니다. 일반적으로 다음 작업을 수행해야 합니다.

의존성 업데이트#

분석기 소스 코드에서 사용하는 의존성과 (있는 경우) 업스트림 스캐너는 분석기 유형에 따라 다른 방식으로 업데이트됩니다.

Renovate를 사용한 SAST 자동 의존성 업데이트#

SAST는 Renovate GitLab Bot을 사용해 의존성 업데이트에 대한 머지 리퀘스트와 체인지로그 항목을 자동으로 생성합니다.

Renovate GitLab Bot으로 새 분석기의 자동 의존성 업데이트를 활성화하려면, SAST 분석기 추가에 나온 패턴을 따라 머지 리퀘스트를 제출해 분석기를 추가합니다.

체인지로그 자동 업데이트

의존성 업데이트가 포함된 머지 리퀘스트의 체인지로그 항목은 다음과 같이 자동으로 생성됩니다.

  1. 머지 리퀘스트를 생성하기 전에, Renovate GitLab Bot이 postUpgradeTasks에 나열된 명령을 실행합니다.

    1. postUpgradeTasks는 changelogParserCommand를 실행하며, 이는 changelog-parser 명령줄 도구를 실행합니다.

      changelog-parser 명령줄 도구는 {{MERGE_REQUEST_ID}} 자리표시자 텍스트가 포함된 새 마이너 체인지로그 항목을 자동으로 삽입합니다. 예를 들면 다음과 같습니다.

      ## v1.1.0
      - Update `report` module from `1.2.3` to `1.2.4` (!{{MERGE_REQUEST_ID}})
      
    2. Renovate GitLab Bot이 의존성 업데이트와 체인지로그 항목이 포함된 새 머지 리퀘스트를 생성합니다.

  2. 머지 리퀘스트에서 새 파이프라인이 트리거되며, 이 파이프라인은 analyzer.yml 템플릿에 포함된 update changelog mrid job을 실행합니다.

    update changelog mrid job은 {{MERGE_REQUEST_ID}} 자리표시자 텍스트를 실제 머지 리퀘스트 ID로 바꾸는 커밋을 생성합니다.

SastBot을 사용한 시크릿 탐지 자동 의존성 업데이트#

시크릿 탐지 팀은 파이프라인 기반 시크릿 탐지 분석기의 의존성 관리를 자동화하기 위해 내부 도구(SastBot)를 사용합니다. SastBot은 매월 8일에 MR을 생성하고, 리뷰를 진행할 팀원들에게 담당을 배분합니다. 프로세스에 대한 자세한 내용은 의존성 업데이트 자동화를 참고합니다.

SastBot은 job마다 서로 다른 액세스 토큰이 필요합니다. 예약된 파이프라인 job을 실행할 때 DEP_GITLAB_TOKEN 환경 변수를 사용해 토큰을 가져옵니다.

예약된 파이프라인 토큰 소스 권한 스코프 DEP_GITLAB_TOKEN 토큰 구성 위치 토큰 만료일
Merge Request Metadata Update security-products/analyzers 그룹 developer api Settings > CI/CI Variables 섹션(Masked, Protected, Hidden) Jul 25, 2026
Release Issue Creation security-products/release 프로젝트 planner api 예약된 파이프라인 job의 Configuration 섹션 Jul 28, 2026
Analyzers sast-bot 그룹 developer api 예약된 파이프라인 job의 Configuration 섹션 Jul 28, 2026