
npm 배포 토큰을 없애도 끝이 아니다…OIDC 뒤 provenance를 확인하라

GitHub Actions에서 npm 배포용 장기 쓰기 토큰을 없애려면 npm 패키지에 배포 워크플로를 Trusted Publisher로 등록하고, 발행 작업에 OIDC 권한을 부여한 뒤 토큰 없이 새 버전을 발행해야 한다. npm의 Trusted Publishing 안내에는 npm CLI 11.5.1 이상, Node.js 22.14.0 이상과 GitHub Actions의 id-token: write 권한이 요구 사항으로 명시돼 있다.
전환은 발행 성공만으로 끝나지 않는다. 공개 저장소의 공개 패키지라면 배포된 버전에 provenance가 생성됐는지 확인하고, 기록에 연결된 소스 커밋과 워크플로가 실제 릴리스와 일치하는지 대조해야 한다. 그 결과를 확인한 다음 기존 쓰기 토큰을 폐기하는 순서가 안전하다.
배포 환경의 지원 조건을 먼저 확인한다
GitHub Actions의 Trusted Publishing은 GitHub 호스팅 러너에서 지원된다. 기존 배포 작업이 자체 호스팅 러너를 사용한다면 러너를 바꿀 수 있는지 먼저 결정해야 한다. 또한 package.json의 repository.url은 실제로 발행에 사용하는 GitHub 저장소와 정확히 일치해야 한다. 저장소를 이전했거나 포크에서 배포한다면 이 값도 함께 수정한다.
provenance가 필요한 경우에는 저장소와 npm 패키지가 모두 공개 상태인지 확인한다. 비공개 GitHub 저장소에서 공개 패키지를 발행할 때도 OIDC 인증은 사용할 수 있지만 provenance 자동 생성은 지원되지 않는다. 따라서 두 기능의 성공 여부를 하나의 결과로 취급하면 발행은 됐는데 출처 기록이 없는 상태를 놓치기 쉽다.
배포 전에 실제로 실행할 워크플로 파일과 릴리스 트리거를 확정하는 편이 좋다. npm에 등록할 대상은 저장소 전체가 아니라 그 저장소의 지정된 워크플로다. 배포 승인에 GitHub Environment를 쓴다면 워크플로의 환경 이름도 등록 정보와 맞아야 한다.
npm 패키지에 발행 워크플로를 등록한다
npmjs.com에서 대상 패키지의 Settings를 열고 Trusted publishing에서 GitHub Actions를 선택한다. Organization or user에는 GitHub 소유자, Repository에는 저장소 이름, Workflow filename에는 .github/workflows/에 있는 파일의 이름만 입력한다. 예를 들어 워크플로가 .github/workflows/publish.yml이라면 파일명 칸에는 publish.yml을 적는다. 경로 전체를 넣거나 확장자와 대소문자를 다르게 쓰면 실제 발행 때 인증에 실패할 수 있다.
직접 npm publish를 실행할 계획이라면 해당 Trusted Publisher의 허용 동작에서 직접 발행도 선택해야 한다. 단계적 발행에 쓰는 npm stage publish 권한과 직접 발행 권한은 별개다. 배포 승인을 별도로 거치려는 팀은 단계적 발행을 선택할 수 있지만, 그 경우 워크플로의 명령도 선택한 방식에 맞춰야 한다.
등록 화면에서 저장했다고 연결이 검증된 것은 아니다. 등록 정보는 첫 성공 발행에서 확인되므로, 새 연결을 만든 뒤 실제 릴리스를 미루지 말고 검증 가능한 버전으로 배포를 진행한다. 잘못 등록한 연결은 필수 식별 정보를 수정하는 대신 삭제하고 다시 만들어야 한다.
발행 작업에만 OIDC 권한을 부여한다

