Sec 섹션 분석기 개발

분석기는 CI 파이프라인 컨텍스트 내에서 실행되는 도커 이미지로 제공됩니다. 이 가이드에서는 분석기 간의 개발과 테스트 관행을 설명합니다.

공유 모듈

여러 분석기 간의 공통 동작 및 인터페이스를 위해 공유하는 Go 모듈이 있습니다.

  • command Go 패키지는 CLI 인터페이스를 구현합니다.
  • common 프로젝트는 로깅, 인증서 처리, 디렉터리 검색 기능을 위한 여러 공유 모듈을 제공합니다.
  • report Go 패키지의 ReportFinding 구조체는 JSON 보고서를 marshal합니다.
  • template 프로젝트는 새로운 분석기를 위한 템플릿을 구성합니다.

분석기 사용 방법

분석기는 도커 이미지로 제공됩니다. 예를 들어, 작업 디렉터리를 스캔하는 Semgrep 도커 이미지를 실행하려면 다음을 실행하세요.

  1. 스캔하려는 소스 코드의 디렉터리로 이동합니다.
  2. docker login registry.gitlab.com을 실행하고 사용자 이름과 적어도 read_registry 스코프를 갖는 개인 또는 프로젝트 액세스 토큰을 제공합니다.
  3. 도커 이미지를 실행합니다:

    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. 도커 컨테이너는 분석기 카테고리에 해당하는 보고서 파일을 마운트된 프로젝트 디렉터리에 생성합니다. 예를 들어, SASTgl-sast-report.json이라는 파일을 생성합니다.

분석기 개발

분석기를 업데이트하려면:

  1. Go 소스 코드를 수정합니다.
  2. 새로운 도커 이미지를 빌드합니다.
  3. 분석기를 해당 테스트 프로젝트에 대상으로 실행합니다.
  4. 생성된 보고서를 기대치와 비교합니다.

다음은 analyzer라는 도커 이미지를 만드는 방법입니다:

docker build -t analyzer .

예를 들어, Secret Detection을 테스트하려면 다음을 실행하세요.

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

또는 자체 환경을 위해 이진 파일을 컴파일하여 로컬에서 실행할 수도 있지만, 분석기의 런타임 의존성이 없으므로 analyzerun이 작동하지 않을 것입니다.

다음은 SpotBugs를 기반으로 한 예제입니다.

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

실행 기준

SAST를 활성화하려면 GitLab CI/CD 구성에 미리 정의된 템플릿을 포함해야 합니다.

프로젝트에서 실행할 분석기를 결정하는 다음과 같은 독립 기준이 있습니다.

  1. SAST 템플릿은 특정 파일의 존재 여부에 따라 실행할 분석기를 결정하기 위해 rules:exists를 사용합니다. 예를 들어, Brakeman 분석기는 .rb 파일 및 Gemfile이 있을 때 실행됩니다.
  2. 각 분석기는 실제 분석을 수행하기 전에 사용자 정의 match 인터페이스를 실행합니다. 예를 들어, Flawfinder는 C/C++ 파일의 유무를 확인합니다.
  3. 일부 분석기는 일반적인 파일 확장자에 대해 CI/CD 변수를 기반으로 확인을 수행합니다. 예를 들어, 쿠버네티스 매니페스트는 YAML로 작성되므로 SCAN_KUBERNETES_MANIFESTS가 true로 설정되어 있을 때만 Kubesec가 실행됩니다.

단계 1은 프로젝트와 어울리지 않는 분석기 실행을 방지합니다. 그러나 기술적인 제한으로 인해 대규모 프로젝트에는 사용할 수 없습니다. 따라서 단계 2는 불일치하는 분석기가 조기에 종료되도록 하는 최종 확인 역할을 합니다.

분석기 테스트 방법

의존성 스캔 분석기가 테스트 프로젝트를 사용하여 분석기를 테스트하기 위해 다운스트림 파이프라인 기능을 활용하는 영상 안내:

Sec가 GitLab의 다운스트림 파이프라인 기능을 활용하여 분석기를 끝까지 테스트하는 방법

로컬 변경사항 테스트

분석기에 대한 공유 모듈(예: command 또는 report)의 로컬 변경사항을 테스트하려면 go mod replace 지시문을 사용하여 원격으로 태그된 버전이 아닌 로컬 변경사항이 적용된 command를 로드할 수 있습니다. 예를 들면 다음과 같습니다.

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
)

도커에서 로컬 변경사항 테스트

go.mod 파일에서 replace를 사용하여 도커에서 로컬 변경사항을 테스트하려면:

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

분석기 스크립트

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

자세한 정보는 프로젝트 README를 참조하세요.

