패키지 매니저처럼 꽥꽥한다면

발행: (2026년 3월 8일 PM 08:27 GMT+9)
13 분 소요

Source: Hacker News

저는 패키지 매니저를 연구하는 데 많은 시간을 보냅니다. 어느 정도 시간이 지나면 오리처럼 울음을 내는 것들을 눈여겨보게 됩니다. 많은 도구가 레지스트리, 버전 고정, 여러분을 대신해 다운로드되고 실행되는 코드를 가지고 있습니다. 하지만 설치 가능한 항목들의 평면 리스트는 그다지 흥미롭지 않죠.

제가 귀에 걸리는 울음은 무언가가 의존성 그래프를 형성할 때입니다: 여러분의 패키지가 또 다른 패키지에, 그 패키지가 또 다른 패키지에 의존하게 되고, 이제는 해결 알고리즘, lockfile, 무결성 검증, 그리고 “내가 실제로 무엇을 실행하고 있으며 그것이 어떻게 여기까지 왔는가?”에 답할 방법이 필요합니다.

플러그인 시스템, CI 러너, 차트‑템플릿 도구로 시작한 여러 도구들이 조용히 전이적 의존성 트리를 키워왔습니다. 이제 이들은 패키지 매니저처럼 걷고, 패키지 매니저처럼 울며, npm, Cargo, Bundler가 수년간 배워가며 관리해 온 모든 문제들을 가지고 있습니다—하지만 대부분은 아직 그 해결책을 따라잡지 못했습니다.

GitHub Actions

기능상태
레지스트리GitHub 저장소
잠금 파일아니오
무결성 해시아니오
해결 알고리즘재귀 다운로드, 제약 조건 해결 없음
전이 고정아니오
변경 가능한 버전예 – git 태그를 이동할 수 있습니다. Immutable releases는 게시 후 태그를 고정하지만 여전히 삭제될 수 있습니다.

저는 이미 이에 대해 자세히작성한 바 있습니다. 다음과 같이 작성하면

uses: actions/checkout@v4

GitHub가 종속성을 해결하고, 다운로드하고, 실행하는 의존성을 선언하는 것입니다. 러너의 PrepareActionsRecursiveAsync 메서드는 다음과 같이 트리를 탐색합니다:

  1. 각 액션의 tarball을 다운로드합니다.
  2. action.yml을 읽어 추가 종속성을 찾습니다.
  3. 최대 열 단계까지 재귀합니다.

제약 조건 해결은 전혀 없습니다. 2021년에 복합‑내‑복합 지원이 추가되면서 전이 종속성 문제가 발생했으며, 잠금 파일이 요청되었지만(2022년에 “계획되지 않음”으로 종료) 구현되지 않았습니다.

상위 레벨 액션은 SHA‑핀 할 수 있지만, Palo Alto의 “Unpinnable Actions” 연구에 따르면 전이 종속성은 여전히 핀할 수 없습니다. tj‑actions/changed‑files 사건 (2025년 3월)은 reviewdog/action-setup(종속성의 종속성)에서 시작되어 공격자가 모든 기존 버전 태그를 악성 코드가 가리키도록 재태깅하면서 CI 비밀을 워크플로 로그에 유출시켰고, 23 000개 이상의 저장소에 영향을 미쳤습니다.

GitHub는 이후 SHA‑핀 강제 정책(상위 레벨만 적용)을 추가했습니다 — 공지 사항을 참조하십시오.

Ansible Galaxy

FeatureStatus
Registrygalaxy.ansible.com
LockfileNo
Integrity hashesOpt‑in
Resolution algorithmresolvelib
Transitive pinningNo
Mutable versionsYes, no immutability guarantees

Ansible 컬렉션과 역할은 ansible-galaxy를 통해 galaxy.ansible.com에서 설치됩니다. 의존성은 meta/requirements.yml에 선언됩니다. 역할을 설치하면 선언된 의존성이 자동으로 설치되고, 그 의존성도 다시 자신의 의존성을 가질 수 있어 실제 전이적 트리를 형성합니다.

  • 해결자는 **resolvelib**이며, 이는 pip이 사용하는 백트래킹 제약 해결기와 동일합니다—Terraform이나 Helm이 사용하는 것보다 더 정교합니다.
  • lockfile은 2016년에 처음 요청(아카이브)되었고 2018년에 다시 열렸으며, 현재도 이슈가 열려 있습니다.
  • 현재는 아카이브된 Mazer 도구가 2020년에 포기되기 전 install --lockfile을 구현했으며, 따라서 이 기능은 잠시 존재했다가 사라졌습니다.

ansible-galaxy collection verify는 서버와의 체크섬을 확인할 수 있고, GPG 서명 검증도 존재하지만 두 기능 모두 옵트인이며 기본적으로 비활성화되어 있습니다. galaxy.ansible.com에 게시된 버전은 게시자가 덮어쓸 수 있으며, Git 저장소에서 가져온 역할도 GitHub Actions와 동일한 mutable‑tag 문제를 겪습니다.

