[Draft] PEP 752 - Implicit namespaces for package repositories

원문 링크: PEP 752 - Implicit namespaces for package repositories

상태: Draft 유형: Standards Track 작성일: 13-Aug-2024

Python Enhancement Proposal (PEP) 752는 패키지 저장소에 대한 암묵적 네임스페이스(Implicit namespaces)를 도입하는 방안을 제시합니다. 이 제안은 Python 패키징 생태계에서 특정 조직이 패키지 이름 접두사를 예약하고 관리할 수 있도록 하여, 이름 스쿼팅(name-squatting) 및 의존성 혼란(dependency confusion)과 같은 문제에 대응하는 것을 목표로 합니다.

PEP 752 – 패키지 저장소를 위한 암묵적 네임스페이스

  • 작성자: Ofek Lev, Jarek Potiuk
  • 후원자: Barry Warsaw
  • PEP 대리인: Dustin Ingram
  • 상태: Draft (초안)
  • 유형: Standards Track (표준 추적)
  • 주제: Packaging (패키징)
  • 생성일: 2024년 8월 13일

초록 (Abstract)

이 PEP는 조직이 향후 업로드를 위해 패키지 이름 접두사를 예약할 수 있는 방법을 명시합니다.

동기 (Motivation)

현재 Python 패키징 생태계는 여러 패키지를 가진 프로젝트가 검증된 소유권 패턴을 알릴 수 있는 방법이 부족합니다. 이는 두 가지 주요 유형의 프로젝트에 영향을 미칩니다.

  1. 네임스페이스에 대한 완전한 통제를 원하는 프로젝트:
    • 주요 클라우드 제공업체 (Amazon, Google, Microsoft): google-cloud-compute와 같이 각 기능에 해당하는 패키지에 공통 접두사를 사용합니다.
    • OpenTelemetry: opentelemetry-<component>-<name>- 형식의 접두사를 사용하며, 모든 contrib 패키지는 중앙 저장소에 존재하고 오직 공식 패키지만 게시할 수 있습니다.
    • Apache Airflow: apache-airflow-providers- 접두사를 사용하는 프로바이더 패키지(provider package)를 가집니다.
  2. 일부 패키지는 공식적으로 유지보수하고, 서드파티 개발자들이 자체 패키지를 게시하여 참여하도록 장려하는 프로젝트:
    • Project Jupyter: 대부분의 확장 기능에 jupyter- 접두사를 사용합니다.
    • Django: 재사용 가능한 앱(reusable apps)에 django- 또는 dj- 접두사를 관습적으로 사용합니다.

이러한 프로젝트들은 이름 스쿼팅 공격(name-squatting attacks)에 특히 취약하며, 이는 궁극적으로 의존성 혼란(dependency confusion)으로 이어질 수 있습니다. 예를 들어, Datadog과 같은 회사가 공식적으로 지원하지 않는 제품에 대해 공격자가 합법적인 것처럼 보이는 패키지를 만들어 악성 코드를 실행할 수 있습니다.

PEP 708은 여러 저장소가 의존성 해결 중 고려되는 경우를 다루지만, 위의 사용 사례에는 보호를 제공하지 않습니다. 또한, 네임스페이스는 오타 스쿼팅(typosquatting) 발생률을 크게 줄일 수 있습니다. 현재 PyPI는 유사한 문자를 정규화하여 오타 스쿼팅을 방지하지만, 이들 사용 사례에는 불충분합니다.

네임스페이스는 또한 새로운 패키지 이름을 선택할 때 기존 명명 패턴을 따르는 문제를 해결합니다. 패키지 이름이 공개되기 전에 다른 사용자가 해당 이름을 선점하는 것을 방지할 수 있습니다.

근거 (Rationale)

다른 패키지 생태계는 역호환성(backwards compatibility)을 최소화하거나 최대화하는 두 가지 접근 방식 중 하나로 이 문제를 해결해 왔습니다.

  • NPM의 스코프 패키지(Scoped Packages): @google-cloud/storage와 같이 사용자 또는 조직 이름과 일치하는 스코프를 부여합니다. 이 방식은 모든 인스톨러와 도구를 수정해야 하므로 역호환성이 가장 낮습니다.
  • NuGet의 패키지 ID 접두사 예약(Package ID Prefix Reservation): 특정 패키지 이름 접두사를 하나 이상의 소유자가 사용하도록 예약할 수 있습니다. 이 방식은 PyPI와 같은 인덱스만 수정하면 되고 인스톨러는 변경할 필요가 없으므로 역호환성이 가장 높습니다.

