패키지 레지스트리의 서명과 출처 증명 비교
Signing and Attestations Across Package Registries
핵심 요약
- 서명은 업로드된 파일의 무결성과 서명 키를 확인하고, provenance attestation은 소스 저장소와 커밋, 빌드 워크플로 또는 게시 주체에 관한 정보를 기록한다.
- trusted publishing은 장기 API 토큰 대신 CI의 단기 OIDC 자격 증명을 사용하지만, 워크플로가 침해되면 공격자가 악성 릴리스를 게시할 수 있다.
- 레지스트리마다 증거의 저장 방식과 검증 범위가 다르며, 설치 시 기본 검증을 수행하는 클라이언트는 일부에 그치고 attestation 검증은 대체로 별도 도구에 맡긴다.
도입
패키지 서명, provenance attestation, trusted publishing은 서로 다른 공급망 증거를 제공한다. 서명은 파일의 바이트와 키를 연결하고, attestation은 빌드나 게시 경로를 기록한다. trusted publishing은 CI의 OIDC 자격 증명으로 게시자를 인증한다. 각 레지스트리는 이 증거를 다른 형식과 위치에 저장하며, 클라이언트가 설치 과정에서 자동 검증하는지도 제각각이다.
상세 요약
증거의 종류
패키지 서명과 attestation은 게시된 아티팩트에 검증 근거를 붙이지만, 확인하는 대상은 다르다.
- 패키지 서명은 파일의 바이트를 레지스트리 또는 작성자의 키와 연결한다. 변조된 미러에서 파일을 받았는지 확인하는 데 쓰인다. 그러나 탈취된 토큰으로 악성 파일을 게시해도 레지스트리 서명은 정상적으로 붙을 수 있다.
- provenance attestation은 아티팩트가 어디에서 왔는지 서명된 진술로 남긴다. SLSA build provenance는 소스 저장소, 커밋, 빌드 워크플로를 기록한다. PyPI의 publish attestation처럼 누가 파일을 게시했는지 기록하는 형식도 있다.
- trusted publishing은 CI가 발급받은 단기 OIDC 자격 증명으로 게시하게 한다. 장기 API 토큰을 대체하고 워크플로 신원을 게시 자격 증명으로 사용하지만, 워크플로 자체가 침해되면 악성 릴리스가 게시될 수 있다.
Ultralytics 침해 사례에서는 프로젝트 릴리스 워크플로가 만든 초기 악성 릴리스에 유효한 attestation이 있었고, 이후 유출된 API 토큰으로 올린 릴리스에는 attestation이 없었다. 이 차이는 조사자가 게시 경로를 구분하는 근거가 됐다.
레지스트리별 구현 차이
npm은 레지스트리 ECDSA 서명을 제공하고, provenance가 포함된 버전에는 Sigstore 인증서를 이용한 SLSA 진술과 레지스트리 키로 서명한 npm publish attestation을 저장한다. trusted publishing을 통한 게시에서는 provenance가 기본 생성된다. 다만 검증은 설치 시 자동 수행되지 않고 npm audit signatures 명령으로 별도 실행한다.
PyPI는 PGP 서명을 중단하고 PEP 740 attestation을 제공한다. trusted publishing을 사용하는 프로젝트의 업로드에서는 기본 생성되며, 증거는 파일별 integrity API에서 조회한다. attestation은 업로드 뒤에도 추가될 수 있어 수집기는 이미 처리한 파일을 다시 조회해야 한다. RubyGems는 Sigstore bundle을 제공하며, 자동 attestation 기능은 GitHub Actions에서 rubygems.org로 게시하는 경우에 한정된다.
다른 레지스트리의 범위도 다르다. Maven Central은 모든 파일에 PGP 서명을 요구하지만 trusted publishing은 제공하지 않는다. NuGet은 저장소 서명을 기본 검증하며, Linux에서는 .NET 8 SDK부터 restore 시 확인한다. Terraform Registry는 provider의 GPG 서명을 terraform init에서 기본 검증하지만 모듈은 서명 없이 Git 태그에서 게시된다. Swift 패키지 레지스트리 프로토콜은 Swift 5.9부터 CMS 서명을 지원하고, SwiftPM은 checksum pinning을 기본으로 엄격하게 적용하며 서명된 아카이브를 trust store와 대조한다. 다만 Git 저장소를 clone하는 패키지는 레지스트리 서명 대상이 아니다.
검증은 설치와 별도일 수 있다
서명을 확인하는 일과 서명자의 신원을 확인하는 일은 별개다. Sigstore 인증서가 유효한지 검사한 뒤, 그 인증서가 예상한 저장소에 속하는지 대조해야 한다. gh attestation verify와 pypi-attestations verify pypi는 호출할 때 저장소를 지정받아 서명 인증서의 저장소 정보와 비교한다. PEP 751 lockfile의 attestation-identities 필드는 패키지별 예상 신원을 기록하는 방식을 제안한다.
설치 때 검증하는 기본값도 일관되지 않다. npm은 별도 명령을 사용하고, Python의 pip와 uv에는 설치 시 attestation 검증을 요구하는 미해결 이슈가 있다. rattler는 2026년 9월부터 설치 시 Sigstore 검증을 선택적으로 지원한다. 반면 Go의 checksum database와 Hackage의 TUF 인덱스는 해시를 담은 메타데이터를 인증하므로 클라이언트가 다운로드 파일뿐 아니라 해시의 출처도 확인한다. Cargo, Julia Pkg, conda는 TLS로 전달된 메타데이터의 해시와 파일을 대조하지만, 해시 메타데이터 자체에는 서명이 없다.
서명된 빌드 캐시와 저장소
Debian과 Fedora는 배포판 인프라에서 소스 패키지를 빌드한 뒤 아카이브 키로 결과물에 서명한다. Nix, Guix, Spack도 프로젝트 인프라에서 빌드한 바이너리 캐시를 서명하며 각 클라이언트는 기본적으로 서명을 확인한다. 반면 언어 레지스트리의 패키지는 작성자의 노트북이나 CI에서 빌드한 파일을 업로드하는 경우가 있어, 레지스트리 서명만으로 빌드 과정을 증명하지는 못한다.
레지스트리마다 attestation 저장 위치와 형식도 다르다. in-toto/friends에 추가된 목록은 패키지 레지스트리, Git 저장소와 릴리스, OCI 이미지, GitHub API 등에서 증거를 어디에 저장하고 비공개로 둘 수 있는지 정리한다. 패키지 관리 보안과 공급망 표준을 다룬 FOSDEM 2026 패키지 관리 세션 요약: 보안 강화와 공급망 표준화의 흐름도 관련 사례를 다룬다.
결론
레지스트리 서명만으로는 릴리스가 어떤 소스와 워크플로에서 만들어졌는지 확인할 수 없다. attestation도 서명 검증 뒤에 예상 저장소와 인증서의 신원을 대조해야 한다. Go와 Hackage처럼 해시를 담은 메타데이터 자체를 인증하는 방식과, TLS로 전달된 해시를 확인하는 방식도 구분해야 한다. 따라서 보호 수준은 증거의 종류뿐 아니라 클라이언트의 기본 검증 범위에 달려 있다.