빌드가 끝났는데 이전 작업의 프로세스와 서명 파일이 남아 있다면, Runner는 온라인이어도 안전하지 않습니다. 이번 주에는 공개 저장소와 신뢰하지 않는 코드를 자체 호스팅 Mac Runner에서 차단하고, 신뢰된 저장소만 격리된 Runner Group에 배정해야 합니다.

공개 저장소나 신뢰하지 않는 풀 리퀘스트는 실행 대상에서 제외합니다. 사설 저장소도 호출 권한, 작업 라우팅, 서명 노드 분리와 작업 후 정리를 모두 확인한 뒤에만 운영에 넣습니다. 재구축하거나 완전히 정리할 수 없는 공유 Mac은 낮은 권한 빌드만 맡기고, 서명과 배포는 별도 노드로 옮깁니다.

이 글은 GitHub Actions에서 Xcode 빌드와 Simulator 테스트를 실행하는 모바일 개발팀을 위한 것입니다. Runner Group, 저장소 권한, 네트워크 경계를 관리하는 플랫폼 및 DevOps 담당자에게도 적용됩니다. Apple 서명 인증서, macOS Keychain, 프로덕션 배포 승인을 맡은 보안 담당자도 함께 확인해야 합니다.

01

온라인 상태와 안전한 상태는 다릅니다

GitHub Actions 자체 호스팅 Mac Runner 안전 여부는 Runner 화면의 온라인 표시로 판단할 수 없습니다. 자체 호스팅 Runner는 작업이 끝난 뒤에도 파일, 프로세스, 사용자 설정과 자격 증명이 남을 수 있는 호스트입니다. GitHub도 자체 호스팅 Runner가 호스팅 Runner와 같은 임시 격리를 보장하지 않는다고 설명하며, 공개 저장소의 신뢰하지 않는 코드가 호스트를 지속적으로 변경할 위험을 경고합니다. GitHub의 안전한 사용 안내를 먼저 기준 문서로 삼아야 합니다.

공유 Mac에서 특히 문제가 되는 지점은 다음과 같습니다.

  • 작업 폴더를 지워도 DerivedData, 임시 파일, 로그가 다른 경로에 남을 수 있습니다.
  • 백그라운드 프로세스가 다음 작업의 환경 변수, 파일 시스템, 네트워크를 볼 수 있습니다.
  • 서명 인증서와 배포 토큰이 같은 사용자 계정과 Keychain에 있으면 빌드 코드가 배포 권한까지 만질 수 있습니다.
  • 내부 패키지 저장소, 사내 API, 관리 네트워크에 접근할 수 있다면 Runner 탈취가 옆 시스템으로 이어질 수 있습니다.
  • 노드를 빠르게 재구축할 수 없다면 이상 징후가 발견된 뒤에도 민감한 작업을 계속 배정하게 됩니다.

공개 저장소의 코드도 자체 호스팅 Runner에서 실행할 수 있나요?

운영용으로는 허용하지 않는 편이 맞습니다. 공개 저장소의 기여 코드와 신뢰하지 않는 풀 리퀘스트는 서명 키, 내부 파일, Runner의 장기 설정을 노릴 수 있습니다. 공개 저장소 검증이 꼭 필요하다면 민감한 자격 증명이 없고 외부 네트워크가 제한된 별도 시험 노드에서만 실행합니다. 통과 기준은 빌드 성공이 아니라 호스트 변경, 잔여 프로세스, 파일과 네트워크 접근까지 확인하는 것입니다.

02

저장소 신뢰도와 작업 라우팅을 함께 잠급니다

저장소가 사설인지 여부만으로 신뢰 수준을 정하면 안 됩니다. 누가 워크플로를 수정할 수 있는지, 누가 작업을 실행할 수 있는지, 누가 환경 승인을 내리는지를 목록으로 고정합니다. 사설 저장소라도 쓰기 권한이 넓거나 외부 기여 브랜치가 자동 실행되면 고위험 코드가 될 수 있습니다.

GitHub Actions의 자체 호스팅 Runner는 저장소, 조직 또는 기업 범위에 등록할 수 있습니다. Runner Group의 접근 정책과 저장소 연결을 함께 확인해야 하며, Runner Group 권한 모델 문서의 허용 범위를 그대로 기록해야 합니다.

다음 조건으로 결론을 나눕니다.

  • 조건을 만족하면 허용: 관리되는 사설 저장소이고, 워크플로 수정자와 실행 승인자가 제한되며, 전용 Runner Group과 저장소 허용 목록이 적용됩니다.
  • 일부 조건만 만족하면 격리 시험: 저장소 신뢰도는 높지만 노드 재구축이나 작업 후 정리가 자동화되지 않았습니다. 비밀값 없는 빌드와 Simulator 테스트만 배정합니다.
  • 하나라도 만족하지 못하면 차단: 공개 저장소, 신뢰하지 않는 풀 리퀘스트, 광범위한 조직 Runner Group, 서명 자산이 있는 공유 계정이 해당됩니다.