이 PEP는 NuGet의 접근 방식인 플랫 네임스페이스(flat namespace) 전반에 걸친 ‘인증된 예약(authorized reservation)’을 명시합니다. 이는 기존 패키지 구문 위에 구축될 수 있으며, 기존 패키지와의 호환성을 유지하면서 미래의 무단 업로드를 방지하고 악의적인 경우 PEP 541 제거 요청을 통해 위험을 최소화합니다.

용어 (Terminology)

  • Organization (조직): 프로젝트를 소유하고 다양한 사용자가 연결된 엔티티.
  • Grant (승인/예약): 패키지 저장소에 대한 네임스페이스 예약.
  • Open Namespace (공개 네임스페이스): 모든 프로젝트 소유자의 업로드를 허용하는 네임스페이스.
  • Restricted Namespace (제한된 네임스페이스): 네임스페이스 소유자만 업로드를 허용하는 네임스페이스.
  • Parent Namespace (부모 네임스페이스): 접미사로 붙은 하이픈 구성 요소가 없는 네임스페이스. 예: foo-bar의 부모는 foo.
  • Child Namespace (자식 네임스페이스): 추가적인 접미사 하이픈 구성 요소가 있는 네임스페이스. 예: foo-barfoo의 유효한 자식이며, foo-bar-baz도 그러하다.

명세 (Specification)

조직 (Organizations)

프로젝트 생성을 허용하는 모든 패키지 저장소는 ‘조직’ 개념을 제공할 수 있습니다. 조직은 하나 이상의 네임스페이스를 예약할 수 있으며, 이러한 예약은 기존 프로젝트에 대한 소유권이나 특별한 권한을 부여하지 않습니다.

명명 (Naming)

네임스페이스는 유효한 프로젝트 이름이어야 하며 내부적으로 정규화됩니다. 예: foo.barfoo-bar가 됩니다.

의미 (Semantics)

네임스페이스 예약(grant)은 다음 항목에 대한 소유권을 부여합니다.

  • microsoft와 같은 플레이스홀더(placeholder) 패키지처럼 네임스페이스 자체와 일치하는 프로젝트.
  • 네임스페이스 뒤에 하이픈으로 시작하는 프로젝트. 예: foo 네임스페이스는 foo-bar에 일치하지만 foobar에는 일치하지 않습니다. 패키지 이름 매칭은 정규화된 네임스페이스를 기반으로 합니다. 네임스페이스는 패키지 저장소별로 적용되며 저장소 간에 공유되지 않습니다. 예약(grant)은 중복될 수 없습니다. 예를 들어, foo-bar에 대한 기존 예약이 있다면 foo에 대한 새로운 예약은 금지됩니다.

업로드 (Uploads)

업로드되는 패키지 이름이 예약된 네임스페이스와 일치하고, 다음 조건 중 하나라도 참이면 업로드는 403 HTTP 상태 코드로 실패합니다.

  • 프로젝트가 아직 존재하지 않는 경우.
  • 프로젝트가 해당 네임스페이스에 대한 활성 예약(grant)을 가진 조직에 의해 소유되지 않은 경우.

공개 네임스페이스 (Open Namespaces)

예약 소유자는 다른 사람이 해당 네임스페이스와 관련된 새로운 프로젝트를 출시하도록 허용할 수 있습니다. 이렇게 하면 모든 사용자가 해당 네임스페이스와 일치하는 새 프로젝트를 업로드할 수 있습니다.

숨겨진 예약 (Hidden Grants)

저장소는 공개적으로 표시되지 않는 숨겨진 예약(grant)을 만들 수 있으며, 이는 해당 네임스페이스가 다른 사람에게 점유되는 것을 방지합니다. 이러한 예약은 공개될 수 없으며 API에 노출되어서는 안 됩니다. 이는 네임스페이스를 외부에 노출하지 않고 업로드 제한을 강제하려는 저장소에 유용합니다.

저장소 메타데이터 (Repository Metadata)