배포 작업의 permissions에는 저장소를 가져오는 contents: read와 OIDC ID 토큰을 요청하는 id-token: write를 지정한다. 이 권한을 일반 테스트 작업까지 넓힐 필요는 없다. 실제 발행 작업이 어떤 이벤트에서 시작되는지와 어떤 러너에서 실행되는지도 워크플로에 명확히 둔다.
- 팀이 관리하는 릴리스 태그 등으로 발행 작업을 시작하고 GitHub 호스팅 러너에서 실행한다.
- actions/checkout으로 소스를 가져오고 actions/setup-node에서 지원되는 Node.js 버전과 https://registry.npmjs.org 레지스트리를 설정한다.
- npm ci로 의존성을 설치한 뒤 필요한 빌드와 테스트를 마치고 npm publish를 실행한다.
- 발행 단계에는 기존 npm 쓰기 토큰을 NODE_AUTH_TOKEN이나 다른 비밀값으로 전달하지 않는다.
지원되는 환경에서 npm CLI는 OIDC 신원을 감지해 발행 인증에 사용한다. 기존 쓰기 토큰이 발행 단계에 남아 있으면 배포가 성공하더라도 어느 인증 경로가 쓰였는지 분명하게 확인하기 어렵다. 첫 검증 배포에서는 발행 단계의 쓰기 토큰을 제거하되, npm 계정의 기존 토큰 자체는 새 경로를 확인할 때까지 유지한다.
비공개 npm 의존성을 설치해야 한다면 npm ci 단계에는 인증이 여전히 필요할 수 있다. 이때는 읽기 전용의 세분화된 토큰을 설치 단계에만 전달하고 npm publish 단계로 넘기지 않는다. Trusted Publishing이 대신하는 것은 패키지 발행 인증이지 비공개 의존성 설치 인증이 아니다.
자동 provenance의 생성 조건을 구분한다
GitHub Actions에서 Trusted Publishing으로 공개 저장소의 공개 패키지를 발행하면 provenance attestation이 기본으로 생성된다. 이 경로에서는 npm publish에 --provenance를 추가할 필요가 없다. 다만 환경 변수 NPM_CONFIG_PROVENANCE, .npmrc 또는 package.json의 publishConfig에서 provenance를 false로 지정했다면 자동 생성이 꺼질 수 있으므로 배포 설정을 함께 살펴야 한다.
provenance는 발행된 패키지 버전을 빌드 실행, 소스 커밋, 워크플로 파일과 연결한다. OIDC 인증은 발행을 요청한 워크플로의 신원을 확인하는 과정이고, provenance 확인은 소비자가 볼 수 있는 버전별 출처 기록이 남았는지 살피는 과정이다. 발행 로그의 성공 표시만 보고 후자의 결과까지 추정할 수는 없다.
비공개 저장소에서 발행한 공개 패키지에는 자동 provenance가 생성되지 않는다. 이런 경우 --provenance 옵션을 추가하는 것만으로 공개 저장소 조건을 충족할 수 없다. 출처 기록을 배포 요건으로 삼는 팀이라면 저장소의 공개 여부를 전환 계획 단계에서 결정해야 한다.
첫 배포에서 버전별 출처와 서명을 확인한다

새 버전이 레지스트리에 올라오면 해당 패키지 페이지의 Version 항목에서 녹색 확인 표시를 찾는다. npm의 provenance 확인 절차에 따라 상세 정보를 열면 빌드 환경과 실행 기록, 소스 커밋, 워크플로 파일, 공개 기록으로 이어지는 링크를 볼 수 있다. 이번 릴리스에 사용한 커밋과 워크플로가 표시된 내용과 일치하는지 대조한다.
명령줄에서는 대상 패키지를 의존성으로 설치한 프로젝트에서 npm install 또는 npm ci를 실행한 뒤 npm audit signatures를 사용한다. 이 명령은 내려받은 패키지의 레지스트리 서명과 provenance attestation을 검사하고, 누락되거나 유효하지 않은 서명 또는 증명이 있으면 오류를 반환한다. provenance 검증에는 npm CLI 9.5.0 이상이 필요하다.
확인 표시가 있어도 패키지 코드의 취약점까지 검사됐다는 뜻은 아니다. ENISA의 패키지 선택 권고는 패키지가 어디서 어떻게 발행됐는지와 승인된 발행자를 확인하고, 유효한 provenance 메타데이터가 있는 패키지를 우선하도록 제안한다. 의존성의 알려진 취약점은 별도로 점검해야 한다.
검증 후 기존 쓰기 토큰을 폐기한다
토큰 없이 실행한 첫 OIDC 배포가 성공하고 필요한 provenance까지 확인했다면, npm 계정에서 사용하지 않는 자동화 쓰기 토큰을 폐기하고 GitHub 저장소의 관련 비밀값을 정리한다. npm 패키지의 Settings → Publishing access에서 기존 토큰을 통한 발행을 허용하지 않는 옵션도 적용할 수 있다. 이 제한은 전통적인 토큰 인증에 적용되며 Trusted Publisher의 OIDC 발행은 계속 사용할 수 있다.
토큰을 먼저 폐기하면 등록 정보의 오타나 러너 제한이 첫 배포에서 드러났을 때 정상적인 릴리스 경로까지 잃을 수 있다. 반대로 검증을 마친 뒤에도 토큰을 보유하면 장기 자격 증명을 없애려던 목적이 완성되지 않는다. 비공개 의존성 설치에 쓰는 읽기 전용 토큰이 있다면 발행용 쓰기 토큰과 구분해 관리한다.
첫 발행이 인증 오류로 끝나면 등록한 소유자, 저장소, 워크플로 파일명과 id-token: write 권한을 대조한다. 재사용 워크플로를 호출한다면 호출하는 쪽의 워크플로 이름과 양쪽 워크플로의 권한도 확인한다. 발행은 성공했지만 provenance가 보이지 않는다면 저장소와 패키지의 공개 상태, provenance 비활성화 설정, 확인 중인 패키지 버전을 순서대로 살핀다.
함께 읽기:
관련 기사
뉴스레터 구독
최신 Web3, AI, 암호화폐 뉴스를 이메일로 받아보세요.