태그만으로 안전을 판단하지 않습니다. 태그는 작업을 원하는 노드로 보내는 힌트일 뿐, 저장소 접근 경계와 비밀값 보호를 대신하지 않습니다. 작업을 실행할 Runner 선택 기준에 따라 저장소 허용 목록, 그룹, 태그와 워크플로 조건을 함께 기록합니다.

03

공유 노드와 서명 노드는 분리해야 합니다

Xcode CI에서 일반 빌드 토큰과 Apple 서명 자산을 같은 Runner에 장기간 보관하지 않습니다. 일반 빌드는 컴파일, 테스트, 아티팩트 생성만 수행하게 합니다. 서명과 배포는 승인된 작업에서만 별도 Runner로 넘깁니다.

GITHUB_TOKEN도 필요한 권한만 부여합니다. 저장소 읽기, 릴리스 작성, 배포 호출을 한 번에 허용하는 구성을 기본값으로 두지 않습니다. 환경 승인은 배포 전 확인 절차를 추가하지만, 이미 호스트를 제어한 코드가 Runner 안에서 실행되는 문제를 없애지는 않습니다. 승인 전에 노드가 오염되었다면 승인 자체가 안전을 보장하지 않습니다. 환경과 승인 흐름은 GitHub 배포 환경 문서와 대조합니다.

Xcode CI의 서명 인증서는 어느 Runner에 둬야 하나요?

서명 인증서는 일반 빌드 Runner가 아니라 접근 주체와 네트워크가 제한된 독립 배포 Runner에 둡니다. 해당 노드는 승인된 저장소와 배포 작업만 받게 하고, 작업이 끝나면 임시 키와 프로파일을 폐기합니다. Apple은 코드 서명 인증서의 개인 키와 Keychain 접근 경계를 별도로 설명하고 있으므로 Apple의 코드 서명 인증서 기술 문서를 기준으로 계정과 키 저장 위치를 검토합니다.

macOS Keychain은 파일 하나를 복사해 두는 방식으로 관리하지 않습니다. 실행 계정, 키체인 잠금 상태, 접근 제어 목록, 인증서와 개인 키의 사용 주체를 확인합니다. 일반 테스트 작업이 서명 키를 읽을 필요가 없다면 해당 계정과 키체인에 접근할 수 없어야 합니다.

04

작업 흔적은 파일보다 넓게 검사합니다

Mac Runner 작업이 끝난 뒤 무엇을 지워야 하나요?

저장소 복사본만 삭제해서는 부족합니다. 다음 항목을 작업 단위로 확인합니다.

  • 저장소 디렉터리와 하위 모듈
  • DerivedData, 아카이브, 테스트 결과, 임시 내보내기 파일
  • 환경 변수와 로그에 기록된 토큰 및 인증서 경로
  • 사용자 키체인, 임시 키 파일, 프로파일과 인증서 사본
  • 백그라운드 프로세스, 에이전트, 예약 작업과 열린 포트
  • 셸 설정, 패키지 관리자 설정, Git 자격 증명과 SSH 설정
  • 네트워크 프록시, 호스트 파일, 방화벽과 원격 접근 설정

정리 스크립트가 성공했다는 로그도 충분한 증거가 아닙니다. 파일 목록, 프로세스 목록, 키체인 접근 기록, 네트워크 연결을 작업 전후로 비교합니다. 가능하면 작업마다 새 사용자 계정 또는 재구축 가능한 디스크 이미지를 사용합니다.

장기간 실행한 self-hosted runner가 오염되었는지 어떻게 판단하나요?

기준선을 만들 수 없거나 다음 항목 중 하나라도 설명하지 못하면 오염 가능성을 해소한 것으로 보지 않습니다.

  • 허용되지 않은 프로세스와 예약 작업이 없는가
  • 작업 계정 외의 키체인과 자격 증명에 변화가 없는가
  • 시스템 설정과 원격 접근 설정이 바뀌지 않았는가
  • 작업이 허용된 네트워크 외부로 연결되지 않았는가
  • 재시작 후 동일한 검증을 통과하는가

이 검사를 자동화할 수 없는 장기 실행 Mac은 민감한 작업의 배정을 중지하고 수동 검토로 전환합니다. GitHub는 손상된 자체 호스팅 Runner를 별도 위험으로 다루며, 손상된 Runner 대응 안내에서도 호스트를 신뢰할 수 없는 상태로 취급하는 방향을 제시합니다.

05

네트워크와 관리자 권한은 별도 경계로 줄입니다

빌드에 필요한 대상과 배포에 필요한 대상을 분리합니다. 패키지 저장소, 소스 저장소, 테스트 서비스, 서명 서비스, 내부 관리망을 각각 목록화합니다. Runner가 실제로 접근해야 하는 주소만 허용하고 나머지는 거부되는지 확인합니다.

매일 실행되는 작업에 관리자 권한, 전체 디스크 접근, 제한 없는 외부 네트워크를 주지 않습니다. 권한 상승이 필요한 단계가 있다면 독립 작업으로 만들고, 앞 단계의 산출물과 입력을 다시 검증합니다. 서명 작업은 빌드 결과의 해시와 저장 위치를 승인한 뒤 실행하게 합니다.

