Self-managed runners의 보안

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

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

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

자체 관리형 러너에서 GitLab CI/CD 작업을 실행할 계획이라면, 컴퓨팅 인프라 및 네트워크에 보안 위험이 존재합니다.

러너는 CI/CD 작업에서 정의된 코드를 실행합니다. 프로젝트 저장소에 Developer 역할이 있는 사용자는 의도적이든 그렇지 않든 러너를 호스팅하는 환경의 보안을 compromise할 수 있습니다.

특히 자체 관리형 러너가 비소멸성(non-ephemeral)이고 여러 프로젝트에 사용되는 경우 이 위험이 더욱 심각해집니다.

  • 악성 코드가 포함된 저장소에서의 작업은 비소멸성 러너에 의해 제공되는 다른 저장소의 보안을 compromise할 수 있습니다.
  • 실행기에 따라 작업이 러너가 호스팅되는 가상 머신에 악성 코드를 설치할 수 있습니다.
  • 이미 compromised된 환경에서 실행되는 작업에 노출된 비밀 변수(CI_JOB_TOKEN을 포함하지만 이에 국한되지는 않음)는 도난당할 수 있습니다.
  • Developer 역할을 가진 사용자는 프로젝트와 연관된 서브모듈에 액세스할 수 있으며 해당 서브모듈의 상위 프로젝트에 액세스 권한이 없더라도 해당합니다.

다양한 실행기에 대한 보안 위험

사용 중인 실행기에 따라 다양한 보안 위험에 직면할 수 있습니다.

Shell 실행기 사용

shell 실행기를 사용하여 빌드를 실행할 때, 러너 호스트 및 네트워크에 높은 보안 위험이 존재합니다. 작업은 GitLab 러너 사용자의 권한으로 실행되어 이 서버에서 실행되는 다른 프로젝트의 코드를 도난당할 수 있습니다. 신뢰할 수 있는 빌드에만 사용하세요.

Docker 실행기 사용

Docker는 권한이 없는 모드에서 실행하는 경우 안전하다고 볼 수 있습니다. 이러한 구성을 더 안전하게 만들려면 Docker 컨테이너에서 sudo를 비활성화하거나 SETUIDSETGID 기능을 삭제한 비루트 사용자로 작업을 실행하세요.

권한이 없는 모드에서 보다 세부적인 권한을 설정하려면 cap_add/cap_drop 설정을 통해 설정하세요.

경고: Docker에서의 privileged 컨테이너는 호스트 VM의 모든 루트 권한을 가지게 됩니다. 더 많은 정보는 Runtime privilege and Linux capabilities의 Docker 공식 문서를 참조하세요.

특권 모드로 실행하는 것은 모든 컨테이너의 보안 메커니즘을 비활성화하고 호스트를 권한 상승의 취약점에 노출시키므로 컨테이너가 탈출될 수 있습니다.

여러 기관 간에 공유되는 러너에서 특히 위험합니다. 예를 들어, 여러 조직이 동시에 작업할 수 있는 GitLab.com과 같은 서비스의 인스턴스 전반에 걸친 러너.

Docker Machine 실행기를 사용하는 경우에도 보았더라도, 보안 취약성으로 인해 탈취될 수 있는 단일 자동 크기 조정 가능한 VM에 대해 MaxBuilds = 1 설정을 강력히 권장합니다.

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

고급 구성: 사설 컨테이너 레지스트리 사용에서 설명된 사설 Docker 이미지 지원을 사용할 때, pull_policy 값을 always로 사용해야 합니다. 특히 Docker 또는 Kubernetes 실행기와 함께 공용, 공유 러너를 호스팅하는 경우 always 풀 정책을 사용해야 합니다.

if-not-present로 설정된 풀 정책의 사례를 고려해 봅시다:

  1. 사용자 A가 registry.example.com/image/name에서 사설 이미지를 가지고 있습니다.
  2. 사용자 A가 공유 러너에서 빌드를 시작합니다: 인증 후 이미지를 획득하여 빌드에 사용합니다.
  3. 이미지가 공유 러너의 호스트에 저장됩니다.
  4. 사용자 B는 registry.example.com/image/name에서의 사설 이미지에 액세스할 수 없습니다.
  5. 사용자 B가 동일한 공유 러너에서 이 이미지를 사용하는 빌드를 시작합니다 : 이미지가 외부 인증서 정보가 없는 상황에서 사용자가 이미지를 pull하지 못했더라도 공유 러너의 로컬 버전을 찾아 사용합니다.