버전 및 릴리스 프로세스

GitLab 보안 제품은 GitLab Rails의 MAJOR.MINOR와는 독립적인 버전 관리 시스템을 사용합니다. 모든 제품은 Semantic Versioning의 변형을 사용하며 Docker 이미지로 제공됩니다.

Patch 버전 업데이트는 일반적으로 기본 도구의 Minor 버전 업데이트와 해당되는데, 이를 통해 스캐너에 대한 중요한 변경 사항에 대한 Minor 버전을 더 유연하게 보존할 수 있습니다. 스캐너의 변경으로 인한 중단되는 변화의 경우, 별도의 리포지터리에서 새 분석기를 생성해야 합니다.

분석기는 다음 방식으로 Docker 이미지로 릴리스됩니다:

  • 기본 브랜치로의 각 푸시는 edge 이미지 태그를 덮어씁니다.
  • awesome-feature 브랜치로의 각 푸시는 해당하는 awesome-feature 이미지 태그를 생성합니다.
  • 각 Git 태그는 해당하는 Major.Minor.Patch 이미지 태그를 생성합니다. 매뉴얼 작업을 통해 해당 Majorlatest 이미지 태그를 이 Major.Minor.Patch로 지정할 수 있습니다.

대부분의 경우에는 최신 경고 또는 도구의 패치로 자동으로 유지되는 MAJOR 이미지를 사용하는 것이 좋습니다. 포함된 CI 템플릿은 주 버전에 고정되어 있지만, 사용자는 원하는 경우 직접 버전을 재정의할 수 있습니다.

새 분석기 Docker 이미지를 릴리스하려면 두 가지 옵션이 있습니다:

다음 다이어그램은 새 분석기 버전을 릴리스할 때 생성되는 Docker 태그를 설명합니다:

graph LR A1[git tag v1.1.0]--> B1(CI 파이프라인 실행) B1 -->|패치 빌드 및 태그| D1[1.1.0] B1 -->|마이너 태그| E1[1.1] B1 -->|메이저 재태깅| F1[1] B1 -->|최신 재태깅| G1[latest] A2[git tag v1.1.1]--> B2(CI 파이프라인 실행) B2 -->|패치 빌드 및 태그| D2[1.1.1] B2 -->|마이너 재태깅| E2[1.1] B2 -->|메이저 재태깅| F2[1] B2 -->|최신 재태깅| G2[latest] A3[기본 브랜치에 푸시]--> B3(CI 파이프라인 실행) B3 -->|에지 빌드 및 태그| D3[edge]

지속적인 배포 흐름에 따라, 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을 사용하여 새 파이프라인이 트리거되고 새 분석기 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 이미지를 태그하고 배포합니다.

태그를 만들어 릴리스 작업을 트리거할 때 언제 만들어야 하는지를 결정하기 위해 최선의 판단을 행할 수 있습니다. 결정을 내릴 수 없는 경우, 다른 사람의 의견을 물어보세요.

자동 릴리스 프로세스

자동 릴리스 프로세스를 사용하려면 다음 작업을 수행해야 합니다:

  1. CI/CD 환경 변수CREATE_GIT_TAG: true를 구성합니다.
  2. CI/CD 프로젝트 설정의 Variables를 확인합니다. 프로젝트가 이미 프로젝트 그룹으로부터 GITLAB_TOKEN 환경 변수를 상속받지 않은 경우, complete read/write access to the API를 가진 프로젝트 액세스 토큰을 만들고, 이 토큰을 참조하도록 GITLAB_TOKENCI/CD 환경 변수로 구성합니다.

위 단계를 완료한 후, 자동 릴리스 프로세스는 다음과 같이 실행됩니다:

  1. 프로젝트 유지 관리자가 MR을 기본 브랜치로 Merge합니다.
  2. 기본 파이프라인이 트리거되고 upsert git tag 작업이 실행됩니다.
    • 만약 CHANGELOG.md의 가장 최근 버전이 Git 태그 중 하나와 일치하는 경우, 해당 작업은 무시됩니다.
    • 그렇지 않은 경우, 해당 작업은 릴리스 API를 사용하여 최근 CHANGELOG.md 파일에 대한 버전 및 메시지를 자동으로 사용하여 새 릴리스 및 Git 태그를 생성합니다.
  3. 새 Git 태그의 파이프라인이 자동으로 트리거됩니다. 이 파이프라인은 분석기의 latest, major, minorpatch Docker 이미지를 릴리스합니다.

