-
[GitHub Actions][공급망보안] gh attestation verify와 offline bundle 검증을 온라인·에어갭 환경 기준으로 언제 나누나기타개발지식/풀스택개발 2026. 8. 19. 09:15
IT 리서치 노트
[GitHub Actions][공급망보안] gh attestation verify와 offline bundle 검증을 온라인·에어갭 환경 기준으로 언제 나누나
GitHub artifact attestation을 도입한 뒤 운영팀이 자주 헷갈리는 질문은 하나다. `gh attestation verify`를 쓰면 끝나는지, 아니면 오프라인 배포망에서는 bundle과 trusted root를 따로 패키징해야 하는지다. 2026년 8월 18일 기준 GitHub 공식 문서를 다시 보면 기본 verify는 온라인 환경을 전제하고, air-gapped 환경은 별도 offline verification 절차를 사용하도록 분리해 두고 있다. 이 글은 두 경로를 같은 release runbook에서 언제 갈라야 하는지 정리한다.
1. 개요
결론부터 말하면
인터넷이 연결된 CI·검증 환경에서는 `gh attestation verify`를 기본으로 쓰고,에어갭 또는 오프라인 승인 환경에서는 bundle 다운로드와 trusted root 준비를 선행한 뒤 `--bundle --custom-trusted-root` 경로로 검증하는 편이 맞다. 핵심은 명령 차이보다 입력물 차이다.즉 online verify는 GitHub가 조회 가능한 환경을 전제로 하고, offline verify는 미리 수집한 bundle과 trusted root를 evidence 패키지로 갖고 들어가는 작업이다. release gate 문서에는 두 경로를 같은 검증 단계로 적지 말고 환경 기준으로 분리해야 한다.
2. 어디서 실제로 막히는가
실무에서 막히는 패턴은 대체로 네 가지다. 첫째, workflow에서 attestation을 생성하지 않았는데 verify 명령만 반복한다. 둘째, 온라인에서 성공한 명령을 air-gapped 검증망에 그대로 복사한다. 셋째, bundle 파일은 옮겼는데 trusted root 생성 시각과 파일을 같이 안 옮겨 검증 근거가 끊긴다. 넷째, artifact digest, repo, bundle 파일명, trusted root 버전을 감사 로그에 따로 저장하지 않아 나중에 재검증이 어려워진다.
GitHub 공식 문서는 attestation 생성에 필요한 workflow permissions와 `actions/attest` step을 먼저 보여 주고, verify 예시는 온라인 환경을 전제한다고 명시한다. 이어서 offline guide에서는 attestation bundle을 다운로드하고 trusted root를 가져온 뒤, CLI·artifact·bundle·trusted root 네 가지를 오프라인 환경으로 들고 가라고 적는다. 이 구조를 그대로 operational split으로 바꾸지 않으면 “verify는 했는데 왜 배포망에서 또 안 되지?” 같은 혼선이 반복된다.
또 다른 문제는 provenance 생성과 검증을 같은 티켓에서 다루며 registry drift나 release evidence 보존 이슈를 섞는 것이다. 검증 실패의 원인이 artifact 부재인지, attestation 부재인지, bundle 누락인지, trusted root 갱신 누락인지 먼저 나눠야 한다. 그래야 나중에 offline verification incident와 multi-registry digest mismatch incident를 अलग게 회고할 수 있다.
- 증상: 온라인 verify는 되는데 에어갭 검증망에서는 실패한다.
- 오류: bundle 파일만 복사하고 trusted root 파일을 누락한다.
- 실패: workflow에 attest 생성 단계가 없는데 verify만 실행한다.
- 재발: artifact digest, bundle, trusted root 버전을 release record에 저장하지 않는다.
증상 먼저 볼 값 즉시 할 동작 verify 결과가 비어 있음 workflow permissions, attest step 생성 단계 존재 여부를 로그에서 확인한다 에어갭에서 재현 불가 bundle, trusted root 동봉 여부 온라인 기계에서 다운로드 후 파일을 저장한다 감사 로그 불충분 digest, repo, bundle 파일명 release evidence record를 작성한다 3. 실무에서 적용하는 순서
실무 분기 기준은 단순하다. 네트워크가 열려 있고 GitHub 조회가 가능한 환경이면 artifact 경로 또는 `oci://` ref를 주고 바로 verify한다. 오프라인 검증이 필요한 환경이면 먼저 온라인 기계에서 bundle을 다운로드하고, trusted root를 생성하고, artifact와 함께 같은 evidence 묶음으로 저장한 뒤 에어갭 환경으로 옮겨 verify한다. release check 단계에서는 “검증 환경이 어디인가”를 첫 질문으로 두는 편이 좋다.
- workflow에 attest 생성 단계와 권한이 있는지 확인한다.
- 검증 환경이 온라인인지 오프라인인지 먼저 분리한다.
- 오프라인이면 bundle과 trusted root를 온라인 기계에서 다운로드한다.
- artifact, digest, repo, bundle 파일명을 release record에 저장한다.
- 검증 명령 출력과 입력물 버전을 감사 로그에 같이 남긴다.
이후 운영자는 artifact를 조회하고, bundle을 다운로드하고, trusted root를 저장하고, verify 명령을 실행하고, 결과 로그를 파일로 남겨야 한다. 명령 실행만 하고 입력물 패키징을 기록하지 않으면 오프라인 검증은 재현이 안 되고, 보안 감사에서는 “무엇으로 검증했는가”가 남지 않는다.
4. 공식 문서와 예시 화면으로 확인하기
첫 공식 화면은 생성 단계 전제조건이다. GitHub는 artifact attestation을 만들 때 workflow permissions와 attest step을 먼저 갖추라고 설명한다. 검증이 실패할 때도 출발점이 없는 attestation인지부터 확인해야 한다.
즉 verify 단계만 보고 들어가면 안 된다. 검증이 비어 보이는 경우는 CLI 문제가 아니라 애초에 attest 생성 경로가 빠진 배포일 수 있다.
두 번째 공식 화면은 GitHub CLI verify 기본값이 온라인 환경을 전제한다는 문장이다. 보안팀이 가장 자주 놓치는 지점이 여기다. gh attestation verify가 된다고 해서 같은 명령을 air-gapped 검증실에 그대로 들고 갈 수는 없다.
이미 Docker build-push-action 기본 provenance와 actions/attest를 함께 쓰는 글이 생성 단계 판단을 다뤘다면, 이번 글은 검증 단계에서 online verify와 offline bundle verify를 어디서 갈라야 하는지를 더 좁힌 후속편이다.
세 번째 공식 화면은 offline verification에 필요한 입력 묶음이다. GitHub CLI, artifact, bundle, trusted root 네 가지를 오프라인 환경으로 가져오라고 적혀 있다. 검증 실패를 줄이려면 이 네 항목을 release evidence 패키지로 같이 저장해야 한다.
또 다른 관련 후속으로는 multi-registry digest drift와 단일 registry attestation 검증 순서를 다룬 글이 있다. 이번 글은 registry drift 이전에 online/offline 검증 경로를 먼저 나누는 기준을 붙이는 역할이다.
운영 메모는 online verify와 offline verify를 같은 표에 두는 편이 가장 짧다. 어떤 저장물과 어떤 명령이 필요한지 분리해 두면 release gate가 빨라진다.
특히 보안 승인 절차에서 네트워크가 있는 release runner와 에어갭 배포망이 섞인 조직이라면 이 표가 없으면 같은 티켓에 서로 다른 실패 원인이 섞인다.
명령도 online path와 offline path를 따로 보관하는 편이 좋다. verify 한 줄만 저장하면 bundle을 어디서 받았는지, trusted root를 언제 갱신했는지 남지 않는다.
실무에서는 이 명령 파일을 저장하고, artifact digest를 확인하고, bundle 이름을 기록하고, trusted root 생성 시각을 남겨 두는 네 단계를 같이 실행해야 한다.
5. 주의사항과 리스크
첫 번째 리스크는 online verify 성공을 offline verify 성공과 같은 신호로 읽는 것이다. 두 번째는 bundle은 옮기지만 trusted root 갱신 시각을 안 남겨 key rotation 시점을 놓치는 것이다. 세 번째는 artifact와 bundle을 따로 보관해 나중에 어느 파일 쌍이 같은 release였는지 찾지 못하는 것이다.
검증 전에 확인할 최소 칸은 verify mode, repo, artifact digest, bundle 파일명, trusted root 생성 시각이다. 팀은 값을 입력하고, 파일을 저장하고, 명령을 실행하고, 결과를 조회하고, 로그를 보관하는 순서를 같은 템플릿으로 유지해야 한다.
- online verify와 offline verify는 입력물이 다르다.
- trusted root는 갱신 시각까지 같이 저장해야 한다.
- release evidence에는 digest와 bundle 파일명을 함께 남긴다.
에어갭 운영팀이 실제 반입 순서와 manifest 필드를 더 촘촘하게 고정해야 한다면 bundle, trusted roots, artifact 반입 순서를 체크리스트로 고정한 후속 글을 이어서 보면 online/offline 환경 분기 다음 단계인 증빙 패키지 구성까지 바로 연결된다.
6. 결론
GitHub artifact attestation 검증은 명령어 하나의 차이가 아니라 환경과 입력물의 차이다. 온라인 환경이면 `gh attestation verify`로 빠르게 확인하고, 에어갭 환경이면 bundle과 trusted root를 준비한 뒤 offline verify로 분기해야 release gate와 감사 로그가 덜 꼬인다.
- 먼저 검증 환경이 온라인인지 오프라인인지 나눈다.
- 오프라인 검증에는 bundle과 trusted root가 필수다.
- 결과뿐 아니라 입력물 패키지를 release evidence로 저장한다.
7. 참고 링크
- https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations
- https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/verify-attestations-offline
- https://cli.github.com/manual/gh_attestation_verify
- https://cli.github.com/manual/gh_attestation_download
- https://cli.github.com/manual/gh_attestation_trusted-root
'기타개발지식 > 풀스택개발' 카테고리의 다른 글