아래 체크 항목은 배포 전 증거로 보관합니다.

  • [ ] 허용된 패키지 저장소 연결은 성공합니다.
  • [ ] 금지된 내부 관리망 연결은 실패합니다.
  • [ ] 일반 빌드 계정은 서명 키에 접근하지 못합니다.
  • [ ] 서명 작업만 승인된 Keychain 항목을 사용합니다.
  • [ ] 작업 계정에 불필요한 관리자 권한이 없습니다.
  • [ ] 외부 네트워크가 필요한 단계와 그렇지 않은 단계가 분리됩니다.
  • [ ] 허용 및 거부 결과가 작업 로그와 네트워크 기록에 남습니다.

JIT 등록이나 짧은 Runner 수명은 라우팅과 등록 노출을 줄이는 데 도움을 줄 수 있습니다. 그러나 JIT 등록이 호스트 Mac을 깨끗하게 만들거나 이미 실행된 코드를 되돌린다는 뜻은 아닙니다. 자체 호스팅 Runner 운영 문서에서 제공하는 기능과 호스트 정리 책임을 구분합니다.

주의: 노드가 다시 온라인이 되었다는 사실은 복구 증거가 아닙니다. 재시작 뒤에도 계정, 프로세스, 키체인, 네트워크 경계를 다시 검사해야 합니다.

06

복구 가능성까지 확인한 뒤 운영에 넣습니다

운영 전에는 낮은 권한 빌드, 제한된 서명, 잔여물 모의 시험, 재시작 후 재검증을 순서대로 수행합니다. 실패하면 작업을 계속 배정하지 말고 원인을 기록한 뒤 노드를 재구축하거나 폐기합니다.

다음 조건으로 선택합니다.

  • 독립적인 저권한 Runner를 선택합니다: 신뢰된 저장소만 사용하고, 서명 자산이 없으며, 작업 후 정리가 자동 검증됩니다.
  • 독립 배포 Runner를 추가합니다: 프로덕션 서명, 스토어 업로드 또는 배포 토큰이 필요합니다. 일반 빌드 Runner와 계정, Keychain, 네트워크를 나눕니다.
  • 매번 재구축하는 Runner를 선택합니다: 작업 출처가 다양하거나 호스트 오염 여부를 지속적으로 증명하기 어렵습니다.
  • 관리형 실행 환경으로 돌아갑니다: 팀이 Mac 재구축, 로그 보존, 키 교체, 예비 노드 복구를 맡을 운영 역량이 없습니다.
  • 운영을 보류합니다: 공유 Mac을 정리할 수 없고, 승인된 복구 경로와 예비 노드가 없습니다.

운영 증거에는 허용 및 거부 작업 결과, 작업 전후 파일 목록, 프로세스 검사, Keychain 접근 결과, 네트워크 허용 목록, 재시작 뒤 검증 결과를 포함합니다. 이 자료가 없으면 Runner Group이 올바르게 설정되어 있어도 승인하지 않습니다.

운영 방식 맡겨도 되는 작업 반드시 분리할 것 중지 기준
공유 Mac 비밀값 없는 빌드와 테스트 서명 키, 배포 토큰, 내부망 작업 흔적을 자동 검증하지 못함
전용 빌드 Runner 신뢰된 저장소의 Xcode 빌드와 테스트 프로덕션 서명 계정 허용 목록 밖 저장소가 작업을 호출함
독립 배포 Runner 승인된 서명과 배포 일반 빌드 계정과 네트워크 키체인 또는 계정 경계가 확인되지 않음
매번 재구축하는 Runner 출처가 다양한 시험 작업 재사용 자격 증명 재구축과 복구 로그가 없음

현재 사내 Mac을 계속 공유하는 방식은 초기 비용을 줄일 수 있지만, 저장소 간 읽기 경계가 약하고, 작업 후 정리 누락을 확인하기 어렵고, 고장이나 오염 뒤 복구 시간이 길다는 단점이 있습니다. 가상화나 Linux 기반 실행 환경도 Mac 전용 Xcode 도구와 실제 서명 흐름을 그대로 대신하지 못합니다. 이런 조건에서 격리된 실제 Mac이 필요하다면 MESHLAUNCH의 원격 Mac 대여 방식을 비생산 저장소로 먼저 검증하는 편이 낫습니다. 다만 장기간 고정된 고강도 부하, 직접 연결해야 하는 물리 장치, 조직 내부망의 특수한 규정이 핵심이면 자체 전용 장비가 더 적합할 수 있습니다.

처음부터 프로덕션 배포를 옮기지 않습니다. Mac mini 대여 비용과 조건을 확인한 뒤 독립 계정, 재시작 복구, 노드 초기화, 허용 및 거부 네트워크 결과를 먼저 기록합니다. 그 증거가 남고 서명 노드의 경계까지 확인된 경우에만 실제 배포 작업을 단계적으로 이전합니다.