컴플라이언스 파이프라인

Tier: Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated
  • GitLab 13.9에서 소개되었으며, ff_evaluate_group_level_compliance_pipeline 기능 플래그로 비활성화되었습니다.
  • GitLab 13.11에서 기본으로 활성화되었습니다.
  • GitLab 14.2에서 기능 플래그가 제거되었습니다.

그룹 소유자는 컴플라이언스 파이프라인을 기타 프로젝트와 별도로 구성할 수 있습니다. 기본적으로 컴플라이언스 파이프라인 구성(예: .compliance-gitlab-ci.yml)은 레이블이 지정된 프로젝트의 파이프라인 구성(예: .gitlab-ci.yml)보다 먼저 실행됩니다.

그러나 컴플라이언스 파이프라인 구성은 레이블이 지정된 프로젝트의 .gitlab-ci.yml 파일을 참조할 수 있어야 합니다. 이렇게 하면:

  • 컴플라이언스 파이프라인은 레이블이 지정된 프로젝트 파이프라인의 작업도 실행할 수 있습니다. 이를 통해 파이프라인 구성을 중앙에서 제어할 수 있습니다.
  • 컴플라이언스 파이프라인에 정의된 작업과 변수는 레이블이 지정된 프로젝트의 .gitlab-ci.yml 파일의 변수에 의해 변경되지 않습니다.

:: 주의: :: 알려진 문제로 인해 프로젝트 파이프라인은 컴플라이언스 파이프라인 구성의 상단에 먼저 포함되어야 합니다. 이렇게 함으로써 프로젝트가 하향적으로 설정을 덮어쓰는 것을 방지할 수 있습니다.

자세한 정보는 다음을 참조하세요:

레이블이 지정된 프로젝트에 미치는 영향

사용자는 컴플라이언스 파이프라인이 구성되었는지 알 방법이 없으며, 자신의 파이프라인이 전혀 실행되지 않거나 스스로 정의하지 않은 작업이 포함된 이유에 혼란스러울 수 있습니다.

레이블이 지정된 프로젝트에서 파이프라인을 작성할 때, 컴플라이언스 파이프라인이 구성되었는지 여부를 나타내는 표시가 없습니다. 프로젝트 수준에서의 유일한 표시물은 컴플라이언스 프레임워크 레이블 그 자체이지만, 레이블이 지정된 프레임워크에 컴플라이언스 파이프라인이 구성되었는지 여부는 나타내지 않습니다.

그러므로 불확실성과 혼란을 줄이기 위해 프로젝트 사용자에게 컴플라이언스 파이프라인 구성에 대해 알리세요.

컴플라이언스 파이프라인 구성하기

컴플라이언스 파이프라인을 구성하려면 다음 단계를 따르세요:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 그룹을 찾으세요.
  2. 설정 > 일반을 선택하세요.
  3. 컴플라이언스 프레임워크 섹션을 확장하세요.
  4. 컴플라이언스 파이프라인 구성 (선택 사항) 에 컴플라이언스 프레임워크 구성 경로를 추가하세요. 이때 path/file.y[a]ml@group-name/project-name 형식을 사용합니다. 예:

    • .compliance-ci.yml@gitlab-org/gitlab.
    • .compliance-ci.yaml@gitlab-org/gitlab.

이 구성은 컴플라이언스 프레임워크 레이블이 적용된 프로젝트에서 상속됩니다. 해당 프레임워크 레이블이 적용된 프로젝트에서는 레이블이 지정된 프로젝트의 파이프라인 구성 대신 컴플라이언스 파이프라인 구성이 실행됩니다.

레이블이 지정된 프로젝트에서 파이프라인을 실행하는 사용자는 최소한 컴플라이언스 프로젝트에서 리포터 역할을 가져야 합니다.

스캔 실행을 강제하는 데 사용될 때, 이 기능은 스캔 실행 정책과 겹치는 부분이 있습니다. 이 두 가지 기능에 대한 사용자 경험을 통합하지는 않았습니다. 이러한 기능 간의 유사점 및 차이점에 대한 자세한 내용은 스캔 실행 강제화를 참조하세요.

