개발 리뷰를 받고 사내 적용을 결정했다
1편에서는 개인 홈 서버에 프로젝트 생성부터 Preview 배포까지 연결한 과정을 정리했다. 이후 개발 리뷰를 받으며 사내 버셀의 목표와 도입 방법, 현재 시스템을 설명했다. 리뷰 후에는 사내 개발에 먼저 적용해보기로 했다.
목표: 검토와 승인을 거쳐 운영까지 연결하기
최종 목표는 GTM 방식으로 프로젝트 검증부터 운영 반영까지 이어지는 파이프라인을 구축하는 것이다. 보안 검토와 서버 개발 검토를 거치면서도 변경 사항을 운영에 빠르게 반영할 수 있는 환경을 만들고 싶다.
보안 관련 공통 설정은 사내 버셀에서 우리가 관리한다. 각 기능에 필요한 세부 보안 검토는 일부 자동화하고, 담당자가 검토하고 승인하기 쉬운 환경을 제공하려 한다. 여기에 서버 개발 관련 검토 과정도 연결해, 개발부터 운영 반영까지 필요한 절차를 이어가는 것이 목표다.
도입 방법: 사내 개발에서 사용성과 활용도 확인하기
첫 적용 대상은 사내 개발로 정했다. 기획자, 마케터, 클라이언트 개발자가 사내 버셀에 어떤 반응을 보이고 어떻게 활용하는지 살펴보며 발전 방향을 정하기로 했다.
먼저 사용하기 편한지, 실제 개발에 얼마나 활용되는지 확인한다. 그 결과를 바탕으로 필요한 기능을 보완하고, 운영까지 반영하는 과정은 이후 구체화하기로 했다.
사내 적용 과정
프로젝트를 자유롭게 만들어보고 검증할 수 있도록 사내망에서 진행했다. 그 과정에서 사내 버셀이 동작하는 데 필요한 통신과 각 프로젝트가 사용하는 서비스에 대한 접근을 정리해야 했다.
1. 방화벽 설정
사용자가 포털에 접속하는 것 외에도 GitHub 로그인과 저장소 조회, 이미지와 패키지 다운로드가 필요하다. 프로젝트마다 연동할 내부 서비스도 달라진다. 사내 버셀이 공통으로 사용하는 통신은 기본 설정으로 관리하고, 개별 프로젝트에 필요한 접근은 목적지와 용도에 따라 추가하는 방식으로 정리하려 한다.
현재 시스템을 기준으로 방화벽 구성하기
먼저 외부 인바운드와 아웃바운드를 정리했다. 아래 그림은 사내 버셀 서버의 통신 흐름으로, 사내 사용자 접근도 포함했다. 인바운드는 왼쪽, 아웃바운드는 오른쪽에 표시했다. 포트는 목적지 포트이며, 실제 방화벽 허용 결과를 나타내는 그림은 아니다.
GitHub 관련 IP 대역은 GitHub 메타 API의 최신 응답을 기준으로 설정한다. IP 범위를 표현하는 CIDR 값을 통신 용도에 맞게 선택한다.
- 인바운드 —
hooks: GitHub Webhook의 출발지 IP 대역으로 사용한다. Webhook의 외부 인바운드 TCP 443을 이 대역으로 제한하고, 수신 URL 경로는 리버스 프록시에서 제한한다. - 아웃바운드 —
web: GitHub 웹 인증과 OAuth 토큰 교환을 위한 목적지 IP 대역이다. - 아웃바운드 —
api: 저장소 생성·권한 확인·Poller 조회 등 GitHub API 호출에 사용한다. - 아웃바운드 —
git: 저장소의 소스 코드를 가져올 때 사용한다. 현재 구현은 HTTPS clone이므로 TCP 443을 사용한다.
사내 인바운드 443의 IP 대역별 허용 검토
사내 버셀 서버의 TCP 443에 접근할 때 IP 대역 단위로 허용할 수 있는지 검토했다. 현재 정책상 IP 대역별로 허용하는 방식은 불가능하다. 따라서 그림의 사내 사용자 접근 경로를 그대로 적용할 수 있는 것은 아니며, 정책에 맞는 접근 방식은 추가로 정해야 한다.
2. 시스템 구축
GitHub App 등록 및 설정 정책안
프로젝트 관리 범위와 사용자 이용 조건은 다음과 같이 정하려 한다.
- 관리 범위: 전용 GitHub 조직을 하나 만들고, 해당 조직의 저장소만 사내 버셀에 등록한다.
- 이용 대상: 같은 Enterprise에 속한 사용자는 해당 조직에 가입하지 않아도 사내 버셀을 이용할 수 있도록 한다.
- 이용 조건: 사용자는 서비스 이용 전에 GitHub App 등록을 완료해야 한다.
프로젝트를 시작하는 경로는 두 가지다.
| 경로 | 사용자 행동 | 사내 버셀 처리 |
|---|---|---|
| 새 프로젝트 생성 | 관리 페이지에서 프로젝트 생성 | 전용 조직에 저장소 생성 → 사내 버셀 등록 → 기본 서비스 배포 |
| 기존 저장소 등록 | 전용 조직에 저장소를 만든 뒤 관리 페이지에서 등록 | 해당 저장소를 사내 버셀에 연결 → 서비스 배포 |
기능별 구축 및 동작 확인
정책에 맞춰 GitHub App과 인증·저장소 연동을 설정하고, 다음 흐름을 확인한다.
- 같은 Enterprise 사용자 및 GitHub App 등록 여부에 따른 이용 조건.
- 전용 조직의 저장소만 등록되는지와 두 경로의 최초 배포.
- 이후 코드 변경 감지 → 빌드·테스트 → Preview 접속.
구축 중 확인한 문제와 기능별 동작 확인 결과는 이후 이어서 기록할 예정이다.
3. 보안 피드백 반영
보안 검토에서 다음 항목을 확인하고 대응해야 한다는 피드백을 받았다.
- 사용자 코드가 사내망, 호스트, 다른 프로젝트에 접근하지 않도록 제한해야 한다.
- 사내 버셀의 관리 권한과 비밀 정보가 사용자 컨테이너에 노출되지 않아야 한다.
- 특정 프로젝트의 자원 사용과 로그 증가가 다른 서비스에 영향을 주지 않도록 제한해야 한다.
이 피드백을 바탕으로 로컬 Docker 실험 환경에서 격리 설정을 적용했다.
아래 그림은 사용자 접근 경로와 프로젝트별 격리 범위를 요약한 개념도다.
| 구성 | 검토 범위 |
|---|---|
| 보안 피드백 개요 | 통신 제한, 컨테이너 격리, 로그 감사와 모니터링의 전체 검토 범위 |
| 통신 제한 | IP 제한, TLS 1.2 이상 적용, secret 기반 페이로드 검증 |
| 컨테이너 격리 — 담당 작업 | 디스크 격리, 네트워크 격리, 권한 제한, 가용 자원 제한의 목적과 구성 방향 |
| 로그 감사와 모니터링 — 담당 작업 | 수집할 이벤트, 기록할 정보, 로그 보관과 조회 방식, 모니터링 대상 |
네트워크 격리
사용자 코드의 접근 범위를 제한하려면 실행 중인 컨테이너뿐 아니라 빌드 중 실행되는 코드의 통신도 확인해야 했다.
실행 컨테이너에 적용한 제한이 빌드 과정에도 그대로 적용된다고 볼 수는 없었다. 사내 버셀에서 사용하는 빌더의 통신 경로를 확인하고, 그 경로까지 제한 대상에 포함해야 한다는 점을 확인했다.
| 검토된 이슈 | 적용한 내용 | 적용 결과 |
|---|---|---|
| 사용자 코드의 사내망 접근 | 실행 컨테이너의 사설 대역 접근 차단 |
|
| 사용자 코드의 호스트 서비스 접근 | 실행 컨테이너의 호스트 접근 차단 |
|
| 실행 컨테이너의 제한을 적용해도 남는 빌드 중 사내망 접근 | 빌드 단계의 통신 경로에도 사설 대역 접근 차단 적용 |
|
| 내부 연동을 위한 예외 허용 범위의 확대 | 필요한 내부 연동을 위해 지정한 IP와 포트만 허용하는 예외 설정 |
|
디스크 격리
프로젝트마다 읽고 쓸 수 있는 경로를 나누고, 호스트 파일이나 다른 프로젝트의 데이터를 공유하지 않도록 구성했다.
| 검토된 이슈 | 적용한 내용 | 적용 결과 |
|---|---|---|
| 호스트 파일의 컨테이너 노출 | 테스트 호스트 디렉터리의 bind mount 제거 |
|
| 프로젝트 간 데이터 공유와 노출 | 프로젝트별 named volume 분리 |
|
| 컨테이너 루트 파일시스템의 불필요한 변경 | 컨테이너 루트 파일시스템을 읽기 전용으로 설정 |
|
| 임시 파일 증가에 따른 자원 소진 | 쓰기가 필요한 임시 경로에만 용량이 제한된 tmpfs 연결 |
|
권한 제한과 비밀 정보 보호
파일 접근을 나누는 것과 함께, 사용자 컨테이너에 전달하는 실행 권한과 비밀 정보의 범위도 줄였다.
| 검토된 이슈 | 적용한 내용 | 적용 결과 |
|---|---|---|
| 사용자 코드에 부여된 과도한 실행 권한 | 비루트 사용자로 실행하고 Linux capabilities 제거 |
|
| Docker socket을 통한 관리 API 접근 | 사용자 컨테이너의 Docker socket 마운트 제거 |
|
| 환경변수를 통한 사내 버셀의 비밀 정보 노출 | 사내 버셀의 비밀 값을 제외하고 사용자에게 필요한 환경변수만 명시적으로 전달 |
|
| 빌드 토큰의 이미지 이력과 설정 잔존 | 빌드에 필요한 가짜 토큰을 ARG와 ENV 대신 BuildKit secret mount로 전달 |
|
가용 자원 제한
한 프로젝트가 서버 자원을 계속 점유하지 않도록 컨테이너별 사용량에 상한을 두고 동작을 확인했다.
| 검토된 이슈 | 적용한 내용 | 적용 결과 |
|---|---|---|
| 특정 프로젝트의 메모리 사용에 따른 다른 서비스 영향 | 메모리 사용량 제한docker run --memory 512m --memory-swap 512m <image> |
|
| 특정 프로젝트의 CPU 점유 | CPU 사용량 제한docker run --cpus 1 <image> |
|
| 과도한 프로세스 생성에 따른 자원 소진 | 생성할 수 있는 프로세스 수 제한docker run --pids-limit 256 <image> |
|
로그 관리와 모니터링
로그가 계속 쌓이는 것을 제한하고, 디스크 사용량에 따라 알림 조건을 판단하는 동작을 확인했다.
| 검토된 이슈 | 적용한 내용 | 적용 결과 |
|---|---|---|
| 로그 누적에 따른 저장 공간 소진 | 새 컨테이너의 로그에 max-size=10m, max-file=3 로테이션 설정 |
|
| 디스크 사용량 증가를 감지할 기준 부재 | 테스트 파일시스템 사용률이 80% 이상이면 알림 조건을 충족하도록 판정 |
|