C.W.K.
Stream
Lesson 05 of 05 · published

TCC signed launcher

~11 min · war-story, permissions, code-signing, process-group

Level 0Empty Shelf
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"권한이 네 코드한테 거부된 게 아냐. 네 코드의 identity 한테 거부된 거고 — 벌거벗은 인터프리터엔 그게 거의 없어."

같은 Python, 다른 두 답

두 번째 전쟁 이야기, 지난번과 같은 미치는 모양. executor 는 마운트된 볼륨에서 영상 아카이브를 읽어야 해 — 그건 현대 macOS 에선 유저가 full-disk 파일 접근을 승인해야 해. 승인하고, SSH 로 들어가, Python 을 돌리면, 아카이브를 완벽히 읽어. 그다음 서비스 매니저가 정확히 같은 인터프리터를, 같은 기계에서 띄우면, 운영체제가 파일 접근을 거부해.

이유는 권한 시스템이 코드에 접근을 승인하는 게 아니라서야. identity — 코드 서명된 애플리케이션, 책임 프로세스에 귀속된 — 에 승인해. 인터랙티브 셸 세션은 시스템이 이미 신뢰하는 identity 를 지니고, 네 Python 이 그 컨텍스트를 상속해. 서비스 매니저가 띄운 벌거벗은 인터프리터 바이너리는 그런 승인 가능한 identity 를 안 지녀서, 요청이 유저가 승인한 적 없는 것에 착지하고, 거부돼.

그리고 놓치기 쉬운 방식으로 더 나빠져: 그 Python 바이너리에 직접 접근을 승인해봐도, 일상적 환경 업데이트가 그 바이너리를 교체할 수 있고 — 그 특정 바이너리에 붙었던 승인이 증발해. 다음에 툴링을 업데이트하면 조용히 만료되는 권한을 지은 거야. 갈아끼울 수 있는 파일에 준 승인은 네가 고르지도 않았고 통보받지도 않을 만료일이 붙은 승인이야.

고침: 승인이 살 안정된 identity 를 줘

Recall 의 답은 OS 한테 교체 가능한 파일을 믿으라고 하길 그만두는 거야. 서비스 매니저가 안정된 bundle identifier 를 가진 작고, 기계-로컬이고, 코드 서명된 애플리케이션 번들을 host 해. 그 launcher 가 시스템이 보는 거고; 책임 부모 프로세스고, 런타임 Python 을 자식으로 spawn 해. full-disk 접근은 안정된 앱 identity 에 한 번 승인돼 — 다음 주에 conda 가 교체할 수 있는 인터프리터가 아니라. 이제 권한이 그 밑 툴체인의 모든 일상 업데이트보다 오래 살아, 안 흔들리는 것에 붙었으니까.

그게 옮겨 쓸 원리야: 권한 승인은 identity 에 붙으니, identity 는 안정되고 일부러 소유돼야 해. 네 승인이 일상적으로 재생성되거나, 업그레이드되거나, 재설치되는 것에 고정돼 있으면, 접근을 승인받은 게 아냐 — 다음 업데이트까지 빌린 거야.

나중에 무는 디테일: 신호를 전달해

서비스 매니저랑 진짜 작업 사이에 launcher 를 끼우면 새 의무가 하나 생기고, 그걸 건너뛰면 고약한 부류의 버그가 나와. 서비스 매니저가 job 을 멈출 때, 자기가 아는 프로세스 — launcher — 에 신호를 보내. launcher 가 그냥 죽으면, 그게 spawn 한 Python 자식이 고아가 될 수 있어: 아직 도는 전사, 아직 lease 를 쥔 채, 네가 통제한다고 생각한 lifecycle 엔 안 보이게. 그래서 launcher 는 종료 신호를 전체 worker 프로세스 그룹에 전달해. restart 는 restart 를 뜻해야지, 'restart 더하기 아직 일하는 유령' 이 아니라. 진짜 작업 앞에 supervisor 를 둘 때마다, 그 일은 시작하는 것만이 아냐 — 멈춤이 자기가 시작한 전부를 실제로 멈추게 하는 거야.

Code

인터프리터 말고 identity 에 승인 — 그리고 신호를 전달·text
틀림: 서비스 매니저 -> 벌거벗은 인터프리터 바이너리
  - 안정된 승인 가능 identity 없음 -> 파일 접근 거부
  - 승인해도: 환경 업데이트가 바이너리를 교체
    -> 승인이 조용히 증발

맞음: 서비스 매니저 -> signed app bundle (안정된 bundle id)
                            └─ 런타임 Python 을 자식으로 spawn
  - full-disk 접근이 안정된 앱 identity 에 한 번 승인됨
  - 그 밑 conda/툴체인 업데이트를 살아남음
  - launcher 가 책임 부모 프로세스

의무: launcher 는 종료 신호를 전체 worker 프로세스 그룹에
전달해야 함 -- 아니면 '정지' 가 lease 쥔 live 전사를 고아로 만듦.

External links

Exercise

네 설정에서 특정 산물에 붙은 권한, 자격 증명, 접근 승인을 찾아 — 바이너리 경로, 생성된 key 파일, 컨테이너 이미지 태그, 인터프리터. 물어: 어떤 일상 행위가 그 산물을 교체하고, 승인이 그걸 살아남아? 그다음 스택의 supervisor 나 wrapper 를 봐: 멈추면, 자기가 시작한 전부에 종료를 전달해, 아니면 자식이 유령으로 살아남을 수 있어?
Hint
탐침 둘: (1) 네 승인이 고정된 걸 교체하는 업데이트를 대봐(패키지 업그레이드, 재빌드, 재배포) — 승인이 그것과 함께 죽으면, 일부러 소유한 안정된 identity 에 다시 고정해. (2) supervisor 를 멈추고 그 뒤 자식 프로세스가 아직 살아 있는지 확인해. 작업을 살려두는 정지는 정지 없음보다 나빠, 네 툴링은 성공을 보고하는데 유령이 리소스를 계속 쥐니까.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.