분석기를 릴리스한 후 수행해야 할 단계

  1. 분석기 Docker 이미지의 새 버전이 태그되고 배포된 후 해당 테스트 프로젝트에서 테스트합니다.
  2. 해당 그룹 Slack 채널에 릴리스를 알립니다. 예시 메시지:

    FYI 새로운 버전의 ANALYZER_NAME ANALYZER_VERSION를 릴리스했습니다. LINK_TO_RELEASE

한 번 푸시된 Git 태그는 삭제하지 마십시오. 해당 태그가 Go 패키지 레지스트리에서 사용되거나/또는 캐시될 가능성이 매우 높습니다.

새로운 분석기 개발

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

또한, GitLab 응용 프로그램에 통합될 커스텀 분석기를 작성하려면 최소한의 기능 세트가 필요합니다:

체크리스트

다음 사항을 확인하세요:

  • 허용되는 소프트웨어 라이선스가 있는지 여부.
  • Headless 실행 (CLI 도구).
  • Docker 이미지로 패키지화할 수 있는 의존성 번들.
  • Linux 또는 Windows Docker 실행기를 사용하여 실행할 수 있는 호환 프로젝트 (파일명 또는 확장자를 기준으로 감지).
  • 오프라인 실행 (인터넷 접근 불가) 또는 사용자 정의 프록시 및/또는 CA 인증서를 사용하도록 구성할 수 있는지 여부.

Dockerfile

Dockerfile은 관리자(루트) 사용자로 컨테이너를 실행할 수 없는 Red Hat OpenShift 인스턴스와 호환성을 제공하기 위해 GitLab이라는 이름의 비권한 사용자를 사용해야 합니다. 관리자 권한이 없는 사용자로 컨테이너를 실행할 때 고려해야 할 일부 제한 사항이 있습니다. 예를 들면 Docker 파일 시스템에 쓰여져야 하는 파일은 GitLab 사용자의 적절한 권한이 필요합니다. 자세한 내용은 다음 Merge Request을 참조하세요: Docker 이미지에서 루트 대신 GitLab 사용자 사용.

최소한의 취약점 데이터

모든 필수 필드의 전체 디렉터리을 확인하려면 우리의 보안 보고서 스키마를 참조하세요.

보안 보고서 스키마 리포지터리에는 각 보고서 유형에 대한 필수 필드가 나열된 JSON 스키마가 포함되어 있습니다:

컨테이너 이미지 위치

컨테이너 레지스트리에 쓰기 액세스 권한이있는 사람 수를 제한하기 위해서, 모든 이미지는 아래 위치에 게시되어야합니다.

  • 그룹: https://gitlab.com/security-products/
  • 프로젝트 경로: https://gitlab.com/security-products/<이름> (예시)
  • 레지스트리 주소: registry.gitlab.com/security-products/<이름>[/<이미지_이름>]:[태그]
  • 권한
  • 프로젝트 설정
    • 가시성, 프로젝트 기능, 권한.
      • 프로젝트 가시성: 공개. “사용자가 액세스 요청을 할 수 없도록” 선택 해제.
      • 이슈: 비활성화.
      • 리포지터리: “프로젝트 멤버만”으로 설정. 비활성화: Merge Request, 포크, Git LFS, 패키지, CI/CD.
      • 나머지 항목 비활성화: 분석, 요구사항, 위키, 스니펫, 페이지, 작업.
    • 서비스 데스크: 비활성화

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

  1. 자신들의 아티팩트에 대한 폐기 및 제거 일정을 관리하고 이를 위한 이슈를 생성.
  2. 새 위치에 프로젝트를 생성하고 구성.
  3. 릴리스 아티팩트를 새로운 위치로 푸시하기 위해 빌드 구성.
  4. 지원 계약에 따라 이전 위치에 존재하는 이미지를 유지하거나 제거.

컨테이너 이미지의 매일 재빌드

분석기 이미지는 매일 다시 빌드되어, 의존하는 기본 이미지 공급 업체가 제공하는 패치를 자주 자동으로 가져올 수 있도록 합니다.

이 프로세스는 현재 메이저 릴리스와 일치하는 GitLab 버전에서 사용되는 이미지에만 적용됩니다. 매일 새로운 버전을 릴리스하는 것이 아니라, 각 활성화 된 변형별로 이미지를 다시 빌드하고 해당 태그를 덮어쓰는 것이 목적입니다:

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

재빌드 프로세스의 구현은 프로젝트에 따라 다를 수 있지만, 이를 달성하기 위한 공유 CI 구성은 개발 CI 템플릿 프로젝트에서 사용할 수 있습니다.

Go 언어의 보안 및 빌드 수정