예제 구성

다음 예제 .compliance-gitlab-ci.yml은 레이블이 지정된 프로젝트 파이프라인 구성도 실행되도록 include 키워드를 포함합니다.

include:  # 프로젝트에 .gitlab-ci.yml이 포함되어 있으면 개별 프로젝트 구성 실행
  - project: '$CI_PROJECT_PATH'
    file: '$CI_CONFIG_PATH'
    ref: '$CI_COMMIT_SHA' # 반드시 정의되어야 하며, 그렇지 않으면 MR 파이프라인은 항상 기본 브랜치를 사용함
    rules:
      - if: $CI_PROJECT_PATH != "my-group/project-1" # 이 프로젝트를 호스팅하는 프로젝트에 대한 고정 경로여야 함.

# 컴플라이언스 팀이 스테이지/작업의 순서 및 교차를 제어할 수 있게 함. 작업이 정의되지 않은 스테이지는 숨겨집니다.
stages:
  - pre-compliance
  - build
  - test
  - pre-deploy-compliance
  - deploy
  - post-compliance

variables:  # 프로젝트의 로컬 .gitlab-ci.yml에서 작업별 변수 설정으로 덮어쓸 수 있음
  FOO: sast

sast:  # 프로젝트의 로컬 .gitlab-ci.yml로 덮어쓰일 수 없는 속성
  variables:
    FOO: sast
  image: ruby:2.6
  stage: pre-compliance
  rules:
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
      when: never
    - when: always  # 또는 when: on_success
  allow_failure: false
  before_script:
    - "# No before scripts."
  script:
    - echo "running $FOO"
  after_script:
    - "# No after scripts."

sanity check:
  image: ruby:2.6
  stage: pre-deploy-compliance
  rules:
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
      when: never
    - when: always  # 또는 when: on_success
  allow_failure: false
  before_script:
    - "# No before scripts."
  script:
    - echo "running $FOO"
  after_script:
    - "# No after scripts."

audit trail:
  image: ruby:2.7
  stage: post-compliance
  rules:
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
      when: never
    - when: always  # 또는 when: on_success
  allow_failure: false
  before_script:
    - "# No before scripts."
  script:
    - echo "running $FOO"
  after_script:
    - "# No after scripts."

include 정의에서의 rules 구성은 컴플라이언스 파이프라인이 호스트 프로젝트 자체에서 실행될 수 있어야 하는 경우에 순환적인 포함을 피하기 위한 것입니다. 컴플라이언스 파이프라인이 레이블이 지정된 프로젝트에서만 실행되는 경우 이 부분은 생략하셔도 됩니다.

컴플라이언스 파이프라인 및 외부에서 호스팅된 사용자 지정 파이프라인 구성

위의 예시는 모든 프로젝트가 그들의 파이프라인 구성을 동일한 프로젝트에 호스팅한다고 가정합니다. 만약 어떤 프로젝트가 프로젝트 외부에서 호스팅된 구성을 사용할 경우:

  • 예시 컴플라이언스 파이프라인 구성의 include 섹션을 조정해야 합니다. 예를 들어, include:rules 사용하는 방법:

    include:
      # 사용자 정의 경로 변수가 정의된 경우, 프로젝트의 외부 구성 파일을 포함합니다.
      - project: '$PROTECTED_PIPELINE_CI_PROJECT_PATH'
        file: '$PROTECTED_PIPELINE_CI_CONFIG_PATH'
        ref: '$PROTECTED_PIPELINE_CI_REF'
        rules:
          - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH && $PROTECTED_PIPELINE_CI_CONFIG_PATH && $PROTECTED_PIPELINE_CI_REF
      # 사용자 정의 경로 변수가 정의되지 않은 경우, 프로젝트의 내부 구성 파일을 일반적으로 포함합니다.
      - project: '$CI_PROJECT_PATH'
        file: '$CI_CONFIG_PATH'
        ref: '$CI_COMMIT_SHA'
        rules:
          - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH == null || $PROTECTED_PIPELINE_CI_CONFIG_PATH == null || $PROTECTED_PIPELINE_CI_REF == null
    
  • 외부 파이프라인 구성을 사용하는 프로젝트에 CI/CD 변수를 추가해야 합니다. 이 예시에서:

    • PROTECTED_PIPELINE_CI_PROJECT_PATH: 구성 파일을 호스팅하는 프로젝트의 경로, 예를 들어 group/subgroup/project.
    • PROTECTED_PIPELINE_CI_CONFIG_PATH: 프로젝트 내 구성 파일의 경로, 예를 들어 path/to/.gitlab-ci.yml.
    • PROTECTED_PIPELINE_CI_REF: 구성 파일을 검색하는 데 사용할 ref, 예를 들어 main.

