~/infra-dev.md
INFRA_DEV

배포된 것만 위험한 것은 아니지만, 먼저 고쳐야 한다: GitHub Linked Artifacts로 보는 코드-클라우드 추적성

10분 읽기·2026.07.22·출처 5·00
오늘의 질문

보안 알림이 500개일 때, 어떤 취약점을 지금 운영 중인 서비스의 위험으로 먼저 볼 수 있을까?

infra-dev.md
Code-to-cloud traceability

배포된 것만 위험한 것은 아니지만, 먼저 고쳐야 한다: GitHub Linked Artifacts로 보는 코드-클라우드 추적성

1. 왜 지금 봐야 하나

보안 알림은 대부분 “코드 저장소”에서 시작한다. Dependabot은 취약한 패키지를 알려주고, code scanning은 위험한 코드 패턴을 알려준다. 문제는 운영자가 실제로 궁금한 질문이 조금 다르다는 것이다.

이 알림이 지금 고객 트래픽을 받는 배포물에 들어가 있는가?

GitHub는 2026년 1월 changelog에서 Linked artifacts와 artifact metadata API를 통해 컨테이너·바이너리 같은 build artifact를 GitHub에 연결하고, 저장 위치와 배포 컨텍스트를 붙일 수 있다고 발표했다. 핵심은 artifact 파일을 GitHub에 다시 올리는 것이 아니다. artifact가 어디서 빌드됐고, 어느 registry에 저장됐고, 어떤 환경에 배포됐고, 런타임 위험이 무엇인지를 메타데이터로 연결하는 것이다.

작은 팀에게도 이 변화는 중요하다. AI가 PR을 더 많이 만들고, 의존성 업데이트가 더 자주 생기고, 보안 스캐너가 더 많은 알림을 내면 “모든 것을 즉시 고친다”는 전략은 무너진다. 이제 필요한 것은 더 큰 대시보드가 아니라, 빌드와 배포 사이의 추적성이다.

오늘의 핵심 문장은 이것이다.

공급망 보안의 첫 단계는 서명을 붙이는 것이고, 운영 우선순위의 첫 단계는 그 서명된 결과물이 실제 어디서 돌고 있는지 연결하는 것이다.

2. 핵심 개념

Linked artifacts는 GitHub 조직 안에서 GitHub Actions로 빌드한 artifact의 메타데이터를 한곳에 모아 보여주는 기능이다. 공식 문서는 이 페이지가 artifact 파일 자체를 저장하지 않고, artifact와 관련된 메타데이터의 authoritative source 역할을 한다고 설명한다.

여기서 봐야 할 개념은 세 가지다.

첫째, artifact attestation이다. GitHub Actions의 actions/attest@v4는 빌드 결과물에 대해 “어느 repository, commit, workflow에서 만들어졌는가”를 증명하는 provenance attestation을 생성한다. 컨테이너 이미지라면 subject-name은 태그 없는 fully-qualified image name이고, subject-digestsha256:HEX_DIGEST 형식이어야 한다. push-to-registry: true를 쓰면 attestation을 registry에 푸시할 수 있다.

둘째, storage record다. storage record는 artifact가 어느 package registry에 저장되어 있는지, 어떤 source repository와 연결되는지, 어떤 attestation이 있는지를 설명한다. GitHub changelog는 GitHub의 attest-build-provenance action이 artifact publish 시 storage record를 자동 생성할 수 있다고 설명한다. 문서 기준으로는 push-to-registry: trueartifact-metadata: write 권한이 필요하다.

셋째, deployment record다. deployment record는 artifact가 어느 환경에 배포됐는지와 런타임 위험을 기록한다. GitHub REST API 문서는 deployment record에 artifact name, digest, status, logical_environment, physical_environment, cluster, deployment_name, runtime_risks 등을 보낼 수 있다고 설명한다. runtime_risks 값에는 critical-resource, internet-exposed, lateral-movement, sensitive-data 같은 값이 있다.

정리하면 다음 흐름이다.

zsh — 생존확인.sh
source repo/commit/workflow
  -> build artifact digest
  -> provenance attestation
  -> storage record: registry 위치
  -> deployment record: prod/staging, cluster, runtime risk
  -> alert filter: has:deployment, runtime-risk:internet-exposed