그러므로 다양한 사용자와 다른 프로젝트에서 사용될 수 있는 러너를 호스팅할 경우 (사적 및 공용 액세스 레벨이 섞인), pull 정책 값을 if-not-present로 사용해서는 안 되고 다음을 사용하세요:

  • never - 본인이 미리 다운로드한 이미지만 사용하도록 사용자를 제한하려면.
  • always - 어떤 레지스트리에서든 사용자가 어떤 이미지를 다운로드할 수 있게 하려면.

if-not-present 풀 정책은 신뢰할 만한 빌드 및 사용자가 사용하는 특정 러너에서만 사용해야 합니다.

추가 정보는 pull policies documentation를 참조하세요.

Docker가 설치된 시스템

참고: 이는 0.5.0 미만의 설치에 적용되거나 보다 새로운 버전으로 업그레이드된 경우에 해당됩니다.

Linux 시스템에 Docker가 설치된 상태에서 GitLab 러너 패키지를 설치할 때 gitlab-runnerDocker 데몬에 액세스할 수 있는 권한을 가진 사용자를 생성합니다. 이로써 shell executor로 실행되는 작업은 docker에 완전한 권한으로 액세스할 수 있게 되며 잠재적으로 서버에 대한 루트 액세스를 허용할 수 있습니다.

SSH executor 사용

SSH executor는 StrictHostKeyChecking 옵션이 누락되어 MITM(중간자 공격)에 취약합니다. 이는 향후 릴리스 중의 하나에서 수정될 것입니다.

Parallels executor 사용

Parallels executor는 가능한 가장 안전한 옵션입니다. 왜냐하면 완전한 시스템 가상화를 사용하며 격리된 가상화 및 격리된 모드로 구성된 VM 머신을 사용합니다. 이는 모든 주변 장치 및 공유 폴더로부터의 액세스를 차단합니다.

러너 복제

러너는 GitLab 서버를 식별하기 위해 토큰을 사용합니다. 따라서 러너를 복제하면 해당 토큰의 같은 작업을 가져갈 수 있습니다. 이는 “러너” 작업을 “도둑질”할 수 있는 가능한 공격 경로입니다.

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

GIT_STRATEGYfetch로 설정하면 러너는 Git 저장소의 로컬 작업 복사본을 재사용하려고 시도합니다.

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

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

GIT_STRATEGY: fetch를 사용할 때는 공유 환경에 액세스 권한이 있는 모든 사용자를 신뢰할 때에만 사용하세요.

보안 강화 옵션

특권 컨테이너 사용의 보안 위험 감소

Docker의 --privileged 플래그를 사용해야 하는 CI/CD 작업을 실행해야 하는 경우 보안 위험을 줄이기 위해 다음 단계를 수행할 수 있습니다:

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

네트워크 분할

GitLab 러너는 사용자가 제어하는 스크립트를 실행하도록 설계되었습니다. 악의적인 작업이 있다면 공격 표면을 줄이기 위해 해당 작업을 자체 네트워크 세그먼트에서 실행할 수 있습니다. 이는 다른 인프라 및 서비스로부터의 네트워크 분리를 제공할 것입니다.

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

  • 자체 네트워크 세그먼트에 러너 가상 머신을 구성합니다.
  • 인터넷에서 러너 가상 머신으로의 SSH 액세스 차단
  • 러너 가상 머신 간의 트래픽 제한
  • 클라우드 제공자 메타데이터 엔드포인트에 대한 액세스 필터링

참고: 모든 러너는 GitLab.com 또는 귀하의 GitLab 인스턴스로의 외부 네트워크 연결이 필요합니다. 대부분의 작업은 종속성 가져오기 등을 위해 인터넷으로의 외부 네트워크 연결이 필요합니다.

러너 호스트 보안

러너에 대한 정적 호스트를 사용하는 경우, 베어 메탈 또는 가상 머신이든 호스트 운영 체제에 대한 보안 모범 사례를 구현해야 합니다.

CI 작업의 맥락에서 악의적인 코드가 실행될 수 있으므로 보안 프로토콜은 영향을 완화하는 데 도움이 될 수 있습니다. 기억해 둘 사항으로는 호스트 시스템에서 SSH 키와 같은 파일을 보안하거나 제거하여 공격자가 환경에서 다른 엔드포인트에 액세스할 수 있는 문제를 방지하는 것이 있습니다.