macOS의 DevToolsSecurity와 무인 CI의 디버거 인증

Mac에서 Xcode나 터미널로 빌드한 프로그램에 디버거를 붙이거나 Instruments를 실행하면, 다른 프로세스를 제어해도 되는지 묻는 «Developer Tools Access» 인증 창이 뜰 수 있어요. 내 Mac에서는 암호를 넣으면 끝나요. 사람이 없는 테스트나 화면 없는 CI/CD 러너에서는 그 창이 입력을 기다리는 동안 작업이 멈춰요.

이 창을 미리 없애는 명령이 sudo DevToolsSecurity -enable이에요. 이 명령이 무엇을 바꾸는지와, 켠 뒤에도 인증이 남을 때 볼 곳을 정리했어요. 2026년 10월 4일에 macOS 27.0.1에서 읽기 전용 명령으로 확인한 내용은 따로 표시했어요. -enable과 그룹 추가 명령은 이번에 다시 실행하지 않았어요.

디버거가 인증을 요구하는 이유

macOS는 프로세스의 메모리를 서로 격리해요. 한 프로세스가 다른 프로세스를 멈추거나, 메모리를 읽고 쓰거나, 코드를 주입하는 일은 제한돼요.

lldb와 Instruments는 분석하려면 대상 프로세스에 접근해야 해요. XNU의 task_for_pid로 대상의 Mach task 포트를 얻고, 그 포트로 한 줄씩 실행하거나 메모리를 덤프해요. 권한이 모자라면 요청이 거부되거나 관리자 암호 인증을 거쳐요. 이 인증을 담당하는 것이 Authorization Services이고, 규칙은 /var/db/auth.db에 저장돼요.

DevToolsSecurity가 바꾸는 규칙

/usr/sbin/DevToolsSecurity는 system.privilege.taskport라는 권한의 규칙을 바꿔요. 이전 판에서는 켜기 전에 로그인 암호나 root 증명을 요구하고, 켠 뒤에는 _developer 그룹과 연결된다고 설명했어요. 이 가운데 켜기 전의 동작은 이번에 확인하지 못했어요.

켠 상태의 규칙을 security authorizationdb read system.privilege.taskport로 읽어 봤어요. 읽은 값은 이래요(macOS 27.0.1).

  • class는 user예요.
  • group은 _developer예요.
  • authenticate-user는 true, allow-root는 false예요.
  • timeout은 36000이에요.

이 글의 이전 판에서는 켠 뒤의 클래스를 rule이라고 적었는데, 이번에 읽은 값은 user였어요. 규칙의 설명문에는 이 권한이 task_for_pid에 쓰이고, 요청하는 프로그램과 대상 프로그램을 같은 사용자가 실행할 때에만 적용된다고 적혀 있어요. 다른 사용자의 프로그램에 대한 접근은 허가하지 않아요. 켜기 전의 값은 이번에 확인하지 못했어요. 확인한 Mac에서는 이미 켜져 있었어요.

상태는 -status로 확인해요

인자 없이 /usr/sbin/DevToolsSecurity만 실행하면 상태를 보여 주는 것이 아니에요. 사용법을 보면 기본 동작이 -enable이에요.

없는 옵션을 넣어서 사용법을 출력한 결과예요.

