<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Artifact Attestation on jyukki's Blog</title><link>https://jyukki.com/tags/artifact-attestation/</link><description>Recent content in Artifact Attestation on jyukki's Blog</description><generator>Hugo -- 0.147.0</generator><language>ko-KR</language><lastBuildDate>Mon, 31 Aug 2026 10:06:00 +0900</lastBuildDate><atom:link href="https://jyukki.com/tags/artifact-attestation/index.xml" rel="self" type="application/rss+xml"/><item><title>2026 개발 트렌드: Artifact Attestation, 빌드 증명이 배포 승인 조건으로 이동한다</title><link>https://jyukki.com/posts/2026-08-31-artifact-attestation-deployment-admission-gate-trend/</link><pubDate>Mon, 31 Aug 2026 10:06:00 +0900</pubDate><guid>https://jyukki.com/posts/2026-08-31-artifact-attestation-deployment-admission-gate-trend/</guid><description>GitHub Actions artifact attestation과 Sigstore Policy Controller를 바탕으로, 빌드 provenance를 릴리스 배지에 머물게 하지 않고 Kubernetes 배포 admission·예외·rollback까지 연결하는 운영 기준을 정리합니다.</description><content:encoded><![CDATA[<p>소프트웨어 공급망 보안에서 &ldquo;서명했다&quot;는 말은 너무 쉽게 결론이 됩니다. 하지만 이미지에 provenance가 붙어도 배포 플랫폼이 그것을 읽지 않으면 증명은 release page의 장식에 머뭅니다. 반대로 Kubernetes admission이 검증을 강제하더라도, tag만 보고 검증하거나 예외가 무기한이면 실제 trust boundary는 넓습니다. 최근의 중요한 흐름은 artifact attestation을 더 많이 발행하는 데 있지 않습니다. <strong>빌드 증명을 배포 시점의 허용·보류 판단에 넣고, 그 판단을 rollback 가능한 운영 절차로 만드는 데</strong> 있습니다.</p>
<p>GitHub Actions는 binary와 container image에 build provenance를 위한 artifact attestation을 생성하고 검증하는 경로를 제공하며, Kubernetes에서는 Sigstore Policy Controller를 통해 signature·attestation 정책을 admission 단계에서 적용할 수 있습니다. SLSA도 provenance의 존재 자체와 build tampering에 대한 보호 수준을 분리해 설명합니다. 이 글은 이 세 흐름을 합쳐, &ldquo;attestation이 있는가&quot;가 아니라 <strong>이 digest가 승인된 workflow에서 만들어졌고 지금 이 workload에 배포돼도 되는가</strong>를 판단하는 실무 기준으로 정리합니다.</p>
<p>이 글은 <a href="/posts/2026-07-30-publish-time-supply-chain-review-context-trend/">Publish-Time Supply Chain Gate와 Review Context Plane</a>, <a href="/posts/2026-07-04-ci-native-agent-runner-actions-token-trend/">CI-native Agent Runner와 Actions Token</a>, <a href="/posts/2026-05-12-package-release-quarantine-gate-trend/">Package Release Quarantine Gate</a>, <a href="/learning/deep-dive/deep-dive-kubernetes-rollouts/">Kubernetes 롤아웃 전략과 무중단 배포</a>의 다음 단계입니다. 앞선 글이 package 공개와 workflow 실행 전 멈춤을 다뤘다면, 여기서는 검증된 build artifact가 runtime 배포 경계에 들어가는 순간을 다룹니다.</p>
<p>참고한 공식 자료:</p>
<ul>
<li><a href="https://docs.github.com/en/actions/concepts/security/artifact-attestations">GitHub Docs: Artifact attestations</a></li>
<li><a href="https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations">GitHub Docs: Generating build provenance</a></li>
<li><a href="https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/enforce-artifact-attestations">GitHub Docs: Enforcing artifact attestations with Kubernetes admission</a></li>
<li><a href="https://docs.sigstore.dev/policy-controller/overview/">Sigstore Policy Controller overview</a></li>
<li><a href="https://slsa.dev/spec/v1.1/levels">SLSA Build Levels</a></li>
</ul>
<h2 id="이-글에서-얻는-것">이 글에서 얻는 것</h2>
<ul>
<li>attestation, image digest, signature, SBOM, vulnerability scan이 각각 답하는 질문을 구분합니다.</li>
<li>GitHub Actions provenance를 어떤 workflow identity와 artifact subject로 검증해야 하는지 이해합니다.</li>
<li>Kubernetes admission을 all-or-nothing 차단이 아닌 관찰·canary·enforcement 단계로 도입하는 기준을 얻습니다.</li>
<li>예외, revocation, rollback을 포함해 배포 gate가 가용성을 해치지 않도록 운영하는 방법을 배웁니다.</li>
</ul>
<h2 id="핵심-개념이슈">핵심 개념/이슈</h2>
<h3 id="1-attestation은-안전하다가-아니라-어떻게-만들어졌는가에-답한다">1) Attestation은 &ldquo;안전하다&quot;가 아니라 &ldquo;어떻게 만들어졌는가&quot;에 답한다</h3>
<p>artifact attestation은 artifact와 build metadata를 연결하는 검증 가능한 증거입니다. GitHub Actions에서 생성한 build provenance는 특정 binary 또는 container image가 어떤 repository·workflow·ref·commit 맥락에서 생성됐는지 확인할 수 있게 합니다. 즉 이 증거가 직접 답하는 질문은 &ldquo;이 이미지에 취약점이 없는가?&ldquo;가 아니라 **&ldquo;이 digest가 우리가 신뢰하는 build 경로에서 나왔는가?&rdquo;**입니다.</p>
<p>이 구분이 없으면 운영 정책이 과도해집니다. provenance가 통과한 이미지는 여전히 취약할 수 있고, secret이 포함된 config로 실행될 수 있으며, 지나친 Kubernetes 권한을 요청할 수도 있습니다. 반대로 vulnerability scan이 통과했다고 빌드가 승인된 source에서 만들어졌다는 보장도 없습니다. 서로 다른 gate는 서로 다른 질문을 담당해야 합니다.</p>
<table>
  <thead>
      <tr>
          <th>증거 또는 검사</th>
          <th>주로 답하는 질문</th>
          <th>단독으로 답하지 못하는 질문</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>provenance attestation</td>
          <td>누가 어떤 workflow·source에서 artifact를 만들었는가</td>
          <td>알려진 취약점·runtime 권한이 안전한가</td>
      </tr>
      <tr>
          <td>image digest</td>
          <td>지금 배포하려는 바이트가 정확히 무엇인가</td>
          <td>누가 만들었고 정책을 통과했는가</td>
      </tr>
      <tr>
          <td>SBOM</td>
          <td>포함된 component와 version은 무엇인가</td>
          <td>실제 build workflow가 변조되지 않았는가</td>
      </tr>
      <tr>
          <td>vulnerability scan</td>
          <td>알려진 취약점·policy 위반이 있는가</td>
          <td>artifact가 승인된 CI에서 build됐는가</td>
      </tr>
      <tr>
          <td>admission policy</td>
          <td>이 workload를 지금 허용할 것인가</td>
          <td>rollout 뒤 사용자 영향이 없는가</td>
      </tr>
  </tbody>