JSON API 버전은 1.2에서 1.3으로 증가합니다. 이 PEP를 지원하는 저장소는 다음 API 변경 사항을 구현해야 합니다.

  • 프로젝트 상세 (Project Detail): 프로젝트 상세 응답에 namespace 키가 추가됩니다. 프로젝트가 활성 네임스페이스 예약과 일치하지 않으면 null이 됩니다. 일치하면 prefix, authorized, open 키를 포함하는 매핑(mapping)을 반환합니다.
  • 네임스페이스 상세 (Namespace Detail): /namespace/<namespace> 형식의 URL로 네임스페이스에 대한 정보를 제공합니다. 응답에는 prefix, owner, open, parent, children 키가 포함됩니다.

예약 제거 (Grant Removal)

예약된 네임스페이스가 점유되지 않게 되면, 저장소는 API에서 namespace 키를 null로 설정해야 합니다. 이전에 예약되었으나 현재는 그렇지 않은 네임스페이스는 어떤 조직이든 다시 예약할 수 있습니다.

커뮤니티 동의 (Community Buy-in)

다음 조직의 대표자들이 이 PEP에 대한 지지를 표명했습니다.

  • Apache Airflow
  • pytest
  • Typeshed
  • Project Jupyter
  • Microsoft
  • Sentry
  • DataDog

역호환성 (Backwards Compatibility)

기존 플랫 네임스페이스(flat namespace)가 여전히 유지되고 인스톨러를 수정할 필요가 없으므로, 내재적인 역호환성 문제는 없습니다. 많은 프로젝트는 이미 typeshed와 같이 접두사를 사용하여 공유 목적을 알리고 있습니다.

보안 영향 (Security Implications)

PEP 740 및 PEP 480을 기반으로 특정 릴리스가 관련 네임스페이스 소유자로부터 왔음을 암호학적으로 증명할 기회가 있습니다. 이 PEP는 이에 대한 자세한 구현 방안을 설명하지 않지만, 향후 작업이 계획되어 있습니다.

교육 방법 (How to Teach This)

패키지 사용자에게는 API에 메타데이터가 어떻게 노출되는지 문서화하고, 향후 설치 시 추가 보안 보증을 제공하기 위해 네임스페이스를 활용하는 도구를 언급할 예정입니다.

참고 구현 (Reference Implementation)

이 PEP의 완전한 참고 구현은 PR #17691에서 확인할 수 있습니다.

거부된 아이디어 (Rejected Ideas)

여러 대체 아이디어가 검토되었으나, 역호환성, 구현의 복잡성, 사용자 경험 저해 등의 이유로 거부되었습니다.

  • 사용자에게 예약 권한 부여: 리소스 경쟁과 사용자 검증 관리의 어려움으로 인해 불가능합니다.
  • 아티팩트 수준 네임스페이스 연결: 사용자에게 혼란을 줄 수 있고, 소유권 보증이 프로젝트 수준에서 이루어져야 한다는 기대에 부합하지 않습니다.
  • 조직 스코핑 (NPM 스타일): 의존성 혼란 공격 위험을 증가시키고, Python의 런타임 환경(단일 전역 네임스페이스)에 적합하지 않으며, 조직명 변경 시 혼란을 야기하고, 커뮤니티 전반에 걸쳐 대규모 업데이트가 필요합니다.
  • 전용 패키지 저장소 권장: 프로젝트에 인프라 유지보수 부담을 부과하고, 대부분의 패키지 관리자가 PyPI를 기본으로 사용하기 때문에 악성 패키지에 여전히 취약하며, 각 패키지 관리자마다 다른 저장소 추가 방법을 문서화해야 하는 복잡성을 야기합니다.
  • 출처 증명(Provenance Assertions)에만 전적으로 의존: 일반 pip install 사용자에게 보안을 제공하지 못하고, 클라이언트 측 로직의 복잡성 증가, UX 저해(예: 설치 시마다 확인 프롬프트), 다중 저장소 환경에서의 문제점 등이 있습니다.
  • 패키지 소유자 이름 주장: microsoft::azure-loganalytics와 같은 새로운 구문이 필요하여 커뮤니티에 큰 혼란을 주고, 저장소별 이름 충돌 가능성이 있습니다.
  • 고정 접두사 사용 (com-, org-): 프로젝트 이름 변경 부담, 브랜딩 문제, 자발적 변경의 어려움 등으로 인해 거부되었습니다.
  • DNS 사용: 대상 사용자에게 문제 해결에 도움이 되지 않고, PEP 740이 이미 더 안전한 방식으로 무결성을 지원하며, 도메인이 없는 프로젝트에 불리합니다.

⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.

Comments