인터넷에서 받은 CLI 도구나 오픈소스 앱을 처음 실행할 때 "확인되지 않은 개발자가 배포했기 때문에 열 수 없습니다"라는 창을 만나는 경우가 잦다. 나도 GitHub 릴리스에서 받은 바이너리를 터미널에서 돌리다 killed: 9로 끝나서 한참 헤맨 적이 있다. macOS Sequoia로 올라오면서 예전에 쓰던 우클릭 열기가 사라져 더 당황스럽다. 이 글에서는 그 차단이 어디서 오는지, 그리고 명령줄에서 어떻게 안전하게 푸는지를 정리한다.
결론부터 말하면, 이 차단은 파일에 붙은 com.apple.quarantine 확장속성 때문이다. 신뢰할 수 있는 출처라면 xattr -d com.apple.quarantine 파일로 속성을 지우면 열린다. Apple Silicon에서 서명 없는 바이너리가 그래도 killed: 9로 죽으면 codesign --force -s - 파일로 애드혹 서명을 붙인다. 차단 사유는 spctl로 먼저 확인한다.
1. 개요: Gatekeeper와 quarantine 확장속성
Gatekeeper는 macOS가 다운로드한 앱을 실행하기 전에 서명과 공증(notarization) 상태를 검사하는 보안 장치다. 검사에 실패하면 실행을 막고 앞의 경고창을 띄운다.
이때 판단 기준이 되는 것이 com.apple.quarantine이라는 확장속성(extended attribute)이다. Safari, 메일, 메시지 같은 앱이 파일을 내려받으면 LaunchServices가 그 파일에 이 꼬리표를 붙인다. Gatekeeper는 꼬리표가 붙은 파일을 처음 열 때만 검사를 수행한다. 즉 차단을 푸는 방법은 크게 두 갈래다. 꼬리표 자체를 지우거나, 서명 상태를 바로잡는 것이다.
아래에서는 꼬리표 확인, xattr로 제거, spctl과 codesign으로 서명 처리, 그리고 Sequoia에서 달라진 점을 차례로 살펴본다.
2. quarantine 꼬리표가 붙었는지 확인한다
먼저 파일에 확장속성이 실제로 붙어 있는지 본다. xattr -l은 속성 이름과 값을 함께 보여준다.
$ xattr -l ~/Downloads/mytool com.apple.quarantine: 0181;66b7c3a0;Safari;1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D
값은 세미콜론으로 나뉜 네 조각이다. 순서대로 플래그(16진수), 다운로드 시각(16진수 타임스탬프), 붙인 에이전트 이름(여기서는 Safari), 이벤트 UUID다. 특정 속성 값만 보려면 -p를 쓴다.
$ xattr -p com.apple.quarantine ~/Downloads/mytool 0181;66b7c3a0;Safari;1A2B3C4D-5E6F-7A8B-9C0D-1E2F3A4B5C6D
출력에 com.apple.quarantine이 없다면 이 파일은 Gatekeeper 검사 대상이 아니다. 그래도 실행이 막힌다면 원인은 꼬리표가 아니라 서명 쪽이므로 4절로 넘어간다.
3. xattr로 quarantine 속성을 제거한다
출처를 신뢰한다면 꼬리표를 지운다. 단일 파일은 -d로 해당 속성만 제거한다.
$ xattr -d com.apple.quarantine ~/Downloads/mytool
앱 번들(.app)은 디렉터리 안에 실행 파일과 리소스가 여러 개 들어 있으므로 재귀 옵션 -r을 함께 쓴다.
$ sudo xattr -dr com.apple.quarantine /Applications/Foo.app
여기서 한 번 걸렸다. -d 없이 -r만 주면 아무 일도 일어나지 않는다. 삭제 의도인 -d와 재귀인 -r을 -dr로 묶어야 번들 내부 파일까지 지운다.
속성이 이미 없는 파일에 -d를 걸면 다음 에러가 난다. 이건 실패가 아니라 지울 게 없다는 뜻이다.
$ xattr -d com.apple.quarantine ~/Downloads/mytool xattr: No such xattr: com.apple.quarantine
quarantine뿐 아니라 파일에 붙은 확장속성을 전부 비우고 싶으면 -c를 쓴다. 번들은 -cr로 재귀 적용한다. 다만 다른 속성까지 싹 지우므로, 정확히 quarantine만 노린다면 -d를 쓰는 편을 권한다.
$ xattr -cr /Applications/Foo.app
"응용 프로그램이 손상되었기 때문에 열 수 없습니다"라는 메시지도 대부분 같은 원인이다. 정상 다운로드인데 이 문구가 뜬다면 위의 -dr 제거로 풀리는 경우가 많다.
4. spctl로 차단 사유를 확인하고 codesign으로 서명한다
spctl은 Gatekeeper의 평가 하위시스템을 다루는 명령이다. 실행을 막기 전에 왜 막히는지 먼저 진단하는 데 쓴다. -a는 평가 요청, -t exec는 실행 파일 검사, -vvv는 상세 출력이다.
$ spctl -a -vvv -t exec /Applications/Foo.app /Applications/Foo.app: rejected source=Unnotarized Developer ID origin=Developer ID Application: Example Corp
source= 줄이 사유다. Unnotarized Developer ID는 서명은 됐지만 공증이 없다는 뜻이고, no usable signature는 서명 자체가 없다는 뜻이다. 앞의 quarantine 제거로 풀리는 것은 대개 이 검사를 건너뛰게 만들기 때문이다.
시스템 전체 평가 상태는 --status로 본다.
$ spctl --status assessments enabled
서명이 아예 없는 실행 파일은 Apple Silicon(arm64)에서 문제가 더 크다. arm64 바이너리는 최소한 애드혹 서명이라도 있어야 커널이 실행을 허용한다. 서명 없는 바이너리를 터미널에서 돌리면 killed: 9로 즉시 죽는다. 이때는 quarantine 제거만으로는 부족하고 서명을 붙여야 한다.
먼저 현재 서명 상태를 확인한다.
$ codesign -dv --verbose=4 ./mytool ./mytool: code object is not signed at all
애드혹 서명은 -s -로 붙인다. 하이픈 하나가 식별자 없는 애드혹 서명을 뜻한다. --force는 기존 서명을 덮어쓰고, 번들이면 --deep으로 내부까지 서명한다.
$ codesign --force -s - ./mytool $ codesign --force --deep -s - /Applications/Foo.app
서명이 제대로 붙었는지 검증한다.
$ codesign -v ./mytool && echo OK OK
애드혹 서명은 이 기기에서 실행을 허용시킬 뿐, 다른 사용자에게 배포할 신뢰를 만들어 주지는 않는다. 배포용이라면 Developer ID 인증서 서명과 Apple 공증이 정답이다.
5. Sequoia에서 달라진 점
macOS Sequoia(15)부터 예전 방식 두 가지가 막혔다. 첫째, Finder에서 앱을 우클릭해 "열기"로 Gatekeeper를 우회하던 메뉴가 사라졌다. 지금은 앱을 한 번 실행해 차단당한 뒤 시스템 설정 > 개인정보 보호 및 보안으로 가서 "확인 없이 열기" 버튼을 눌러야 한다.
둘째, spctl로 Gatekeeper를 통째로 끄는 길이 좁아졌다. 예전의 --master-disable은 --global-disable로 이름이 바뀌었고, Sequoia에서는 평가 하위시스템의 전역 상태나 규칙 데이터베이스를 명령으로 수정하는 동작이 더 이상 지원되지 않는다. 관리 옵션(MDM 구성 프로파일)이 있어야 전역으로 끌 수 있다.
그래서 Sequoia에서는 Gatekeeper를 전역으로 끄는 대신, 대상 파일에만 xattr로 quarantine을 지우거나 필요한 파일만 서명하는 접근이 현실적이다. 개별 처리가 시스템 전체 보안을 낮추지 않아 더 안전하기도 하다.
6. 안전하게 처리하는 순서
차단을 만나면 다음 순서로 접근하는 것을 권한다.
- 출처 확인이 먼저다. quarantine 제거는 Gatekeeper 검사를 건너뛰는 행위다. 신뢰할 수 있는 배포처에서 받은 파일에만 적용한다.
- 사유부터 진단한다.
spctl -a -vvv -t exec로 서명 문제인지 공증 문제인지 본다. - 대상만 좁혀 처리한다.
spctl --global-disable로 전체를 끄지 말고, 문제 파일에만xattr -dr com.apple.quarantine을 적용한다. - arm64에서 죽으면 서명한다.
killed: 9가 나면codesign --force -s -로 애드혹 서명을 붙인다.
명령 출력의 값은 파일과 macOS 버전에 따라 달라질 수 있다. 확장속성 이름과 옵션 동작은 동일하다.