프로젝트 포크에서 발췌된 병합 요청의 컴플라이언스 파이프라인

병합 요청이 fork에서 발췌될 때, 병합될 브랜치는 보통 fork에서만 존재합니다. 이러한 병합 요청을 컴플라이언스 파이프라인이 있는 프로젝트에 만들 때, 위의 스니펫은 Project <project-name> reference <branch-name> does not exist! 오류 메시지로 실패합니다. 이 오류는 대상 프로젝트의 상황에서 $CI_COMMIT_REF_NAME이 존재하지 않는 브랜치 이름으로 평가되기 때문에 발생합니다.

올바른 컨텍스트를 얻으려면, $CI_PROJECT_PATH 대신 $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH을 사용하세요. 이 변수는 병합 요청 파이프라인에서만 사용할 수 있습니다.

예를 들어, 프로젝트 포크에서 발췌된 병합 요청 파이프라인 및 브랜치 파이프라인을 모두 지원하는 구성의 경우, include 지시문과 함께 rules:if를 결합해야 합니다:

include:  # 개별 프로젝트의 구성 실행 가능 (프로젝트에 .gitlab-ci.yml 파일이 포함되어 있는 경우)
  - project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH'
    file: '$CI_CONFIG_PATH'
    ref: '$CI_COMMIT_REF_NAME'
    rules:
      - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
  - project: '$CI_PROJECT_PATH'
    file: '$CI_CONFIG_PATH'
    ref: '$CI_COMMIT_REF_NAME'
    rules:
      - if: $CI_PIPELINE_SOURCE != 'merge_request_event'

컴플라이언스 작업이 항상 실행되도록 보장하기

컴플라이언스 파이프라인은 GitLab CI/CD를 사용하여 사용자가 원하는 어떠한 유형의 컴플라이언스 작업을 정의하는 놀라운 유연성을 제공합니다. 당신의 목표에 따라, 이러한 작업은 다음과 같이 구성될 수 있습니다:

  • 사용자에 의해 변경됨.
  • 변경 불가능함.

일반적으로, 컴플라이언스 작업의 값:

  • 설정된 경우, 프로젝트 수준의 구성에 의해 변경되거나 무시될 수 없습니다.
  • 설정되지 않은 경우, 프로젝트 수준의 구성이 설정할 수 있습니다.

사용 사례에 따라 원하는 지점이나 변경되기를 원치 않는 지점이 될 수 있습니다.

이러한 작업이 항상 여러분이 정의한 대로 실행되고, 하위에 있는 프로젝트 수준의 파이프라인 구성이 이를 변경할 수 없도록 보장하기 위한 몇 가지 최상의 관행은 다음과 같습니다:

  • 각각의 컴플라이언스 작업에 a rules:when:always 블록을 추가합니다. 이렇게 하면 그들이 변경되지 않고 항상 실행됨이 보장됩니다.
  • 작업이 참조하는 변수들을 명시적으로 설정합니다. 이렇게 함으로써 프로젝트 수준의 파이프라인 구성이 이들을 설정하고 그들의 동작을 변경하지 않도록 보장합니다. 예를 들어, 예시 구성에서의 before_scriptafter_script 구성을 참조하십시오.
  • 작업을 실행할 컨테이너 이미지를 명시적으로 설정합니다. 이렇게 함으로써 당신의 스크립트 단계가 올바른 환경에서 실행되도록 보장합니다.
  • Relevant GitLab 미리 정의된 작업 키워드들을 명시적으로 설정합니다. 이렇게 함으로써 여러분이 원하는 설정을 사용하고 프로젝트 수준의 파이프라인에 의해 무시되지 않도록 보장합니다.