역할은 Ansible 프로세스의 전체 권한으로 실행되며(선택적으로 become 상승 가능) 전이적 역할 의존성을 제외하거나 재정의할 수 없는 오래된 오픈 이슈가 존재합니다(예: #13215).

Terraform 공급자 및 모듈

기능상태
레지스트리registry.terraform.io
잠금 파일.terraform.lock.hcl
무결성 해시Yes
해결 알고리즘Greedy, newest match
전이적 고정Yes for providers; no for modules
가변 버전Providers immutable; modules use mutable git tags

Terraform은 기존 패키지 관리자에서 배운 점이 있습니다:

  • .terraform.lock.hcl정확한 공급자 버전암호학적 해시(여러 형식)를 기록합니다.
  • terraform init은 다운로드를 해당 해시와 비교하여 검증하며, 공급자는 GPG‑signed가 되어 있습니다.
  • 버전 제약 구문(~> 4.0, >= 3.1 등)이 지원됩니다.

참고: 잠금 파일은 공급자만 추적하고, 모듈은 추적하지 않습니다 (GitHub issue #31301). 따라서 중첩된 모듈 의존성은 잠금 파일 보호 없이 연속적인 버전 상승이 필요합니다. 모듈을 고정하는 데 사용되는 Git 태그는 변경 가능하므로, 태그로 고정된 모듈이 다른 내용으로 조용히 교체될 수 있습니다 (GitHub issue #29867).

연구자들은 레지스트리 타이포스쿼팅(hashic0rp/aws에 0 사용)을 입증했으며 (BoostSecurity article) 그리고 2025년 NDC Oslo에서 실시간 공급망 공격 데모 (Class Central video)를 통해 실제로 작동하는 모습을 보여주었습니다.

공급자 측면은 견고하지만, 전이적 트리의 모듈 측면은 GitHub Actions와 동일한 변경 가능한 참조 문제를 겪고 있습니다.

Helm Charts

FeatureDetails
RegistryChart repos / OCI registries
LockfileChart.lock
Integrity hashesOpt‑in
Resolution algorithmGreedy, root precedence
Transitive pinningYes
Mutable versionsDepends on registry; OCI digests are immutable, chart‑repo tags are not

Kubernetes Helm은 여기 있는 대부분의 도구보다 패키지‑매니저 DNA가 더 많이 포함되어 있습니다.

  • Chart.yaml은 버전 제약 조건과 함께 의존성을 선언합니다.
  • Chart.lock은 정확히 해결된 버전을 기록합니다.
  • 서브차트는 자체 의존성을 가질 수 있어, 진정한 전이적 트리를 구축합니다.

해결자는 (source) 각 제약 조건에 맞는 최신 버전을 선택하며, 충돌이 발생할 경우 루트에 더 가깝게 지정된 버전이 우선합니다.

  • 차트 저장소는 index.yaml을 제공하는데, 이는 패키지 인덱스와 같은 역할을 합니다.
  • OCI 레지스트리도 동작하지만, 변형 가능성은 다릅니다:
    • OCI digests – 콘텐츠 주소 지정이며 불변입니다.
    • 전통적인 차트 저장소 – 게시자가 동일한 URL에 다시 업로드하여 버전을 덮어쓸 수 있습니다; Chart.lock은 버전 번호만 기록하고 콘텐츠 해시를 기록하지 않으므로 이러한 변화를 감지하지 못합니다.

Helm은 차트 서명을 위한 provenance 파일을 지원하지만, 채택률은 낮은 편입니다 (Helm provenance docs).

Known Limitations & Vulnerabilities

  • helm dependency build 첫 번째 수준 의존성만 해결합니다 (GitHub issue #2247), 전이적 의존성은 포함되지 않습니다.
  • 전이적 의존성에 대한 값을 명시적으로 나열하지 않으면 설정할 수 없습니다 (GitHub issue #8289).
  • 전이적 서브차트의 조건을 비활성화할 방법이 없습니다 (GitHub issue #12020).
  • Chart.lock을 통한 심볼릭 링크 공격helm dependency update 실행 시 로컬 코드 실행을 허용했으며, v3.18.4에서 수정되었습니다 (GHSA‑557j‑xg8c‑q2mm).
  • 악성 Helm 차트가 Argo CD를 악용해 배포에서 비밀 정보를 탈취한 사례가 있습니다 (APIiro blog).

전이 실행이 있다면, 그것은 패키지 매니저다

Once a tool develops transitive dependencies, it inherits a specific set of problems—whether it acknowledges them or not:

ProblemDescription
Reproducibility트리는 매번 다르게 해석될 수 있으며, 정확한 결과를 기록하기 위해 lockfile이 필요합니다.
Supply‑chain amplification공급망 증폭: 트리 깊숙이 있는 하나의 손상된 패키지가 외부로 연쇄되어 이를 의존하는 모든 프로젝트에 영향을 미칠 수 있습니다 (example).
Override and exclusion오버라이드 및 제외: 사용자는 선택하지 않았고 원하지 않는 전이 의존성을 처리할 메커니즘이 필요합니다.
Mutable references가변 참조: 이동, 재작성, 강제 푸시가 가능한 버전 태그는 동일한 식별자가 내일은 다른 코드로 가리킬 수 있음을 의미합니다.
Full‑tree pinning전체 트리 고정: 직접 의존성을 고정해도 그 의존성들이 가변 참조를 사용한다면 효과가 없습니다.
Integrity verification무결성 검증: 오늘 실행하는 것이 어제 실행한 것과 동일함을 확인할 수 있어야 합니다.

If your tool exhibits these issues, it is a package manager. No amount of calling it a “plugin system” or “marketplace” will stop supply‑chain attacks from knocking at your door.

0 조회
Back to Blog

관련 글

더 보기 »

JVG algorithm은 작은 수에서만 이긴다

정기적인 AI 종말에 관한 프로그램을 방해하게 되어 죄송합니다만, 이 블로그의 가장 초기 시절의 전통적인 흐름으로 돌아가겠습니다… 하지만 이제 저는…

첫 비행기 사망 사고

Thomas Selfridge – The First Fatality in Powered Aviation 1908년 9월 17일 저녁, 토머스 셀프리드라는 젊은 미국 장교가 ...