</table>
<p>따라서 attestation 도입의 첫 설계 산출물은 tool 설정이 아니라 trust statement입니다. 예를 들어 &ldquo;<code>ghcr.io/acme/payments@sha256:...</code>는 <code>acme/payments</code> repository의 protected <code>main</code>에서 <code>release-image.yml</code>이 생성하고, production namespace는 이 identity만 받는다&quot;처럼 artifact, source, workflow, environment를 한 문장으로 좁혀야 합니다.</p>
<h3 id="2-tag가-아니라-digest를-배포-단위로-삼아야-한다">2) Tag가 아니라 digest를 배포 단위로 삼아야 한다</h3>
<p><code>payments:2026.08.31</code> 같은 tag는 사람이 읽기 좋지만 mutable합니다. 같은 tag가 나중에 다른 image를 가리킬 수 있고, attestation이 어떤 artifact를 증명하는지와 현재 deployment가 실행하는 바이트가 갈라질 수 있습니다. 그래서 admission과 deployment manifest는 가능한 한 digest를 기준으로 연결합니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6272a4"># 사람이 읽기 좋은 tag만으로는 증거 대상이 고정되지 않는다.</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">image</span>: ghcr.io/acme/payments:2026.08.31
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># 실제 배포·검증 대상을 고정한다.</span>
</span></span><span style="display:flex;"><span><span style="color:#ff79c6">image</span>: ghcr.io/acme/payments@sha256:0123...cdef
</span></span></code></pre></div><p>tag를 release catalog나 UI에서 완전히 없앨 필요는 없습니다. 다만 tag는 발견성, digest는 실행 신원으로 역할을 분리합니다. release pipeline은 build 직후 digest를 수집하고, attestation을 그 digest에 연결하며, promotion manifest도 같은 digest를 사용합니다. 이 연결이 끊기면 &ldquo;attestation은 있었지만 다른 image가 배포됐다&quot;는 가장 비싼 종류의 false assurance가 생깁니다.</p>
<p>실무 시작 기준은 단순합니다.</p>
<ul>
<li>production 배포의 **100%**가 digest reference를 사용한다.</li>
<li>attestation verification subject가 deployment image digest와 정확히 일치한다.</li>
<li>registry host, repository, workflow path, branch 또는 tag policy를 allowlist로 둔다.</li>
<li>이미지 재빌드가 필요하면 기존 tag를 재지정하지 않고 새 digest와 새 attestation을 발행한다.</li>
</ul>
<h3 id="3-ci-권한은-provenance를-강하게도-약하게도-만든다">3) CI 권한은 provenance를 강하게도 약하게도 만든다</h3>
<p>GitHub Actions의 artifact attestation 생성은 workflow permission과 workload identity 위에서 동작합니다. 일반적으로 build provenance 생성에는 <code>contents: read</code>, OIDC token을 위한 <code>id-token: write</code>, attestation 기록을 위한 <code>attestations: write</code> 같은 권한이 필요합니다. 이것은 단순 syntax가 아니라 &ldquo;어떤 workflow가 누구의 identity로 증명을 발행할 수 있는가&quot;라는 정책입니다.</p>
<p>여기서 특히 조심할 지점은 provenance action을 넣었다는 이유로 workflow 전체에 broad permission을 주는 것입니다. build job은 source를 읽고 image를 push하고 attestation을 발행해야 할 수 있지만, issue write, pull-request write, broad package admin은 별개입니다. <a href="/posts/2026-07-04-ci-native-agent-runner-actions-token-trend/">CI-native Agent Runner와 Actions Token</a>에서 다룬 것처럼 CI runner의 token은 build 편의 토큰이 아니라 배포 identity입니다.</p>
<p>권장 원칙은 다음과 같습니다.</p>
<ol>
<li>attestation을 만드는 job을 release 전용 workflow로 분리합니다.</li>
<li>job-level <code>permissions:</code>를 명시하고, third-party action은 full commit SHA로 pin합니다.</li>
<li>fork PR, 사람이 임의로 dispatch하는 workflow, release branch push의 provenance를 같은 신뢰 등급으로 취급하지 않습니다.</li>
<li>workflow path와 source ref를 verifier policy에 포함해, 같은 repository의 다른 workflow가 production 증명을 발행하지 못하게 합니다.</li>
</ol>
<h3 id="4-admission은-보안-도구가-아니라-배포-control-plane의-한-단계다">4) Admission은 보안 도구가 아니라 배포 control plane의 한 단계다</h3>
<p>Sigstore Policy Controller 같은 admission controller는 Kubernetes API 요청이 cluster state가 되기 전에 image signature와 attestation 정책을 평가할 수 있습니다. 이 기능은 강력하지만, 처음부터 모든 namespace에 deny를 걸면 platform team은 정상 서비스까지 멈출 위험을 떠안습니다. 설계의 핵심은 policy syntax가 아니라 <strong>누가 실패를 어떻게 복구하는가</strong>입니다.</p>
<p>권장 rollout은 세 단계입니다.</p>
<table>
  <thead>
      <tr>
          <th>단계</th>
          <th>범위</th>
          <th>통과 기준</th>
          <th>실패 시 행동</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Observe</td>
          <td>staging opt-in namespace</td>
          <td>verification coverage 95% 이상, false denial 원인 분류</td>
          <td>로그·metric만 기록, 배포 차단 안 함</td>
      </tr>
      <tr>
          <td>Canary enforce</td>
          <td>저위험 service 1~3개</td>
          <td>verification latency p95 2초 이하, emergency rollback 성공</td>
          <td>approved exception으로 한시 우회</td>
      </tr>
      <tr>
          <td>Progressive enforce</td>
          <td>production workload 유형별</td>
          <td>digest deployment 100%, 30일간 bypass 없는 정상 운영</td>
          <td>namespace별 확대를 중단하고 원인 수정</td>
      </tr>
  </tbody>