$ /usr/sbin/DevToolsSecurity -help
DevToolsSecurity: unrecognized option `-help'
Changes the security authorization policies for developer systems
Usage: /usr/sbin/DevToolsSecurity [-verbose] [-enable | -disable | -status]
    -enable  :: (default) enable developer mode policies
    -disable :: return policies to system default
    -status  :: prints out whether or not developer mode policies are in effect
    -verbose :: makes output more verbose

상태만 보려면 -status를 써요.

$ /usr/sbin/DevToolsSecurity -status
Developer mode is currently enabled.

이전 판에서는 인자 없이 실행해서 enabled 여부를 본다고 적었어요. 그 설명은 틀렸고, 위와 같이 고쳤어요.

켠 뒤에도 인증이 남을 때

-enable을 실행한 뒤에도 터미널의 lldb나 VS Code의 C++ 디버깅에서 인증 창이 뜨거나 attach failed가 나올 수 있어요. 이때 볼 곳은 계정이 _developer 그룹에 들어 있는지예요.

현재 로그인한 계정을 그룹에 더하는 명령이에요.

# 현재 로그인된 계정을 _developer 그룹에 강제 멤버십 추가
sudo dscl . append /Groups/_developer GroupMembership $(whoami)

추가한 뒤에는 터미널을 다시 열거나 로그아웃했다가 로그인하기를 권해요. 그룹의 구성원은 dscl . read /Groups/_developer GroupMembership으로 볼 수 있어요.

이 부분은 제가 직접 원인을 비교해 본 것이 아니에요. 확인한 Mac에서는 _developer 그룹에 GroupMembership 키가 아예 없었어요.

$ dscl . read /Groups/_developer GroupMembership
No such key: GroupMembership

이 키가 없는 Mac에서 디버거 연결이 어떻게 동작하는지, 그룹 가입이 필요한 조건이 정확히 무엇인지는 확인하지 않았어요. 그룹에 넣는다고 모든 attach failed가 풀린다고 볼 근거도 없어요.

무인 러너에서 생기는 일

모바일 배포 자동화에는 Mac mini나 클라우드의 macOS 가상머신을 러너로 써요. Xcode를 새로 설치하거나 OS를 올린 뒤에 이 조치를 빠뜨리는 경우가 문제예요.

Appium이나 Xcode UI Test가 테스트 앱을 설치하고 디버깅 연결을 시도하면 인증 요청이 백그라운드의 GUI에 떠요. 러너에는 응답할 사람이 없어요. 작업은 설정된 제한 시간이 지난 뒤에야 끝나고, 제한 시간이 없는 러너라면 계속 기다려요. 이 흐름을 재현해서 시간을 잰 결과는 이 글에 싣지 않았어요.

그래서 러너를 준비하는 스크립트에서 두 가지를 함께 실행해요.

# 개발자 도구 액세스 허용 활성화
sudo /usr/sbin/DevToolsSecurity -enable

# 빌드 실행 에이전트 계정을 개발자 그룹에 병합
sudo dscl . append /Groups/_developer GroupMembership build_agent_user

build_agent_user는 러너가 쓰는 계정 이름으로 바꿔요. 러너 설치 안내에도 활성화 명령을 넣어 두면 새 장비에서 빠뜨리지 않아요. 모든 서버에서 두 명령이 다 필요하다는 근거는 없어요. 테스트 앱을 기기나 시뮬레이터에 설치하는 일과 Mac의 task 포트 인증이 어떻게 이어지는지도 직접 측정하지 않았어요.

보안에서 내주는 것

이 설정은 인증 단계를 하나 줄여요. 그만큼 같은 사용자로 실행되는 다른 프로세스의 메모리를 개발 도구가 다룰 수 있는 범위가 넓어져요. 장비에 물리적으로 접근할 수 있는 사람을 관리하고, 출처를 알 수 없는 바이너리나 코드를 그 장비에서 실행하지 않아야 해요.

iPhone이나 iPad의 Developer Mode와는 대상이 달라요. 기기의 Developer Mode는 Xcode로 빌드해 실행하는 앱처럼 로컬에서 설치한 앱을 그 기기에서 실행하도록 허용하는 설정이에요. App Store나 TestFlight로 설치하는 앱에는 영향을 주지 않아요. 이 글의 설정은 Mac에서 lldb 같은 도구가 다른 프로세스를 제어하는 권한이에요.

이번에 읽은 값은 macOS 27.0.1 한 대의 것이고, 이미 켜져 있어서 켜기 전의 값은 확인하지 못했어요. macOS 버전별로 비교한 결과도 이 글에 싣지 않았어요. 서명된 개발 도구만 허용된다는 조건이 정확히 어떤 서명을 뜻하는지도 문서에서 확인하지 못했어요.