첫 번째 프로젝트는 정상 완료됐지만, 두 번째 프로젝트가 이전 작업의 캐시와 파일을 읽는다면 라벨 설정만으로는 격리가 끝난 것이 아닙니다.

이번 주에는 일반 빌드용 공유 Mac Runner와 정식 배포용 전용 Mac Runner를 나누고, 프로젝트 하나씩 작업 공간과 자격 증명을 검증하는 방식으로 배포해야 합니다.

이 글을 읽어야 하는 사람

여러 저장소에 macOS 빌드 자원을 제공하는 플랫폼 엔지니어링 책임자에게 적합합니다. 인증서, 개인 키, 내부 의존성 접근 범위를 관리하는 보안·배포 담당자도 대상입니다.

Mac 노드 수와 공유 범위를 정해야 하는 IT 구매 담당자라면 마지막의 조건 분기표를 사용하면 됩니다. 단순히 Runner가 온라인으로 표시되는지만 확인하는 방식은 충분하지 않습니다.

배포 첫날: 공유 풀과 전용 풀의 경계를 먼저 정합니다

GitLab CI 다중 프로젝트 공유 Mac Runner는 모든 작업을 한곳에 넣는 구조가 아닙니다. 신뢰할 수 있는 프로젝트의 일반 컴파일과 테스트는 공유 풀에 배치할 수 있지만, 정식 서명과 신뢰 영역이 다른 프로젝트는 별도 Mac으로 보내야 합니다.

핵심은 공유 하드웨어와 공유 신원을 구분하는 것입니다. 같은 Mac을 사용하더라도 작업 라벨, 서비스 계정, 사용자 홈, Keychain, 서명 자격 증명은 같은 경계로 취급하면 안 됩니다.

GitLab은 macOS 설정에서 Shell executor를 사용합니다. 공식 문서도 Shell executor의 작업 격리가 제한적이며, 같은 호스트의 다른 프로젝트 코드에 접근할 가능성이 있다고 설명합니다. 따라서 신뢰된 빌드에만 사용해야 합니다. GitLab의 macOS Runner 설정 문서Shell executor의 보안 범위 설명을 배포 승인 전에 함께 확인해야 합니다.

작업 유형 공유 Mac Runner 전용 Mac Runner 배포 판단
같은 조직의 일반 컴파일 가능 선택 사항 보호된 프로젝트만 공유
내부 테스트와 재현 가능한 캐시 가능 선택 사항 캐시를 비밀 정보와 분리
다른 부서의 저장소 주의 권장 별도 서비스 계정 검토
외부 기여 코드 부적합 필요 공유 호스트에 넣지 않음
정식 앱 서명과 배포 부적합 필요 보호된 작업만 허용

GitLab Runner의 범위는 project runner, group runner, instance runner의 세 가지 방식으로 나뉩니다. 여러 저장소를 관리하더라도 첫 배포는 승인된 프로젝트만 연결하는 group runner가 적합합니다. 전체 조직에 노출되는 instance runner를 먼저 열면 허용 범위를 추적하기 어려워집니다. Runner 범위 관리 문서에서 연결 대상을 확인하십시오.

첫 번째 마일스톤: 첫 한 시간에 라우팅을 고정합니다

첫 단계는 Runner를 등록하는 것이 아니라 어떤 작업이 어느 노드로 가는지 고정하는 일입니다.

  1. 공유 빌드용 Mac과 전용 서명용 Mac을 별도 Runner로 등록합니다.
  2. 공유 노드에는 일반 빌드와 테스트에만 사용하는 라벨을 부여합니다.
  3. 서명 노드에는 보호된 작업만 사용할 수 있는 별도 라벨을 부여합니다.
  4. Protected Runner와 보호된 브랜치 또는 태그를 연결합니다.
  5. YAML에서 라벨이 없는 작업이 공유 Mac에 우연히 들어가지 않도록 태그 실행을 강제합니다.
  6. 정상 빌드와 배포 작업을 각각 실행해 예상 노드로 갔는지 기록합니다.
  7. 권한이 없는 프로젝트가 서명 노드를 요청했을 때 거부되는지 확인합니다.

라벨은 보안 경계가 아닙니다. 라벨은 작업을 어느 Runner가 받을지 정하는 라우팅 조건입니다. 접근 통제와 보호된 브랜치 정책을 함께 적용해야 하며, GitLab의 Runner 설정과 태그 규칙에 맞춰 허용 프로젝트 목록을 남겨야 합니다.

최소 검증용 구성은 다음처럼 유지하는 편이 좋습니다.

build:
  tags:
    - macos-shared
  script:
    - whoami
    - pwd
    - xcodebuild -version

이 단계에서 관리자 계정으로 실행한 결과를 제출하면 안 됩니다. 실제 GitLab Runner 서비스 계정의 사용자, 홈 경로, 권한, 환경 변수로 실행된 로그만 승인 증거로 사용해야 합니다.