</table>
<p><code>opt-in</code> namespace부터 시작하는 이유는 정책을 약하게 만들기 위해서가 아닙니다. 각 service의 registry, image format, GitHub trust root, deployment tool이 실제로 policy 표현과 맞는지 확인하기 위해서입니다. verification 오류에는 <code>attestation_missing</code>, <code>issuer_not_allowed</code>, <code>workflow_mismatch</code>, <code>subject_digest_mismatch</code>, <code>registry_unreachable</code>처럼 사람이 조치할 수 있는 reason code가 필요합니다. &ldquo;admission denied&rdquo; 한 줄만 남기면 보안과 가용성 모두 나빠집니다.</p>
<h3 id="5-예외는-break-glass가-아니라-만료되는-별도-계약이다">5) 예외는 break-glass가 아니라 만료되는 별도 계약이다</h3>
<p>긴급 보안 patch나 legacy service migration 중에는 attestation이 없는 artifact를 배포해야 할 수 있습니다. 이때 영구 allowlist를 한 줄 추가하면 gate는 결국 장식이 됩니다. 예외는 강한 정책의 반대가 아니라, <strong>가용성을 지키면서 책임을 남기는 예외적인 policy object</strong>로 모델링해야 합니다.</p>
<p>최소 예외 필드는 다음과 같습니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff79c6">exception</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">workload</span>: <span style="color:#f1fa8c">&#34;payments-reconciler&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">image_digest</span>: <span style="color:#f1fa8c">&#34;sha256:...&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">namespace</span>: <span style="color:#f1fa8c">&#34;production&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">reason</span>: <span style="color:#f1fa8c">&#34;critical security patch while legacy builder migration is in progress&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">owner</span>: <span style="color:#f1fa8c">&#34;payments-platform&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">approval_ticket</span>: <span style="color:#f1fa8c">&#34;SEC-1842&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">expires_at</span>: <span style="color:#f1fa8c">&#34;2026-09-02T00:00:00Z&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">follow_up</span>: <span style="color:#f1fa8c">&#34;rebuild via release-image.yml and verify provenance&#34;</span>
</span></span></code></pre></div><p>중요한 것은 <code>expires_at</code>입니다. 예외가 만료되기 전 재검증하거나 연장 승인하지 않으면 다음 deployment는 다시 gate를 통과해야 합니다. 예외 사용률이 한 달 동안 1%를 넘거나 같은 workflow가 두 번 이상 예외를 요구하면, individual bypass가 아니라 build platform migration backlog로 승격하는 편이 낫습니다.</p>
<h2 id="실무-적용">실무 적용</h2>
<h3 id="1-artifact-to-deployment-chain을-inventory한다">1) Artifact-to-deployment chain을 inventory한다</h3>
<p>도입 전 먼저 아래 체인을 workload 10개에 대해 표로 만듭니다. 자동화가 아니라 목록화부터 하는 이유는, attestation을 검증할 대상과 책임자가 없으면 policy를 넓게 열거나 정상 build를 막게 되기 때문입니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>source repository + protected ref
</span></span><span style="display:flex;"><span>  -&gt; release workflow + immutable action refs
</span></span><span style="display:flex;"><span>  -&gt; image digest + registry
</span></span><span style="display:flex;"><span>  -&gt; provenance attestation
</span></span><span style="display:flex;"><span>  -&gt; promotion manifest using that digest
</span></span><span style="display:flex;"><span>  -&gt; target namespace + service owner
</span></span></code></pre></div><p>이 체인에서 하나라도 빈 곳이 있으면 enforce를 미룹니다. 예를 들어 image가 digest로 promotion되지 않는다면 build provenance가 있어도 deployment target이 고정되지 않습니다. registry가 둘 이상이고 trust root가 다르다면 한 policy에 묶지 말고 workload class를 먼저 나눕니다. <a href="/posts/2026-05-12-package-release-quarantine-gate-trend/">Package Release Quarantine Gate</a>처럼 공급망 검증은 최종 차단률보다, 확인 불가능한 artifact를 얼마나 빨리 분류 가능한 흐름으로 옮기는지가 초기 목표입니다.</p>
<h3 id="2-한-release-workflow에-최소-권한-attestation을-붙인다">2) 한 release workflow에 최소 권한 attestation을 붙인다</h3>
<p>release workflow는 build가 끝난 artifact digest를 입력으로 provenance를 발행합니다. 실제 action 버전과 registry 옵션은 조직의 GitHub 설정에 맞춰 확인해야 하지만, 아래처럼 권한과 산출물의 관계를 명시하는 형태가 출발점입니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff79c6">permissions</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">contents</span>: read
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">id-token</span>: write
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">attestations</span>: write
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># build step가 만든 immutable digest를 provenance subject로 사용한다.</span>
</span></span><span style="display:flex;"><span><span style="color:#6272a4"># action은 organization policy가 허용한 immutable revision으로 pin한다.</span>
</span></span></code></pre></div><p>CI를 통과했다는 사실만으로 promotion하지 않습니다. promotion job에서 동일 digest의 attestation verification을 다시 실행하고, 검증 결과의 workflow identity·repository·source ref를 release record에 남깁니다. 이중 검증은 도구를 믿지 못해서가 아니라, build와 deploy 사이의 handoff가 다른 credential, 다른 runner, 다른 사람에 의해 이루어질 수 있기 때문입니다.</p>
<h3 id="3-canary-policy의-숫자를-먼저-합의한다">3) Canary policy의 숫자를 먼저 합의한다</h3>
<p>다음은 조직 상황에 맞게 조정할 수 있는 보수적인 출발선입니다.</p>
<ul>
<li>observe mode 30일 동안: production candidate 중 provenance coverage <strong>95% 이상</strong></li>
<li>canary namespace: admission verification p95 <strong>2초 이하</strong>, p99 <strong>5초 이하</strong></li>
<li><code>subject_digest_mismatch</code>: <strong>0건</strong>이 될 때까지 enforcement 확대 금지</li>
<li><code>attestation_missing</code>으로 인한 정상 release 차단: 주당 <strong>1건 이하</strong>, 초과하면 developer workflow 개선</li>
<li>emergency exception: workload별 <strong>30일 1회 이하</strong>, 모든 예외는 <strong>72시간 이내</strong> 만료</li>
<li>rollout: workload class별 10% → 25% → 50% → 100%, 각 구간 최소 <strong>7일</strong> 관찰</li>
</ul>
<p>이 기준의 우선순위는 <strong>잘못된 artifact 배포 방지 &gt; rollback 가능성 &gt; release 속도</strong>입니다. 하지만 그 순서가 release를 멈추라는 뜻은 아닙니다. 검증 서비스가 불가용할 때 fail-open할지 fail-closed할지는 workload 위험도와 기존 배포 증거에 따라 명시적으로 정합니다. 결제·identity control plane은 더욱 보수적으로, 내부 dev namespace는 bounded fail-open을 선택할 수 있지만 어떤 선택이든 audit event는 남겨야 합니다.</p>
<h3 id="4-admission을-통과한-뒤에도-progressive-delivery를-유지한다">4) Admission을 통과한 뒤에도 progressive delivery를 유지한다</h3>
<p>attestation policy가 허용한 것은 artifact의 출처이지 application behavior가 아닙니다. schema migration, feature flag, configuration error, dependency latency는 provenance와 무관하게 장애를 만들 수 있습니다. 그래서 <a href="/learning/deep-dive/deep-dive-kubernetes-rollouts/">Kubernetes 롤아웃 전략과 무중단 배포</a>의 canary·health check·rollback은 그대로 필요합니다.</p>
<p>운영 흐름을 다음처럼 분리하면 책임이 선명해집니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>provenance verification pass
</span></span><span style="display:flex;"><span>  -&gt; policy admission pass
</span></span><span style="display:flex;"><span>  -&gt; 5% canary deployment
</span></span><span style="display:flex;"><span>  -&gt; SLO / error / saturation gate
</span></span><span style="display:flex;"><span>  -&gt; progressive promotion
</span></span></code></pre></div><p>provenance fail은 &ldquo;무엇을 배포해도 되는가&quot;의 문제이고, canary fail은 &ldquo;이 artifact가 현재 환경에서 정상 동작하는가&quot;의 문제입니다. 둘을 하나의 green check로 합치면 incident 때 rollback 근거가 흐려집니다.</p>
<h2 id="트레이드오프주의점">트레이드오프/주의점</h2>
<ol>
<li>
<p><strong>Attestation은 vulnerability scan을 대체하지 않습니다.</strong> 어느 workflow가 만들었는지를 증명할 뿐, dependency CVE·license·misconfiguration·runtime permission을 해결하지 않습니다.</p>
</li>
<li>
<p><strong>모든 build를 같은 identity로 신뢰하지 않습니다.</strong> PR preview, nightly, release branch, 수동 hotfix workflow는 source·review·token 조건이 다릅니다. verifier policy도 이 차이를 표현해야 합니다.</p>
</li>
<li>
<p><strong>tag pinning을 digest pinning으로 오해하지 않습니다.</strong> semver tag를 고정했다고 대상 바이트가 고정되는 것은 아닙니다. promotion과 verification은 digest를 기준으로 연결합니다.</p>
</li>
<li>
<p><strong>admission failure의 가용성 영향을 설계해야 합니다.</strong> trust root fetch, registry access, verifier latency가 배포를 막을 수 있습니다. timeout, cache, outage mode, break-glass owner를 test하지 않은 fail-closed는 운영 사고가 될 수 있습니다.</p>
</li>
<li>
<p><strong>예외를 조용히 허용하지 않습니다.</strong> 만료·owner·ticket·범위·사후 검증 없는 bypass는 policy가 아니라 영구 취약점입니다.</p>
</li>
</ol>
<h2 id="체크리스트-또는-연습">체크리스트 또는 연습</h2>
<h3 id="체크리스트">체크리스트</h3>
<ul>
<li><input disabled="" type="checkbox"> production manifest가 mutable tag가 아니라 immutable image digest를 사용한다.</li>
<li><input disabled="" type="checkbox"> attestation verifier가 registry, repository, workflow path, source ref, subject digest를 모두 확인한다.</li>
<li><input disabled="" type="checkbox"> release job의 permissions가 최소 권한으로 명시되고 action refs가 immutable revision으로 pin되어 있다.</li>
<li><input disabled="" type="checkbox"> observe → canary enforce → progressive enforce의 단계와 중단 기준이 있다.</li>
<li><input disabled="" type="checkbox"> missing, workflow mismatch, digest mismatch, verifier outage를 구분한 metric과 runbook이 있다.</li>
<li><input disabled="" type="checkbox"> exception은 workload·digest·owner·ticket·expiry·follow-up을 갖고 자동 만료된다.</li>
<li><input disabled="" type="checkbox"> provenance pass 뒤에도 canary SLO gate와 rollback을 유지한다.</li>
</ul>
<h3 id="연습-staging-namespace-하나에-검증-가능한-배포-gate-만들기">연습: staging namespace 하나에 검증 가능한 배포 gate 만들기</h3>
<ol>
<li>staging의 서비스 하나를 골라 source repository, release workflow, registry, image digest, owner를 inventory합니다.</li>
<li>해당 workflow가 만든 image digest에 build provenance를 발행하고, promotion record에 verification 결과를 남깁니다.</li>
<li>admission을 audit-only로 7일 운영해 missing·issuer mismatch·digest mismatch reason을 분류합니다.</li>
<li>정상 coverage가 95%를 넘으면 그 namespace에서만 enforce를 켜고, verification p95와 false denial을 7일 더 봅니다.</li>
<li>attestation 없는 긴급 image, 잘못된 workflow image, digest가 다른 image를 각각 배포해 정책이 의도대로 막고 audit record를 남기는지 확인합니다.</li>
</ol>
<h2 id="관련-글">관련 글</h2>
<ul>
<li><a href="/posts/2026-07-30-publish-time-supply-chain-review-context-trend/">Publish-Time Supply Chain Gate와 Review Context Plane</a></li>
<li><a href="/posts/2026-07-04-ci-native-agent-runner-actions-token-trend/">CI-native Agent Runner와 Actions Token</a></li>
<li><a href="/posts/2026-05-12-package-release-quarantine-gate-trend/">Package Release Quarantine Gate</a></li>
<li><a href="/learning/deep-dive/deep-dive-kubernetes-rollouts/">Kubernetes 롤아웃 전략과 무중단 배포</a></li>
</ul>
]]></content:encoded></item></channel></rss>