어느 날부터인가 개발 중인 macOS 애플리케이션이 특정 시스템 기능에 접근하지 못하거나, 심지어는 정상적으로 설치된 서드파티 CLI 도구가 Operation not permitted 오류를 뿜으며 실행되지 않는 문제가 발생했습니다. 분명히 앱 번들에는 필요한 권한이 명시되어 있었고, CLI 도구는 시스템 경로에 정확히 설치되어 있었음에도 불구하고 말이죠. 특히 마이크로폰, 카메라, 화면 기록, 파일 시스템 접근 등 민감한 리소스에 접근하려는 시도에서 이러한 문제가 두드러지게 나타났습니다. 처음에는 앱의 코드 버그나 잘못된 권한 설정(chmod, chown)을 의심했지만, 시스템 로그를 자세히 분석하면서 TCC라는 키워드가 반복적으로 등장하는 것을 발견했습니다.
이 문제는 macOS의 핵심 보안 메커니즘인 TCC(Transparency, Consent, and Control) 프레임워크와 직접적으로 연관되어 있습니다. TCC는 사용자의 명시적인 동의 없이는 애플리케이션이 민감한 개인 정보나 시스템 리소스에 접근하지 못하도록 강력하게 제어합니다. 하지만 개발 과정이나 특정 자동화 스크립트 환경에서는 이러한 TCC의 동작 방식이 예상치 못한 장애물로 작용할 수 있습니다. 특히 Accessibility, Full Disk Access, Screen Recording 등과 같은 권한은 시스템 설정 UI를 통해 수동으로 부여해야 하므로, headless 환경이나 CI/CD 파이프라인에서는 더욱 복잡한 트러블슈팅을 요구하게 됩니다.
TCC 프레임워크의 내부 동작 원리 및 권한 관리
macOS의 TCC는 tccd 데몬과 TCC.db라는 SQLite 데이터베이스를 중심으로 동작합니다. tccd는 launchd에 의해 관리되며, 애플리케이션이 민감한 리소스에 접근을 시도할 때마다 TCC.db에 저장된 정책을 조회하여 접근 허용 여부를 결정합니다. 이 데이터베이스는 ~/Library/Application Support/com.apple.TCC/TCC.db 경로에 사용자별로 존재하며, 시스템 전체 정책은 /Library/Application Support/com.apple.TCC/TCC.db에 저장됩니다. 각 애플리케이션은 번들 식별자(Bundle Identifier) 또는 경로를 기준으로 TCC 정책에 등록됩니다.
애플리케이션이 TCC 보호 리소스(예: 카메라, 마이크, 캘린더, 연락처, 전체 디스크 접근 등)에 처음 접근을 시도하면, macOS는 사용자에게 권한 요청 다이얼로그를 표시합니다. 사용자가 '허용'을 선택하면 해당 애플리케이션의 번들 식별자와 요청된 서비스 유형이 TCC.db에 기록됩니다. 이후부터는 동일한 서비스에 대한 접근은 자동으로 허용됩니다. 문제는 이 다이얼로그가 표시되지 않거나, 사용자가 '거부'를 선택한 경우, 또는 CLI 도구처럼 명확한 GUI 번들이 없는 경우에 발생합니다. 특히 Full Disk Access나 Accessibility와 같은 일부 권한은 애플리케이션이 처음 요청할 때 다이얼로그가 뜨지 않고, 사용자가 '시스템 설정' > '개인정보 보호 및 보안'에서 수동으로 추가해 주어야만 합니다.
일반적인 TCC 관련 에러 메시지 및 시스템 로그 분석
TCC 관련 문제는 다양한 형태로 나타나지만, 공통적으로 시스템 로그(log stream)에서 TCC 키워드를 통해 단서를 찾을 수 있습니다. 주로 다음과 같은 에러 메시지를 접하게 됩니다.
Operation not permittedThe application doesn't have permission to access the requested resource.Error Domain=NSCocoaErrorDomain Code=257 "The file couldn’t be opened because you don’t have permission."(특히Full Disk Access부족 시)
실제 시스템 로그에서는 다음과 같은 패턴을 확인할 수 있습니다.
log stream --predicate 'process == "tccd" or (process == "your_app_name" and subsystem == "com.apple.TCC")' --info --debug
# 예시: 특정 앱의 TCC 관련 로그를 실시간으로 확인 (your_app_name을 실제 앱 이름으로 변경)
로그 출력 예시:
2023-10-27 10:30:45.123456+0900 0x12345 Error 0x0 tccd: [com.apple.TCC:access] Denying access to kTCCServiceMicrophone for bundleID com.yourcompany.YourApp because it is not in the TCC database.
2023-10-27 10:30:45.123456+0900 0x12346 Error 0x0 YourApp: [com.apple.TCC:access] TCC: client com.yourcompany.YourApp denied access to kTCCServiceMicrophone
위 로그는 com.yourcompany.YourApp 번들 ID를 가진 애플리케이션이 마이크(kTCCServiceMicrophone) 접근을 시도했지만, TCC.db에 해당 앱의 권한 정보가 없거나 거부되었기 때문에 접근이 거부되었다는 것을 명확히 보여줍니다. kTCCServiceMicrophone, kTCCServiceCamera, kTCCServiceScreenCapture, kTCCServiceSystemPolicyAllFiles 등 kTCCService 접두사를 가진 상수는 TCC가 제어하는 특정 서비스 유형을 나타냅니다.
TCC 권한 문제 해결을 위한 실무 조치 방법
TCC 문제는 주로 수동 설정, tccutil 명령어 활용, 그리고 경우에 따라서는 sqlite3를 통한 TCC.db 직접 조작으로 해결할 수 있습니다.
1. 시스템 설정 UI를 통한 수동 권한 부여 (가장 일반적)
대부분의 TCC 문제는 '시스템 설정'을 통해 해결됩니다.
시스템 설정(macOS Ventura 이상) 또는시스템 환경설정(macOS Monterey 이하)을 엽니다.개인정보 보호 및 보안(Privacy & Security) 섹션으로 이동합니다.- 좌측 목록에서 문제가 되는 서비스 유형 (예:
파일 및 폴더,전체 디스크 접근,화면 기록,손쉬운 사용등)을 선택합니다. - 우측 창에서 해당 애플리케이션을 찾아 토글을 켜거나, 하단의
+버튼을 눌러 애플리케이션 목록에 추가하고 체크박스를 활성화합니다. 특히 CLI 도구의 경우, 해당 실행 파일의 경로를 직접 찾아 추가해야 합니다. (예:/usr/local/bin/my_cli_tool)
2. tccutil 명령어를 이용한 TCC 데이터베이스 관리
tccutil은 TCC 데이터베이스의 항목을 재설정하는 데 사용되는 유용한 CLI 도구입니다. 특정 서비스에 대한 모든 권한을 초기화하거나, 특정 번들 ID에 대한 권한을 초기화할 수 있습니다.
# 모든 서비스에 대한 모든 TCC 권한 초기화 (주의: 모든 앱의 TCC 설정이 초기화됩니다)
# sudo tccutil reset All
# 특정 서비스에 대한 모든 TCC 권한 초기화 (예: 마이크 접근 권한)
tccutil reset Microphone
# 특정 서비스에 대한 특정 번들 ID의 TCC 권한 초기화 (예: com.yourcompany.YourApp의 카메라 접근 권한)
tccutil reset Camera com.yourcompany.YourApp
tccutil은 주로 개발/테스트 환경에서 TCC 상태를 깨끗하게 재설정해야 할 때 유용합니다. 하지만 Full Disk Access나 Accessibility 같은 일부 민감한 서비스는 tccutil로 직접 추가하거나 제거할 수 없으며, 여전히 수동으로 설정해야 합니다.
3. sqlite3를 이용한 TCC.db 직접 조작 (고급 & 주의 필요)
매우 드물지만, 시스템 설정 UI나 tccutil로 해결되지 않는 복잡한 시나리오에서는 TCC.db 파일을 sqlite3 명령어로 직접 수정하는 방법을 고려할 수 있습니다. 이 방법은 매우 강력하지만, 잘못 사용하면 시스템의 보안 무결성을 해치거나 예기치 않은 부작용을 초래할 수 있으므로 극도로 주의해야 합니다. macOS의 SIP(System Integrity Protection) 때문에 시스템 전역 TCC.db (/Library/Application Support/com.apple.TCC/TCC.db)는 수정하기 어렵습니다. 주로 사용자별 TCC.db (~/Library/Application Support/com.apple.TCC/TCC.db)를 대상으로 합니다.
# TCC.db 파일 경로
TCC_DB_PATH="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
# TCC.db 파일이 존재하는지 확인
if [ ! -f "$TCC_DB_PATH" ]; then
echo "TCC.db not found at $TCC_DB_PATH"
exit 1
fi
# TCC.db 백업 (필수!)
cp "$TCC_DB_PATH" "$TCC_DB_PATH.bak_$(date +%Y%m%d%H%M%S)"
echo "TCC.db backed up to $TCC_DB_PATH.bak_..."
# sqlite3를 사용하여 TCC.db 내용 조회 (예: 모든 서비스 접근 허용 항목)
sqlite3 "$TCC_DB_PATH" "SELECT service, client, client_type, allowed, prompt_count FROM access WHERE allowed = 1;"
# 예시: 특정 앱 (my_cli_tool)에 'Full Disk Access' (kTCCServiceSystemPolicyAllFiles) 권한 부여
# 이 예시는 CLI 도구에 대한 Full Disk Access를 프로그램적으로 부여하려는 시나리오를 가정합니다.
# 주의: client_type은 0=Bundle ID, 1=Path, 2=Executable Code Signature 입니다.
# 대부분의 CLI 도구는 Path (1) 또는 Code Signature (2)로 등록됩니다.
# 아래 예시는 경로 기반으로 추가하는 방법입니다.
# 실제 앱의 번들 ID나 경로, 코드 서명 정보를 정확히 파악해야 합니다.
# 이 방법은 macOS 업데이트에 따라 작동하지 않을 수 있으며, Apple이 권장하는 방식이 아닙니다.
# 프로덕션 환경에서는 반드시 시스템 설정 UI를 통해 수동으로 설정해야 합니다.
#
# sqlite3 "$TCC_DB_PATH" <<EOF
# INSERT INTO access (service, client, client_type, allowed, prompt_count, csreq) VALUES
# ('kTCCServiceSystemPolicyAllFiles', '/usr/local/bin/my_cli_tool', 1, 1, 0, X'');
# EOF
# echo "Attempted to grant Full Disk Access to my_cli_tool. Please verify in System Settings."
# 변경사항 적용을 위해 tccd 데몬 재시작 (필요할 경우)
# sudo killall tccd
TCC.db의 스키마는 macOS 버전에 따라 변경될 수 있으므로, 항상 최신 정보를 확인하고 신중하게 접근해야 합니다. 특히 csreq 필드는 애플리케이션의 코드 서명 요구사항을 나타내며, 이 값이 잘못되면 권한이 부여되지 않거나 앱이 실행되지 않을 수 있습니다.
TCC 권한 문제 방지를 위한 개발 및 배포 가이드라인
TCC 문제를 사전에 방지하려면 개발 단계부터 TCC의 동작 방식을 이해하고 적절하게 대응해야 합니다.
- Entitlements 파일 관리: macOS 앱 개발 시
Info.plist외에.entitlements파일을 통해 앱이 필요로 하는 권한을 명시적으로 선언해야 합니다. 예를 들어, 네트워크 접근, 샌드박스 예외 등은 여기에 포함됩니다. TCC는 이와는 별개로 사용자 동의가 필요한 민감한 리소스에 대한 접근을 제어합니다. - 권한 요청 시점 명확화: 앱이 처음으로 TCC 보호 리소스에 접근할 때, 사용자에게 명확한 메시지와 함께 권한 요청 다이얼로그가 표시되도록 구현해야 합니다. 사용자 경험을 고려하여 왜 해당 권한이 필요한지 설명하는 것이 좋습니다.
- 자동화 환경 고려: CI/CD 파이프라인이나 자동화된 테스트 환경에서는 TCC 권한을 수동으로 부여하기 어렵습니다. 이러한 환경에서는 TCC 보호 리소스에 대한 접근을 최소화하거나, 테스트용으로만 특정 권한을 부여하는 스크립트를 작성해야 합니다. 하지만 이는 보안 위험을 증가시킬 수 있으므로 신중하게 접근해야 합니다. 가상 머신 환경에서 TCC 설정을 스냅샷으로 관리하는 것도 한 가지 방법입니다.
- 코드 서명: macOS에서 앱과 CLI 도구는 유효한 개발자 ID로 서명되어야 합니다. 서명되지 않은 앱은 Gatekeeper에 의해 차단될 수 있으며, TCC 역시 서명된 앱에 대해 더 신뢰할 수 있는 방식으로 동작합니다.
codesign --verify --verbose "YourApp.app"명령어로 코드 서명 상태를 확인할 수 있습니다.
TCC 트러블슈팅 FAQ
### Q. Full Disk Access 권한을 부여했는데도 Operation not permitted 오류가 계속 발생합니다.
A. Full Disk Access는 특정 애플리케이션이나 CLI 도구가 시스템의 모든 파일에 접근할 수 있도록 허용하는 강력한 권한입니다. 이 권한을 부여했음에도 문제가 발생한다면, 다음 사항을 확인해 보세요.
- 정확한 실행 파일 경로:
시스템 설정에 추가된 경로가 실제로 실행되는 바이너리 파일의 경로와 일치하는지 확인하세요. 예를 들어, Python 스크립트라면python인터프리터 자체에Full Disk Access를 부여해야 할 수도 있습니다. - 번들 ID vs. 경로: GUI 앱은 번들 ID로, CLI 도구는 경로로 등록되는 경우가 많습니다. 어떤 방식으로 등록되었는지 확인하고, 필요한 경우
tccutil reset후 다시 등록해 보세요. - SIP(System Integrity Protection): macOS의 SIP는
root권한으로도 특정 시스템 파일 및 디렉토리(예:/System,/usr/bin의 일부)를 수정하는 것을 방지합니다.Full Disk Access가 부여되었더라도 SIP 보호 영역에는 접근이 제한될 수 있습니다.csrutil status명령어로 SIP 상태를 확인할 수 있습니다. - 재부팅: 드물지만, TCC 설정 변경 후 시스템 재부팅이 필요한 경우가 있습니다.
### Q. 개발 중인 앱에서 마이크나 카메라 접근 요청 다이얼로그가 뜨지 않습니다.
A. 앱이 Info.plist 파일에 해당 서비스에 대한 Privacy - Microphone Usage Description (NSMicrophoneUsageDescription) 또는 Privacy - Camera Usage Description (NSCameraUsageDescription) 키와 설명을 포함하고 있는지 확인해야 합니다. 이 키가 없으면 macOS는 사용자에게 권한 요청 다이얼로그를 표시하지 않습니다. 또한, 앱이 샌드박스 처리되어 있다면, 샌드박스 엔타이틀먼트에 해당 권한이 명시되어 있어야 합니다.
<!-- Info.plist 예시: 마이크 접근 설명 추가 -->
<key>NSMicrophoneUsageDescription</key>
<string>이 앱은 음성 명령 및 녹음 기능을 위해 마이크 접근이 필요합니다.</string>
<!-- Info.plist 예시: 카메라 접근 설명 추가 -->
<key>NSCameraUsageDescription</key>
<string>이 앱은 사진 촬영 및 비디오 스트리밍 기능을 위해 카메라 접근이 필요합니다.</string>
### Q. CI/CD 환경에서 macOS 앱 테스트 시 TCC 권한 문제를 어떻게 처리해야 하나요?
A. CI/CD 환경에서 TCC 권한 문제는 매우 까다롭습니다.
- 테스트 범위 조정: TCC 보호 리소스에 의존하는 테스트는 GUI 상호작용이 필요한 경우가 많으므로, 이러한 테스트를 분리하거나 Mock 객체를 사용하여 의존성을 제거하는 것이 좋습니다.
- 가상 머신 스냅샷: macOS 가상 머신을 사용하는 CI/CD 환경이라면, TCC 권한이 미리 설정된 스냅샷을 만들어 사용하면 매번 수동으로 설정할 필요가 없습니다.
- 스크립트를 통한 자동화 (제한적):
sqlite3를 이용한TCC.db직접 조작은 앞서 언급했듯이 위험하며, macOS 업데이트에 따라 작동하지 않을 수 있습니다. 하지만 통제된 개발/테스트 환경에서는 최후의 수단으로 고려될 수 있습니다. 이 경우, 반드시 변경 사항을 백업하고, 스크립트 실행 후 TCC 설정이 올바른지 검증해야 합니다. - Apple Script/UI 자동화:
osascript나UI Automation프레임워크를 사용하여 시스템 설정 UI를 프로그램적으로 조작하는 방법도 있지만, 이는 매우 불안정하며 macOS 버전업에 취약합니다.
TCC는 macOS의 강력한 보안 기능이지만, 그만큼 개발자와 엔지니어에게는 깊은 이해와 신중한 접근을 요구합니다. 이 가이드가 macOS 환경에서 TCC 관련 문제를 해결하고, 안전하고 효율적인 개발 워크플로우를 구축하는 데 도움이 되기를 바랍니다.