이 흐름이 생기면 “취약점이 있다”와 “고객에게 노출된 prod artifact에 그 취약점이 있다”를 분리할 수 있다.

3. 최신 이슈와 연결

GitHub의 2026년 1월 발표는 code-to-cloud traceability를 강조한다. 새 REST API endpoint로 artifact 저장 위치, release pipeline promotion, 배포 데이터, runtime risk를 연결할 수 있고, Linked artifacts view에서 attestation·storage·deployment history를 함께 볼 수 있다는 내용이다.

중요한 점은 GitHub가 이 데이터를 보안 triage 표면에 연결한다는 것이다. 공식 튜토리얼은 production context를 제공하려면 두 지점을 업데이트하라고 안내한다.

  • artifact가 production-approved package repository로 승격될 때 storage record를 업데이트한다.
  • artifact가 production environment에 배포될 때 deployment record를 업데이트한다.

그 다음에는 alert view에서 artifact-registry-url, artifact-registry, has:deployment, runtime-risk 같은 필터를 쓸 수 있다. 예를 들어 인터넷에 노출된 배포물의 알림만 먼저 보려면 다음처럼 생각할 수 있다.

zsh — 생존확인.sh
has:deployment AND runtime-risk:internet-exposed

이것은 보안 팀만의 기능이 아니다. 인프라·플랫폼 팀의 CD 파이프라인 설계 문제다. deploy job이 이미지 digest를 모르면 deployment record를 정확히 쓸 수 없다. cluster runtime monitor가 어떤 image digest가 실제 pod에서 도는지 모르면 “배포됨” 상태가 drift된다. registry promotion 규칙이 없으면 storage record가 “운영 승인 artifact”라는 의미를 갖기 어렵다.

즉 최신 이슈는 “GitHub 보안 기능 추가”가 아니라, CI/CD 파이프라인이 빌드 결과물의 digest와 배포 컨텍스트를 일급 데이터로 다뤄야 한다는 신호다.

4. 개발자 관점 해석

개발자가 이 주제를 배울 때 가장 조심해야 할 오해는 “attestation만 만들면 끝”이라는 생각이다.

Attestation은 출생증명서에 가깝다. 이 artifact가 어디서 태어났는지, 어떤 workflow에서 만들어졌는지를 증명한다. 하지만 출생증명서만으로는 지금 어디서 일하고 있는지 알 수 없다. 운영 우선순위에는 배포 기록이 필요하다.

반대로 deployment record만 있으면 “무엇이 돌고 있는지”는 보이지만, 그 artifact가 신뢰할 수 있는 빌드에서 왔는지 약하다. 그래서 둘은 경쟁 관계가 아니라 연결 관계다.

작은 팀에서 실무적으로 중요한 경계는 네 가지다.

  1. 태그보다 digest를 기준으로 삼기 latest, prod, main 태그는 움직인다. 취약점 triage와 배포 추적은 sha256:... digest를 기준으로 해야 한다. 그래야 같은 이미지를 registry, attestation, cluster, alert에서 같은 객체로 볼 수 있다.

  2. 빌드 파이프라인과 배포 파이프라인의 책임 분리 빌드 job은 artifact를 만들고 attestation과 storage record를 남긴다. 배포 job 또는 runtime monitor는 “이 digest가 어느 환경에 배포됐다”는 deployment record를 남긴다. 한 job에 모두 넣을 수는 있지만, 책임은 분리해서 생각해야 장애 대응이 쉽다.

  3. runtime risk를 사람이 읽는 라벨이 아니라 정책 입력으로 보기 internet-exposed, sensitive-data 같은 값은 설명용 태그가 아니다. 앞으로 어떤 alert를 먼저 볼지, 어떤 repository에 ruleset을 적용할지, 어떤 campaign을 만들지 결정하는 정책 입력이다. 잘못 붙이면 조용히 우선순위가 왜곡된다.

  4. GitHub deployments dashboard와 deployment record를 혼동하지 않기 Linked artifacts 문서는 deployment record가 repository deployment dashboard의 활동과 다른 source라고 명시한다. “GitHub Deployment 이벤트가 있으니 Linked artifacts도 채워지겠지”라고 가정하면 안 된다. 별도의 metadata upload 경로를 설계해야 한다.

