Self-managed runners의 보안

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed

GitLab CI/CD 파이프라인은 간단한 또는 복잡한 DevOps 자동화 작업에 사용되는 워크플로우 자동화 엔진입니다. 이러한 파이프라인은 원격 코드 실행 서비스를 가능하게 하므로 다음과 같은 프로세스를 구현하여 보안 위험을 줄여야 합니다:

  • 전체 기술 스택의 보안을 구성하는 계획적인 방법.
  • 설정 및 플랫폼 사용에 대한 지속적이고 엄격한 검토.

GitLab CI/CD 작업을 self-managed runners에서 실행할 계획이 있다면, 컴퓨팅 인프라와 네트워크에 대한 보안 위험이 존재합니다.

Runner는 CI/CD 작업에서 정의된 코드를 실행합니다. 프로젝트 리포지토리의 Developer 역할을 가진 사용자는 의도적 또는 그렇지 않아도 runner를 호스팅하는 환경의 보안을 compromise할 수 있습니다.

특히 self-managed runners가 비휘발성이고 여러 프로젝트에 사용될 경우 이러한 위험이 더욱 심각해집니다.

  • 악성 코드가 포함된 리포지토리로부터의 작업은 비휘발성 runner에 서비스되는 다른 리포지토리의 보안을 compromise할 수 있습니다.
  • executor에 따라 작업은 runner가 호스팅된 가상 머신에 악성 코드를 설치할 수 있습니다.
  • 손상된 환경에서 실행되는 작업에 노출된 기밀 변수(예: CI_JOB_TOKEN)는 도난당할 수 있습니다.
  • Developer 역할을 가진 사용자는 프로젝트와 연결된 서브모듈에 액세스할 수 있습니다. 심지어 서브모듈의 상위 프로젝트에 액세스 권한이 없더라도 그렇습니다.

다른 Executor에 대한 보안 위험

사용 중인 executor에 따라 다른 보안 위험을 마주하게 됩니다.

Shell executor의 사용

shell executor로 빌드를 실행할 때 runner 호스트와 네트워크에 대한 높은 보안 위험이 존재합니다. 작업은 GitLab Runner의 사용자 권한으로 실행되며, 이로 인해 이 서버에서 실행된 다른 프로젝트의 코드를 도난당할 수 있습니다. 신뢰할 수 있는 빌드에만 사용하도록 하세요.

Docker executor의 사용

비특권 모드에서 실행할 때 Docker는 안전한 것으로 간주될 수 있습니다. 이러한 구성을 보다 안전하게 만들려면 Docker 컨테이너에서 sudo 비활성화 또는 SETUIDSETGID 권한 해제로 작업을 실행하세요.

비특권 모드에서 더 세분화된 권한은 cap_add/cap_drop 설정을 통해 구성할 수 있습니다.

경고: Docker의 특권 컨테이너에는 호스트 VM의 모든 루트 권한이 있습니다. 자세한 내용은 런타임 권한 및 Linux 기능에 대한 공식 Docker 문서를 참조하세요.

특권 모드에서 사용자가 CI/CD 작업을 실행하면 runner 호스트 시스템에 대한 완전한 루트 액세스, 볼륨의 장착 및 해제 권한, 중첩된 컨테이너 실행 권한을 얻을 수 있습니다.

특권 모드를 활성화하면 컨테이너의 모든 보안 메커니즘이 비활성화되고 권한 상승으로 이어질 수 있는 호스트 노출이 발생할 수 있습니다.

Docker Machine executor를 사용하는 경우 MaxBuilds = 1 설정을 사용하는 것을 강력히 권장합니다. 이렇게 하면 보안 취약점으로 인해 손상될 수 있는 단일 자동 확장되는 VM이 하나의 작업을 처리하는 데 사용됩니다.

if-not-present 풀 정책을 사용한 사설 Docker 이미지의 사용

프라이빗 컨테이너 레지스트리 사용 설명서에서 기술된 대로 사설 Docker 이미지를 사용하는 경우 pull_policy 값을 always로 사용해야 합니다. 특히 Docker 또는 Kubernetes executor를 사용하는 public, shared Runner에서는 always pull 정책을 사용해야 합니다.

if-not-present 풀 정책이 설정된 예제를 고려해 보겠습니다:

  1. 사용자 A가 registry.example.com/image/name에 프라이빗 이미지를 가지고 있습니다.
  2. 사용자 A가 공유 Runner에서 빌드를 시작합니다: 빌드는 레지스트리의 자격 증명을 수신하고 인증된 후 이미지를 가져옵니다.
  3. 이미지가 공유 Runner의 호스트에 저장됩니다.
  4. 사용자 B가 registry.example.com/image/name에서의 프라이빗 이미지에 액세스 권한이 없습니다.
  5. 사용자 B가 사용자 A가 사용한 공유 Runner에서 이 이미지를 이용한 빌드를 시작합니다. 사용자 B가 이미지에 액세스할 수 없었더라도 공유 로컬 버전을 찾고 이를 사용합니다.

그러므로 여러 사용자 및 다른 프로젝트가 사용할 수 있는 Runner를 호스팅하는 경우(public, shared, private, 다양한 액세스 수준) if-not-present 풀 정책 값을 사용해서는 안 되며, 대신 다음과 같이 사용하세요:

  • never - 사용자가 당신이 이미 사전에 다운로드한 이미지만 사용하도록 제한하려는 경우.
  • always - 사용자가 어떤 레지스트리에서든 어떤 이미지를 다운로드할 수 있도록 하려는 경우.

