-
[npm][보안] staged artifact rollback에서 reviewer 2FA 흔적과 stage ID를 어떤 감사 필드로 고정하나기타개발지식/풀스택개발 2026. 8. 21. 20:17
IT 리서치 노트
[npm][보안] staged artifact rollback에서 reviewer 2FA 흔적과 stage ID를 어떤 감사 필드로 고정하나
npm staged publishing을 운영하다 보면 rollback 메모가 package version과 dist-tag 쪽으로만 쏠리고, 정작 reviewer 2FA 흔적과 stage ID는 뒤늦게 찾게 되는 경우가 많다. 하지만 2026년 8월 21일 기준 npm 공식 문서를 다시 보면 staged artifact lifecycle은 stage-id 중심으로 움직이고, stage publish는 2FA를 나중 승인 단계로 미루며, bypass 2FA token도 staged approval의 2FA를 우회하지 못한다. 이 글은 staged artifact rollback에서 reviewer 2FA 흔적과 stage ID를 어떤 감사 필드로 고정해야 incident 복기가 짧아지는지 정리한다.
1. 개요
결론부터 말하면 npm staged artifact rollback 메모의 첫 칸은 package version이 아니라
stage-id여야 하고, 두 번째 칸은reviewer + 2FA 확인 시각이어야 한다. stage publish는 CI가 2FA 없이 올릴 수 있지만 approve·reject 판단은 proof-of-presence가 필요한 별도 단계이기 때문이다.이 둘을 고정하지 않으면 reject, approve 보류, re-stage, dist-tag rollback이 모두 "release 되돌리기"처럼 보여도 artifact 축과 live registry 축을 다시 분리할 수 없다. stage-id는 승인 전 artifact를 식별하고, reviewer 2FA 흔적은 사람이 그 artifact에 개입했다는 보안 증거를 남긴다.
2. 어디서 실제로 막히는가
실무에서 흔한 실패는 rollback을 version 메모 하나로 닫는 것이다. 예를 들어
@scope/pkg@2.4.1을 reject했는데 어떤 stage-id였는지 안 적으면, 나중에 같은 version을 다시 stage한 사건과 원래 reject 사건이 섞인다. 또 CI가 stage publish를 했다는 사실만 적고 reviewer가 언제 2FA로 approve 또는 reject했는지 안 남기면 proof-of-presence가 있었는지 회고가 불가능해진다.npm stage 문서는 view·approve·reject가 모두 stage-id를 기준으로 동작한다고 적고, stage publish는 2FA prompt를 요구하지 않아 proof-of-presence를 나중으로 미룬다고 설명한다. creating and publishing public packages 문서는 bypass 2FA가 켜진 granular access token도 staged package approval의 2FA를 우회하지 못한다고 못 박는다. trusted publishers 문서는 OIDC로 할 수 있는 것은 publish 또는 stage publish까지이며, stage view·approve·reject는 interactive auth가 필요하다고 적는다. 이 네 문장을 합치면 artifact lifecycle의 감사 중심은 version이 아니라 stage-id와 reviewer action이다.
문제가 더 커지는 지점은 dist-tag rollback과 섞일 때다. live registry에서 latest를 되돌리는 일은 이미 공개된 install path를 바꾸는 사건이고, staged artifact reject는 승인 전 artifact를 폐기하는 사건이다. version만 적고 넘어가면 이 두 사건이 같은 시간축에 겹쳐져 누가 무엇을 승인했고 무엇을 공개 경로에서 되돌렸는지 분리되지 않는다.
- 증상: 같은 version이 두 번 stage됐는데 어느 artifact를 reject했는지 다시 못 찾는다.
- 실패: reviewer와 2FA 흔적을 stage 메모에 안 남긴다.
- 막힘: approve 보류와 dist-tag rollback을 같은 줄에 적는다.
- 누락: trusted publisher action scope와 re-stage 여부를 함께 기록하지 않는다.
보이는 장면 섞이면 안 되는 필드 먼저 적을 값 artifact를 reject했다 package version만 적고 종료 stage-id, reviewer, 2FA 확인 시각 같은 version을 다시 stage했다 old/new stage-id 혼합 new stage-id, target tag, reason latest도 잘못 노출됐다 artifact 사건과 live tag 사건 혼합 dist-tag 기록, operator, registry 조회 결과 3. 실무에서 적용하는 순서
가장 짧은 방법은 rollback 메모를 두 블록으로 자르는 것이다. 첫째 블록은 staged artifact block이다. 여기에 stage-id, package@version, reviewer, 2FA 확인 시각, 결정, re-stage 필요 여부를 넣는다. 둘째 블록은 live registry block이다. dist-tag rollback이 실제로 있었을 때만 package@version, old tag, new tag, operator, registry 재조회 결과를 넣는다.
- stage view 결과에서 stage-id를 먼저 고정한다.
- approve 또는 reject 판단을 한 reviewer와 2FA 흔적을 적는다.
- reject 사유와 re-stage 필요 여부를 artifact block에 적는다.
- live dist-tag 변경이 있었을 때만 별도 registry block을 연다.
- 새 artifact를 stage했다면 new stage-id를 새 줄로 만든다.
- stage-id를 조회하고 reviewer를 기록하고 2FA 시각을 저장한다.
- reject 이유를 분리하고 re-stage 여부를 확인하고 target tag를 비교한다.
- registry 상태를 재조회하고 operator를 남기고 live 사건을 분리한다.
- 새 artifact를 다시 stage하고 새 stage-id를 적고 승인 경로를 추적한다.
- approve 또는 reject를 명시하고 proof-of-presence를 검증하고 audit line을 유지한다.
- tag 변경을 점검하고 tarball 결과를 확인하고 incident 복구 메모를 저장한다.
실제 대응에서는 stage view 조회 결과, approve 또는 reject 응답, registry 조회 결과, 남겨 둘 로그 파일, 바꾼 설정, 검토한 권한 범위, 다시 실행한 명령까지 한 묶음으로 저장하는 편이 좋다. 이 기록이 있어야 같은 incident를 다시 확인할 때 artifact 축과 live 축을 빠르게 분리할 수 있다.
이 방식의 장점은 staged artifact와 live package distribution을 서로 다른 속도로 복구할 수 있다는 점이다. 어떤 incident는 stage reject로 끝나고 live registry에는 아무 변화가 없을 수 있다. 반대로 어떤 incident는 artifact reject와 동시에 latest 복구까지 해야 한다. 두 사건을 같은 줄에 넣으면 package version 하나만 남고, 사람 승인 흔적과 stage lineage가 지워진다.
또 reviewer 2FA 흔적은 단순 참고용이 아니다. npm이 staged approval에서 proof-of-presence를 요구하도록 설계한 이상, 누가 어떤 경로로 approve·reject했는지를 남기는 것이 공급망 운영 기록의 핵심이다. token bypass 2FA가 approve를 우회하지 못한다는 문장도 이 설계를 뒷받침한다. stage-id와 reviewer 2FA를 먼저 적고, 그 다음에야 dist-tag나 trust permission을 붙이는 순서가 맞다.
4. 공식 문서와 예시 화면으로 확인하기
첫 공식 자료는 npm stage subcommands 구간이다. npm은 view, approve, reject가 모두 stage-id를 기준으로 움직인다고 명확히 적어 둔다.
즉 rollback 메모를 package@version 하나로 끝내면 승인 전 artifact 사건을 다시 못 따라간다. reviewer 2FA 흔적도 결국 특정 stage-id에 연결돼야 audit trail이 닫힌다.
두 번째 공식 자료는 token behavior 설명이다. npm은 stage publish 자체는 2FA prompt를 요구하지 않고, proof-of-presence를 나중 승인 단계로 미룬다고 설명한다.
이 전제가 있으면 CI가 artifact를 올린 시각과 사람이 approve·reject 판단을 한 시각을 같은 줄에 뭉개면 안 된다는 결론이 나온다. stage-id는 artifact 축이고 reviewer 2FA는 proof-of-presence 축이다.
세 번째 공식 자료는 staged approval의 2FA 한계다. npm은 bypass 2FA가 켜진 granular access token이라도 staged package approval의 2FA를 우회하지 못한다고 못 박는다.
이 문장 때문에 rollback 메모에서 reviewer 2FA 흔적을 optional 필드처럼 다루면 안 된다. live publish와 달리 staged artifact lifecycle은 사람 승인 사실 자체가 보안 증거가 된다.
실무에서는 stage-id와 reviewer 2FA 흔적을 어떤 칸에 고정할지 먼저 정하는 편이 좋다. stage reject, approve 보류, re-stage, live rollback은 모두 release incident처럼 보이지만 남겨야 할 값이 다르다.
이미 stage reject와 org member removal 분기 글과 dist-tag recovery 글로 바깥 축을 다뤘다면, 이번 표는 staged artifact rollback 안쪽 audit 필드만 더 좁게 정리한 판이다.
마지막 자료는 rollback memo 예시다. stage-id와 reviewer 2FA 흔적을 별도 블록으로 고정해 두면 CI staging과 사람 승인 판단을 한눈에 분리할 수 있다.
이 정도만 있어도 release incident 회고에서 '누가 reject 했는지', '2FA proof-of-presence가 있었는지', '같은 version을 다시 stage 했는지'를 package version 하나보다 훨씬 정확히 복원할 수 있다.
5. 주의사항과 리스크
첫 번째 리스크는 reject 사건을 version 메모만 남기고 끝내는 것이다. 두 번째는 reviewer 2FA를 구두 확인에만 두고 시간과 경로를 안 적는 것이다. 세 번째는 dist-tag recovery가 일어나지 않았는데도 rollback 메모에 미리 넣어 artifact 사건과 섞는 것이다.
운영 전에 확인할 때는 최소한 stage-id, review actor, 2FA 확인 시각, decision, re-stage 여부 다섯 값을 artifact block 기본값으로 고정해 두는 편이 좋다. 그래야 rollback 메모가 사람 기억이 아니라 stage lineage 기준으로 남는다.
- stage-id는 package version보다 먼저 적는다.
- reviewer 2FA 흔적은 선택값이 아니라 proof-of-presence 증거다.
- artifact 사건과 live registry 사건은 별도 블록으로 둔다.
6. 결론
npm staged artifact rollback을 짧게 복기하려면 package version보다 stage-id와 reviewer 2FA 흔적을 먼저 고정하는 편이 맞다. stage-id는 승인 전 artifact lineage를, reviewer 2FA는 사람 개입 증거를 남긴다. 그다음에만 dist-tag 같은 live registry 사건을 별도 블록으로 붙이면 release incident가 훨씬 읽기 쉬워진다.
여기서 한 걸음 더 나가 approve actor 시점과 reviewer 2FA 시점을 실제 사건 시간축으로 나눠 적고 싶다면 같은 날 발행한 approve actor와 reviewer 2FA 시점을 어떤 incident timeline으로 분리하나를 바로 이어서 보면 된다. 그 글은 artifact staged_at, review decision_at, live visible_at, rollback action_at을 따로 적는 후속편이다.
- artifact block의 기본 필드는 stage-id와 reviewer 2FA다.
- re-stage가 생기면 new stage-id를 새 줄로 만든다.
- live rollback은 별도 registry block으로 분리한다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글