"자체 서명한 로컬 신원은 커밋해도 돼. 애플이 믿어주는 인증서는 절대 안 돼."
이 방식이 푸는 문제
애드혹 서명한 앱은 requirement가 자기 해시로 돼 있어서, 다시 빌드할 때마다 TCC와 키체인 입장에선 새 앱이야. 손쉬운 사용 권한을 또 묻고, 키체인 항목의 "항상 허용"은 절대 안 남아. 만든 Mac 밖으로 나갈 일 없는 Mac 앱에 대해 가족이 내린 답은 자체 서명한 코드 서명 신원 하나야. 네이티브 앱, 런처, 권한 쓰는 헬퍼가 전부 같이 쓰고, 빌드하는 모든 Mac의 로그인 키체인에 들어가 있어. 그걸로 서명하면 앱의 designated requirement가 identifier "…" and certificate leaf = H"…"가 돼. 다시 빌드해도 같고, 같은 인증서로 서명하는 모든 Mac에서 같아.
왜 애플 인증서가 아니냐면
애플 Developer ID 인증서도 안정적인 requirement를 만들어 주고, 다른 사람에게 배포하려면 그 인증서가 필요해(이 트랙 마지막 레슨에서 다뤄). 근데 애플이 믿어주고, Gatekeeper가 받아주고, 공증까지 되는 인증서는 자격 증명이야. 유출되면 누군가 macOS가 네 서명으로 믿는 소프트웨어를 내보낼 수 있어. 자체 서명 신원은 그걸 믿는 Mac 바깥에선 아무것도 못 열어. Gatekeeper는 거부하고, 계정도 서버도 열리지 않아. 대신 그 Mac들 안에선 TCC 권한과 키체인 접근 목록이 가리키는 게 바로 이 신원이야. 그래서 개인 키를 가진 사람은 같은 식별자로 서명한 바이너리에 그 권한을 그대로 물려받게 할 수 있어. 결국 피해 범위는 비공개 레포에 더해 이 Mac들에서 코드를 돌릴 수단까지 가진 경우인데, 둘 다 가진 사람은 그 권한이 지키는 걸 이미 손에 쥔 거야. 가족이 자체 서명 신원은 비공개 레포에 두면서, 신뢰받는 인증서는 어디에도 절대 커밋하지 않는 이유가 이거야.
치르는 값, 솔직하게
- Gatekeeper가 안 믿어줘. 앱은 인증서가 깔려 있고 네가 직접 실행하는 Mac에서만 돌아. 남의 Mac에선 안 돼.
codesign이 키를 처음 쓸 때 Mac마다 키체인이 "codesign wants to use key …"라고 한 번 물어봐. Mac마다 한 번씩 항상 허용을 눌러.- 앱을 애드혹에서 안정적인 신원으로 옮긴 뒤엔 옛 권한을 한 번 초기화해(
tccutil reset Accessibility com.example.spark). 옛 cdhash에 묶인 권한은 새 requirement와 안 맞거든. 한 번만 다시 허용하면 그 뒤로는 계속 유지돼. - 인증서를 다시 만들면 leaf 해시가 바뀌어서, 모든 Mac이 한 번씩 다시 허용하고 모든 앱을 다시 빌드해야 해.
신원 찾기의 함정
security find-identity -v -p codesigning으로 신원을 확인하는 빌드 스크립트는 신원이 없다고 잘못 결론 내려. -v는 신뢰할 수 있는 루트로 이어지는 유효한 신원만 남기거든. 자체 서명 신원은 CSSMERR_TP_NOT_TRUSTED로 보고돼서 목록에서 빠져. 그러니 -v를 빼. 가족 받아쓰기 앱은 이 함정을 찾아내기 전까지, 이것 하나 때문에 애드혹 서명에 머물면서 빌드할 때마다 권한을 다시 물었어.