if-not-present 풀 정책은 신뢰할 수 있는 빌드와 사용자가 사용하는 특정 Runner에서만 사용해야 합니다.

자세한 내용은 풀 정책 문서를 참조하세요.

Docker 설치 시스템

참고: 이는 0.5.0 미만 버전 또는 더 최신 버전으로 업그레이드된 시스템에 적용됩니다.

Linux 시스템에 Docker가 설치된 경우, gitlab-runnerDocker에 액세스 권한을 갖는 사용자를 생성합니다. 이는 shell executor로 실행되는 작업이 docker에 완전한 권한으로 액세스할 수 있게 하므로 서버에 대한 루트 액세스를 허용할 수 있습니다.

SSH executor의 사용

SSH executor는 StrictHostKeyChecking 옵션이 누락됨으로써 MITM 공격(중간자 공격)에 취약합니다. 이는 향후 릴리스에서 수정될 것입니다.

Parallels executor의 사용

Parallels executor는 가능한 최고의 안전한 옵션으로 전체 시스템 가상화를 사용하며, 격리된 모드에서 실행되는 VM 머신을 사용합니다. 이는 모든 주변 장치 및 공유 폴더에 대한 액세스를 차단합니다.

Runner 복제

Runner는 GitLab 서버를 식별하기 위해 토큰을 사용합니다. Runner를 복제하는 경우 복제된 Runner가 해당 토큰의 작업을 가져갈 수 있습니다. 이는 Runner 작업을 “도난”할 수 있는 가능한 공격 벡터입니다.

공유 환경에서 GIT_STRATEGY: fetch 사용 시 보안 위험

여기에서 GIT_STRATEGYfetch로 설정하면 runner는 Git 리포지토리의 지역 작업 사본을 재사용합니다.

지역 사본 사용은 CI/CD 작업의 성능을 향상시킬 수 있습니다. 그러나 재사용 가능한 사본에 액세스할 수 있는 모든 사용자는 다른 사용자의 파이프라인에서 실행되는 코드를 추가할 수 있습니다.

Git은 서브모듈(다른 리포지토리 내에 포함된 리포지토리)의 내용을 부모 리포지토리의 Git reflog에 저장합니다. 따라서 프로젝트의 서브모듈이 초기에 복제된 후에도 사용자는 스크립트에서 git submodule update를 실행하여 서브모듈의 내용에 액세스할 수 있습니다. 이는 서브모듈이 삭제되었고 해당 작업을 시작한 사용자가 서브모듈 프로젝트에 액세스 권한이 없더라도 적용됩니다.

GIT_STRATEGY: fetch는 공유 환경에 액세스하는 모든 사용자들을 신뢰할 경우에만 사용하세요.

보안 강화 옵션

권한 있는 컨테이너 사용의 보안 리스크 감소

Docker의 --privileged 플래그를 사용해야 하는 CI/CD 작업을 실행해야 하는 경우, 다음 단계를 따라 보안 리스크를 줄일 수 있습니다.

  • --privileged 플래그가 활성화된 Docker 컨테이너를 격리되고 일회성 가상 머신에서만 실행합니다.
  • Docker의 --privileged 플래그를 필요로 하는 작업을 실행하기 위해 전용 실행기를 구성합니다. 그런 다음 이러한 실행기를 보호된 브랜치에서만 작업을 실행하도록 구성합니다.

네트워크 세분화

GitLab Runner는 사용자가 제어하는 스크립트를 실행하기 위해 설계되었습니다. 악성일 가능성이 있는 작업을 실행할 때, 공격 표면을 줄이기 위해 해당 작업을 자체 네트워크 세그먼트에서 실행할 수 있습니다. 이렇게 함으로써 인프라 및 서비스로부터 네트워크 분리가 이루어집니다.

모든 필요는 고유합니다. 그러나 클라우드 환경의 경우 다음을 포함할 수 있습니다:

  • 실행기 가상 머신을 자체 네트워크 세그먼트에 구성
  • 인터넷에서 실행기 가상 머신으로의 SSH 액세스 차단
  • 실행기 가상 머신 간의 트래픽 제한
  • 클라우드 제공 엔드포인트의 접근 제어

참고: 모든 실행기에는 GitLab.com 또는 GitLab 인스턴스로의 외부 네트워크 연결이 필요합니다. 대부분의 작업에는 의존성 검색 등을 위해 인터넷으로의 외부 네트워크 연결도 필요합니다.

실행기 호스트의 보안 강화

실행기에 정적 호스트를 사용하는 경우(물리적 서버 또는 가상 머신), 호스트 운영 체제에 대한 보안 모범 사례를 구현해야 합니다.

CI 작업에서 실행되는 악성 코드는 호스트를 compromise할 수 있으므로 보안 프로토콜은 영향을 완화하는 데 도움이 될 수 있습니다. 고려해야 할 다른 사항으로는 환경에서 다른 엔드포인트에 액세스할 수 있게 하는 SSH 키와 같은 파일을 보호하거나 제거하는 것 등이 있습니다.

각 빌드 후 .git 폴더 정리

작업 에이전트에 정적 호스트를 사용하는 경우, FF_ENABLE_JOB_CLEANUP 피처 플래그를 활성화하여 추가적인 보안 계층을 구현할 수 있습니다.

FF_ENABLE_JOB_CLEANUP을 활성화하면 실행기가 호스트에서 사용하는 빌드 디렉터리가 각 빌드 후 정리됩니다.