Go로 구현된 보안 분석기의 DockerfileMAJOR 릴리스의 Go를 참조해야하며, MINOR 리비전을 참조해서는 안됩니다. 이를 통해 분석기를 컴파일하는 데 사용되는 Go 버전이 특정 시점에 사용 가능한 모든 보안 수정 사항을 포함함을 보장합니다. 예를 들어, 분석기의 멀티 스테이지 Dockerfile은 분석기 CLI를 빌드하기 위해 golang:1.15-alpine 이미지를 사용해야 하며 golang:1.15.4-alpine을 사용해서는 안됩니다.

Go의 MINOR 리비전이 출시되고 보안 수정 사항이 포함되어있는 경우, 프로젝트 유지 관리자는 보안 분석기가 다시 빌드해야 하는지 확인해야 합니다. 빌드에 사용된 Go 버전은 안정 릴리즈에 해당하는 build 작업 로그에서 확인할 수 있으며 strings 명령을 사용하여 Go 바이너리에서 추출할 수도 있습니다.

만약 분석기의 최신 이미지가 해당하는 버전의 Go로 빌드된 경우, 다시 빌드해야 합니다. 이미지를 다시 빌드하려면 유지 관리자는 다음 중 하나를 수행할 수 있습니다:

  • 안정 릴리즈에 해당하는 Git 태그에 대한 새 파이프라인 트리거
  • 빌드 번호가 증가된 새로운 Git 태그 생성
  • 기본 브랜치에 대한 파이프라인 트리거 및 PUBLISH_IMAGES 변수를 비어 있지 않은 값으로 설정

어느 방법이든 새로운 도커 이미지가 빌드되며, 해당 이미지 태그인 MAJOR.MINOR.PATCHMAJOR로 게시됩니다:

이 작업 흐름은 동일한 MAJOR 릴리스의 MINOR 리비전간의 전체 호환성을 가정합니다. 호환성 문제가 있는 경우 프로젝트 파이프라인은 테스트를 실행할 때 실패합니다. 이 경우 Dockerfile에서 MINOR 리비전을 참조하고 호환성 문제가 해결될 때까지 해당 예외 사항을 문서화하는 것이 필요할 수 있습니다.

Dockerfile에 참조되지 않아도, MINOR 리비전의 Go는 프로젝트 변경 로그에 언급되지 않습니다.

때로는 변경 사항이 빌드와 관련되므로 변경 로그 항목이 필요없는 빌드 태그를 사용하는 것이 타당한 상황일 수 있습니다. 예를 들어, Docker 이미지를 새 레지스트리 위치로 푸시하는 경우.

Git 태그를 다시 빌드하려면

분석기를 다시 빌드하기 위해 새로운 Git 태그를 만들 때, 새 태그는 이전과 동일한 MAJOR.MINOR.PATCH 버전을 가지지만 BUILD 번호(정의된 대로 semver에서)가 증가합니다.

예를 들어, 분석기의 최신 릴리스가 v1.2.3이고 해당 도커 이미지가 영향을 받는 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 태그에는 새 빌드가 필요한 이유를 설명하는 간단한 메시지가 있습니다. 예시: Go 1.15.6으로 다시 빌드. 해당 태그에는 릴리스 노트가 없으며, 릴리스가 생성되지 않습니다.

분석기를 다시 빌드하기 위해 새로운 Git 태그를 만들려면 다음 단계를 따르세요:

  1. 새로운 Git 태그를 만들고 메시지를 제공합니다

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

    git push origin --tags
    
  3. Git 태그를 위한 새로운 파이프라인이 트리거되고 새 이미지가 빌드되어 태깅됩니다.
  4. 새로운 이미지에 대해 전체 테스트 스위트를 실행하고 새로운 취약점 보고서를 생성하기 위해 master 브랜치의 새 파이프라인을 실행하세요. 위 단계 3.에서 트리거된 릴리스 파이프라인은 일부 테스트만 실행하므로 이 과정이 필요합니다. 예를 들어 컨테이너 스캐닝 분석을 수행하지 않습니다.

월간 릴리스 프로세스

이는 매월 18일에 수행되어야 합니다. 그러나 이는 유연한 마감일이며 며칠 후에도 수행해도 문제가 없습니다.

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

의존성 업데이트

분석기 소스에 사용된 모든 의존성 및 상위 스캐너(있는 경우)는 주로 보안 수정 및 호환되는 변경 사항이 포함된 월간 주기로 업데이트됩니다.

  • Static Analysis 팀은 모든 SAST 분석기의 의존성 관리를 자동화하기 위해 사용자 정의 내부 도구(SastBot)를 사용합니다. SastBot은 매월 8일에 MR을 생성하고 이를 정적 분석 팀원들에게 리뷰를 진행하기 위해 할당합니다. 프로세스에 대한 자세한 내용은 의존성 업데이트 자동화를 참조하세요.