GitHub가 eBPF를 사용하여 배포 안전성을 향상시키는 방법 (새 탭에서 열림)
GitHub는 장애 상황에서도 배포를 계속할 수 있도록 배포 코드가 GitHub 자체나 다른 내부 서비스에 의존하는 순환 의존성을 차단하려 한다. 이를 위해 배포 프로세스만 별도 Linux cGroup에 배치하고, eBPF의 `BPF_PROG_TYPE_CGROUP_SKB`를 이용해 해당 프로세스의 네트워크 송신을 선택적으로 감시·차단하는 방식을 검토했다. 이 접근법은 호스트 전체의 네트워크를 막지 않으면서 배포 과정의 외부·내부 의존성을 검증할 수 있다는 점이 핵심이다. ## GitHub 배포의 순환 의존성 - GitHub는 자체 소스 코드를 `github.com`에 보관하므로, GitHub 장애 시 소스 코드 접근과 복구 배포가 동시에 어려워질 수 있다. - 이를 완화하기 위해 다음을 유지한다. - 장애 시 수정 배포를 위한 코드 미러 - 롤백에 사용할 사전 빌드된 배포 자산 - 하지만 배포 스크립트가 새롭게 순환 의존성을 만들 가능성은 여전히 남아 있다. - 내부 서비스 호출 - GitHub에서 바이너리 다운로드 - 실행 중인 도구의 자동 업데이트 확인 등 ## 순환 의존성의 세 가지 유형 ### 직접 의존성 - 배포 스크립트가 GitHub에서 오픈 소스 도구의 최신 릴리스를 직접 다운로드한다. - GitHub 장애로 릴리스 데이터를 제공할 수 없으면 배포 스크립트도 완료되지 않는다. ### 숨은 의존성 - 필요한 도구가 이미 호스트 디스크에 존재하더라도, 실행 시 업데이트 가능 여부를 확인할 수 있다. - 이때 도구가 GitHub에 접속하지 못하면: - 오류를 반환하고 실패하거나 - 네트워크 타임아웃으로 멈출 수 있다. - 코드만 검토해서는 이런 런타임 의존성을 발견하기 어렵다. ### 일시적·간접 의존성 - 배포 스크립트가 내부 마이그레이션 서비스 같은 다른 서비스를 API로 호출한다. - 해당 서비스가 다시 GitHub에서 최신 바이너리를 받으려 하면, 의존성이 여러 단계 뒤에서 발생한다. - 최종적으로 GitHub 장애가 내부 서비스와 배포 스크립트까지 연쇄적으로 실패시킨다. ## 기존 검증 방식의 한계 - 기존에는 각 상태 저장 호스트를 담당하는 팀이 배포 스크립트를 검토해 순환 의존성을 찾아야 했다. - 실제로는 많은 의존성이 장애가 발생한 뒤에야 드러난다. - 가장 단순한 검증 방법은 호스트에서 `github.com` 접근을 전부 차단하는 것이다. - 그러나 해당 호스트는 롤링 배포, 드레인, 재시작 중에도 고객 트래픽을 처리하므로 호스트 전체의 네트워크를 차단하면 운영 기능까지 손상된다. ## cGroup과 eBPF를 이용한 선택적 네트워크 차단 - eBPF는 Linux 커널에 사용자 정의 프로그램을 로드하고 네트워크 같은 핵심 시스템 동작에 연결할 수 있다. - GitHub가 주목한 프로그램 유형은 `BPF_PROG_TYPE_CGROUP_SKB`다. - 특정 cGroup의 네트워크 ingress/egress에 연결 가능 - 특히 프로세스 그룹의 외부 송신 트래픽을 제어할 수 있음 - cGroup은 프로세스 집합에 리소스 제한과 격리를 적용하는 Linux 기능이다. - Docker 전용 기능이 아니며 직접 생성·구성할 수 있다. - 따라서 다음 구조가 가능하다. - 배포 스크립트만 별도 cGroup에 배치 - 해당 cGroup의 egress 트래픽만 eBPF로 감시 - GitHub나 특정 내부 서비스로 향하는 연결만 차단 - 같은 호스트에서 실행 중인 고객 트래픽 처리 프로세스는 계속 네트워크 사용 ## Go와 `cilium/ebpf`를 이용한 구현 - GitHub는 Go 기반 proof of concept을 만들고 `cilium/ebpf` 라이브러리를 사용했다. - 이 라이브러리는 다음 작업을 단순화한다. - eBPF 프로그램과 맵을 읽고 수정 - 프로그램을 컴파일·로드 - 커널의 다양한 hook에 연결 - Go 코드에서는 다음 흐름으로 cGroup에 eBPF 프로그램을 연결한다. - 사전 컴파일된 eBPF 오브젝트와 맵을 커널에 로드 - `/sys/fs/cgroup/system.slice` 같은 cGroup 경로 지정 - `ebpf.AttachCGroupInetEgress`를 사용해 송신 트래픽 hook에 연결 - eBPF 맵에서 패킷 수 등 관측 데이터를 주기적으로 조회 - 예제 eBPF 프로그램은 `BPF_MAP_TYPE_ARRAY` 맵에 값을 저장하고, `cgroup_skb/egress` hook이 호출될 때마다 송신 패킷 수를 증가시키는 구조다. - 이처럼 먼저 트래픽을 관찰한 뒤, 특정 목적지에 대한 연결을 허용하거나 차단하는 정책으로 확장할 수 있다. ## 실용적인 의미 - 배포 시스템은 “호스트 전체를 격리”하는 대신 “배포 프로세스만 제한”할 수 있다. - 장애 대응 전에 GitHub, 내부 API, 자동 업데이트 서버 등 필수 경로에 대한 의존성을 실제 실행 환경에서 검증할 수 있다. - eBPF 기반 필터링은 숨은 의존성과 간접 의존성을 찾아내는 방어 계층으로 활용할 수 있다. - 다만 실제 운영에서는 차단 정책을 적용하기 전에 관찰 모드로 트래픽을 수집하고, 정상적인 고객 트래픽과 배포 트래픽이 정확히 분리되는지 검증하는 것이 바람직하다.