첫 번째 파이프라인: 계정과 디렉터리를 분리합니다

GitLab Runner가 사용하는 macOS 계정은 GitLab 프로젝트의 논리적 범위와 다릅니다. 같은 서비스 계정으로 여러 작업이 실행되면 디렉터리를 나누어도 다른 프로젝트의 파일을 읽을 가능성이 남습니다.

다음 순서로 실제 작업을 확인합니다.

  1. Runner 서비스 계정으로 현재 사용자와 홈 경로를 출력합니다.
  2. 소스 체크아웃 경로와 임시 작업 경로를 확인합니다.
  3. 캐시 경로와 Xcode DerivedData 경로를 프로젝트별로 분리합니다.
  4. 빌드 산출물과 장기 인증 정보를 서로 다른 저장 영역으로 나눕니다.
  5. 작업이 끝난 뒤 소스, 임시 파일, 로그, 프로세스가 남는지 기록합니다.
  6. 두 번째 프로젝트에서 첫 번째 프로젝트의 파일을 읽는 시험을 실행합니다.
영역 다시 만들어도 되는 것 보호해야 하는 것 확인 방법
작업 폴더 체크아웃 소스 다른 프로젝트의 소스 작업 뒤 목록 비교
캐시 의존성 캐시 토큰이 포함된 파일 캐시 내용과 만료 정책 검사
DerivedData 컴파일 중간 산출물 서명 결과와 배포 산출물 프로젝트별 경로 확인
사용자 홈 임시 설정 개인 키와 인증 설정 서비스 계정 권한 확인
프로세스 빌드 프로세스 오래 남은 백그라운드 작업 작업 전후 목록 비교

캐시는 속도를 위한 데이터이지 비밀 저장소가 아닙니다. GitLab의 CI/CD 캐시 동작 문서처럼 캐시 키와 저장 범위를 설계하되, 토큰이나 개인 키를 캐시에 넣지 않아야 합니다.

디렉터리 분리는 실수로 다른 파일을 사용하는 일을 줄여 줍니다. 그러나 같은 Shell 계정에서 실행되는 스크립트가 다른 경로를 읽는 것까지 막지는 못합니다. 이 차이를 배포 문서에 명시해야 합니다.

두 번째 프로젝트 연결 시점: 교차 오염을 일부러 만듭니다

첫 번째 프로젝트가 성공했다고 바로 여러 저장소를 연결하면 안 됩니다. 두 번째 프로젝트를 추가할 때는 정상 동작보다 잔존 자산을 찾는 시험을 먼저 해야 합니다.

확인할 항목은 다음과 같습니다.

  • 이전 프로젝트의 소스와 빌드 산출물이 남아 있는지 확인합니다.
  • 환경 변수와 사용자 설정 파일에 다른 프로젝트 값이 남아 있는지 확인합니다.
  • 종료되지 않은 빌드 프로세스가 다음 작업을 점유하는지 확인합니다.
  • Homebrew 상태와 공용 의존성 변경이 다른 작업에 영향을 주는지 확인합니다.
  • 시뮬레이터와 동일한 DerivedData 경로가 동시에 사용되는지 확인합니다.
  • 캐시를 삭제하기 전과 후의 파일 목록을 비교합니다.
  • 동시 작업에서 한 프로젝트의 산출물이 다른 프로젝트에 표시되는지 확인합니다.
시험 항목 통과 기준 실패 시 조치
잔존 소스 다음 작업에서 이전 소스가 보이지 않음 작업 공간 초기화 또는 노드 분리
환경 변수 다른 프로젝트의 값이 없음 변수 범위와 정리 절차 수정
백그라운드 프로세스 작업 종료 뒤 남은 프로세스가 없음 강제 정리와 전용 노드 검토
캐시 허용한 의존성만 재사용 캐시 키와 저장 범위 축소
동시 실행 파일과 시뮬레이터 충돌이 없음 동시성 제한 또는 노드 추가

서로 다른 부서나 신뢰 영역의 프로젝트가 같은 작업 공간, 계정, 내부망을 사용한다면 이 단계에서 공유를 중지해야 합니다. 독립 Runner 계정만으로 위험이 충분히 줄지 않는다면 독립 Mac 노드로 전환합니다.

생산 배포 전: Keychain과 서명 노드를 분리합니다

정식 iOS 배포에는 인증서 개인 키, 프로비저닝 프로파일, App Store 연결 자격 증명, 내부 저장소 토큰이 함께 관여할 수 있습니다. 이 자산을 일반 테스트 작업과 같은 사용자 홈이나 캐시에 두면 공유 풀의 위험 범위가 커집니다.

Apple의 Keychain Services 문서접근 제어 목록 문서를 기준으로 항목별 호출 주체와 허용 작업을 정의해야 합니다. Keychain 항목 접근 제한 문서도 함께 검토하십시오.