GitLab 14.7 및 이전 버전에서 부모 및 자식 파이프라인 피하기

참고: 이 조언은 GitLab 14.8 이상에는 적용되지 않습니다. 왜냐하면 수정 사항이 추가되어 컴플라이언스 파이프라인, 부모 및 자식 파이프라인을 결합할 수 있도록 호환성이 높아졌기 때문입니다.

컴플라이언스 파이프라인은 레이블이 지정된 프로젝트의 모든 파이프라인 실행에서 시작됩니다. 따라서 레이블이 지정된 프로젝트의 파이프라인이 자식 파이프라인을 트리거하는 경우 컴플라이언스 파이프라인이 먼저 실행됩니다. 이로 인해 자식 파이프라인 대신 부모 파이프라인이 트리거될 수 있습니다.

따라서 컴플라이언스 프레임워크가 있는 프로젝트에서는 다음과 같이 부모-자식 파이프라인을 다음과 같이 바꿔야 합니다:

  • 부모 파이프라인에 자식 파이프라인 구성을 제공하는 include 문 사용
  • 부모-자식 파이프라인 기능 대신 트리거 API를 사용하여 다른 프로젝트에 배치된 자식 파이프라인 실행

이 대안은 컴플라이언스 파이프라인이 부모 파이프라인을 다시 시작하지 않도록 보장합니다.

문제 해결

컴플라이언스 작업이 대상 리포지토리에 덮어씌워짐

컴플라이언스 파이프라인 구성에서 extends 문을 사용하면 컴플라이언스 작업이 대상 리포지토리 작업에 덮어씌워집니다. 예를 들어, 다음과 같은 .compliance-gitlab-ci.yml 구성이 있을 수 있습니다:

"컴플라이언스 작업":
  extends:
    - .compliance_template
  stage: build

.compliance_template:
  script:
    - echo "컴플라이언스 작업 수행"

또한 다음과 같은 .gitlab-ci.yml 구성이 있을 수 있습니다:

"컴플라이언스 작업":
  stage: test
  script:
    - echo "컴플라이언스 작업 덮어쓰기"

이 구성은 대상 리포지토리 파이프라인이 컴플라이언스 파이프라인을 덮어씌우고 다음 메시지를 받게 됩니다: 컴플라이언스 작업 덮어쓰기.

컴플라이언스 작업을 덮어쓰지 않으려면 컴플라이언스 파이프라인 구성에서 extends 키워드를 사용하지 않습니다. 예를 들어, 다음과 같은 .compliance-gitlab-ci.yml 구성이 있을 수 있습니다:

"컴플라이언스 작업":
  stage: build
  script:
    - echo "컴플라이언스 작업 수행"

또한 다음과 같은 .gitlab-ci.yml 구성이 있을 수 있습니다:

"컴플라이언스 작업":
  stage: test
  script:
    - echo "컴플라이언스 작업 덮어쓰기"

이 구성은 컴플라이언스 파이프라인을 덮어쓰지 않으며 다음 메시지를 받게 됩니다: 컴플라이언스 작업 수행.

미리 채워진 변수가 표시되지 않음

GitLab 15.3 이후의 컴플라이언스 파이프라인은 알려진 문제로 인해 수동으로 파이프라인을 시작할 때 미리 채워진 변수가 나타나지 않을 수 있습니다.

이 문제를 해결하기 위해 개별 프로젝트의 구성을 실행하는 include: 문에서 ref: '$CI_COMMIT_REF_NAME' 대신 ref: '$CI_COMMIT_SHA'를 사용합니다.

이 변경 사항이 적용된 예시 구성은 다음과 같습니다:

include:
  - project: '$CI_PROJECT_PATH'
    file: '$CI_CONFIG_PATH'
    ref: '$CI_COMMIT_SHA'