5. 내 프로젝트에 적용할 체크포인트

아래 질문에 답할 수 없으면, 보안 알림 우선순위는 아직 코드 저장소 기준에 머물러 있을 가능성이 높다.

  • 프로덕션 컨테이너 이미지를 tag가 아니라 digest로 기록하고 있는가?
  • GitHub Actions build workflow에 id-token: write, contents: read, attestations: write 권한이 명시돼 있는가?
  • 컨테이너 이미지 attestation에서 subject-name에 태그를 넣지 않고, subject-digest를 build output에서 가져오는가?
  • artifact publish 시점에 storage record 또는 자동 storage upload가 남는가?
  • CD 파이프라인이 logical_environment=prod, cluster, deployment_name, digest를 알 수 있는가?
  • 인터넷 노출, 민감 데이터 처리, 핵심 리소스 여부 같은 runtime risk를 누가 결정하는지 정해져 있는가?
  • 배포 삭제 또는 rollback 때 status=decommissioned 같은 상태 전환을 남기는가?
  • Dependabot/code scanning 알림을 볼 때 “production context filter”로 먼저 좁히는 triage runbook이 있는가?

최소 구현은 거창하지 않아도 된다. 첫 번째 목표는 모든 서비스를 연결하는 것이 아니라, 가장 중요한 프로덕션 서비스 하나에 대해 “build digest -> registry -> prod deployment -> runtime risk” 선을 끊기지 않게 만드는 것이다.

6. 오늘 10분 액션

오늘 바로 할 수 있는 작은 실험은 다음과 같다.

  1. 최근 배포된 프로덕션 서비스 하나를 고른다.
  2. 그 서비스의 현재 image digest를 확인한다. Kubernetes라면 kubectl get pod -o json에서 imageID를 보면 registry digest가 보인다.
  3. GitHub Actions 빌드 로그에서 같은 digest가 어디서 생성됐는지 찾는다.
  4. 그 workflow에 attestation 생성 step을 넣을 위치를 표시한다.
  5. CD job이 deployment record에 넣을 수 있는 값을 표로 적는다.

예시 표는 이렇게 시작하면 된다.

zsh — 생존확인.sh
artifact name: api-server
digest: sha256:...
source repo: org/api
logical_environment: prod
physical_environment: ap-northeast-2
cluster: main-prod
 deployment_name: api-server-web
runtime_risks: internet-exposed, sensitive-data

이 표를 만들다 막히는 지점이 바로 추적성의 구멍이다. digest를 모르면 build와 deploy가 끊긴 것이다. runtime risk를 못 정하면 보안 우선순위 정책이 아직 운영 모델과 연결되지 않은 것이다.

7. 더 볼 자료

  • GitHub Changelog: code-to-cloud traceability와 SLSA Build Level 3 보안 발표
  • GitHub Docs: Linked artifacts 개념 문서
  • GitHub REST Docs: Artifact metadata API, deployment/storage record endpoint
  • GitHub Docs: Artifact attestations 생성과 검증
  • GitHub Docs: production context로 Dependabot/code scanning 알림 우선순위 정하기

중복 회피 메모

로컬 content/generated와 Supabase 최근 infra_dev 글을 확인했다. 최근 글은 Kubernetes In-place Pod Resize, Terraform state secret, GitHub Actions step-level 병렬화, OpenTelemetry semantic convention 카디널리티, RDS delayed replica, GitHub secret scanning triage, Vercel AI Gateway routing, pull_request_target 보안, OIDC subject/audience, Kubernetes Indexed Job 실패 예산, Cloudflare Queues backlog/DLQ를 다뤘다. 이번 글은 GitHub Actions를 다시 언급하지만 workflow 권한·OIDC·secret scanning·step 병렬화가 아니라, artifact attestation과 artifact metadata API로 build artifact digest, storage record, deployment record, runtime risk를 연결해 “운영 중인 배포물 기준”으로 보안 알림 우선순위를 정하는 code-to-cloud traceability에 집중해 중복을 피했다.

오늘 10분 액션+5%

댓글 0

최신순 ▾
한 줄 남기기

혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)