다만 Keychain 접근 제어가 같은 Runner 계정에서 실행되는 임의 스크립트의 위험을 자동으로 없애지는 않습니다. 따라서 다음과 같이 설계합니다.

  1. 일반 빌드 풀에는 생산 개인 키를 저장하지 않습니다.
  2. 서명 노드는 보호된 브랜치와 태그 작업만 받도록 구성합니다.
  3. 서명 작업을 요청하는 프로젝트와 사용자를 허용 목록으로 제한합니다.
  4. 최소 서명 시험으로 올바른 앱만 처리되는지 확인합니다.
  5. 권한이 없는 프로젝트의 서명 요청이 거부되는지 기록합니다.
  6. 인증서와 토큰 교체 절차를 문서화합니다.
  7. Mac 재시작 뒤에도 자동으로 과도한 접근 권한이 복구되지 않는지 확인합니다.

이 구조에서는 일반 빌드가 중단되어도 생산 서명 노드가 함께 영향을 받지 않습니다. 반대로 서명 노드에 일반 테스트를 넣으면 보호된 경계가 다시 약해집니다.

첫 주 마일스톤: 공유 유지와 분리를 기록으로 결정합니다

첫 주에는 온라인 상태보다 운영 증거를 수집해야 합니다. 각 프로젝트의 대기 기록, 동시 실행 충돌, 정리 결과, 재시작 뒤 복구 결과, 서명 작업 점유 상황을 같은 형식으로 남깁니다.

시간, 처리량, 용량, 비용과 같은 수치는 기업 기록이나 실제 측정값이 없으면 단정하지 않아야 합니다. 특정 Mac의 성능을 다른 환경의 기준처럼 사용하지 말고, 네트워크와 Xcode 버전이 달라질 때 결과가 달라질 수 있다는 점도 기록합니다.

조건 분기로 최종 배포를 결정합니다

  • 모든 프로젝트가 같은 신뢰 영역에 있고, 외부 기여 코드가 없으며, 생산 키를 공유 풀에서 제외했다면 공유 빌드 풀을 유지합니다.
  • 프로젝트는 신뢰할 수 있지만 대기 충돌과 동시 실행 충돌이 반복되면 일반 빌드용 Mac을 추가합니다.
  • 부서가 다르거나 내부망 접근 범위가 다르면 독립 Runner 계정부터 검토하고, 읽기 시험이 실패하면 독립 Mac으로 전환합니다.
  • 외부 기여 코드나 비보호 브랜치가 생산 자산에 접근할 수 있으면 공유 풀에서 제외합니다.
  • 정식 서명이 필요하면 전용 Mac Runner로 이동시키고, 보호된 작업만 허용합니다.
  • 일시적인 빌드 증가만 문제라면 고정 장비를 즉시 구매하기보다 공유 기본 용량과 탄력적인 원격 Mac을 함께 시험합니다.

현재 한 대의 Mac에서 일반 빌드, 비보호 브랜치, 정식 서명을 모두 처리하고 있다면 장비를 더 빠르게 만드는 것보다 역할을 분리하는 일이 먼저입니다. VMSPIN의 원격 Mac 운영 환경을 활용해 공유 빌드 노드와 전용 배포 노드를 각각 시험하고, 실제 로그를 기준으로 확대 여부를 판단할 수 있습니다. 필요하다면 Mac 렌탈 요금과 기간을 확인하되, 장기 고정 부하나 물리 장비 접근이 필요한 조직에는 직접 구매가 더 적합할 수 있습니다.

자주 묻는 운영 판단

FAQ에서는 공유 범위, Shell executor, Runner 종류, 캐시와 Keychain, 정식 서명 노드의 판단을 각각 분리해 답해야 합니다. 같은 Mac을 쓴다는 사실만으로 같은 보안 경계를 공유할 수 있는 것은 아닙니다.

일반적으로 공유 풀의 장점은 여러 프로젝트가 유휴 자원을 함께 사용할 수 있다는 점입니다. 단점은 작업 정리 실패, 계정 권한, 잔존 프로세스, 캐시 오염을 지속적으로 감시해야 한다는 점입니다. 전용 풀은 자원과 자격 증명 경계를 명확히 하지만 노드 수와 운영 비용이 늘어날 수 있습니다.

결국 GitLab CI 다중 프로젝트 공유 Mac Runner는 신뢰된 일반 빌드에만 적용하고, 생산 서명과 신뢰 영역이 다른 프로젝트는 독립 Mac Runner로 분리해야 합니다. 라벨, Protected Runner, 디렉터리 분리는 필요한 통제이지만 완전한 호스트 격리를 대신하지 않습니다. 공유 풀과 전용 풀을 실제 프로젝트 목록에 맞춰 나누는 것이 단일 Mac을 무리하게 확대하는 것보다 안전한 출발점입니다.