Skip to content

docs(supply-chain): document monitoring your own signing identity - #1959

Open
lockwobr wants to merge 6 commits into
mainfrom
docs/rekor-signer-identity-monitoring
Open

docs(supply-chain): document monitoring your own signing identity#1959
lockwobr wants to merge 6 commits into
mainfrom
docs/rekor-signer-identity-monitoring

Conversation

@lockwobr

Copy link
Copy Markdown
Contributor

Summary

Documents how a signer monitors the transparency log for their own signing identity, the producer-side complement to the consumer-side verification the rest of these docs cover. Adds a Monitoring Your Signing Identity section to the integrator guide and a pointer to it from the user-facing verification page.

Motivation / Context

Users of aicr bundle --attest, aicr validate --emit-attestation --push, and the evidence signing commands sign under their own identity and upload to a transparency log by default. AICR documented how to sign and how to verify, but never told signers to watch the log for their own identity. An entry under your identity that you did not produce is the signal that the identity was used without you, and for keyless signing it is the only signal: there is no private key on disk whose use could be audited, and the Fulcio certificate is short-lived.

Fixes: #1462
Related: #1149, #1153, #1650

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Build/CI/tooling

Component(s) Affected

  • Docs/examples (docs/, examples/)

Implementation Notes

The issue's proposed approach does not work as written, and the docs say so. #1462 proposed pointing users at "the same sigstore/rekor-monitor reusable workflow". That workflow resolves its Rekor target from Sigstore's default signing config, which lists only Rekor v1, and Sigstore has stated the public-good instance will keep v1 as the default log for the foreseeable future. Since #1650, AICR's signing paths default to Rekor v2. So the upstream workflow cannot monitor the log that AICR users sign to by default.

The section therefore routes by log version rather than pretending one tool covers everything:

  • Rekor v2 (the default for every keyless and KMS path): use tools/rekor-monitor, which resolves the v2 shard from the same signing config AICR signs against and takes the watched identity as flags. Includes a drop-in scheduled workflow derived from AICR's own rekor-monitor.yaml, with the checkpoint-artifact round trip and the two hardening steps called out.
  • Rekor v1, public or private: use the upstream reusable workflow, which is what it supports. Covers both certificate identities and, for KMS, the fingerprints mode, with the cosign public-key pipeline to derive the fingerprint.

Two coverage gaps are stated plainly rather than papered over: a KMS key signing to the default Rekor v2 has no turnkey monitor (tools/rekor-monitor exposes only certificate-identity flags, though the upstream library it builds on does match v2 entries by fingerprint), and a private Rekor v2 reached via --signing-config is out of reach for both tools.

The per-mode identity table is grounded in the code rather than inferred: KMS entries carry a public key with no SAN or issuer to match, and --tlog-upload=false uploads nothing, so there is nothing to monitor.

Five upstream Sigstore references were added, each at the claim it supports: the threat model and Rekor overview for why monitoring is the detection control, the Rekor evolution post as the primary source for the v1-default statement, the sigstore/rekor-monitor repository, and Sigstore's rekor-monitor walkthrough for the consistency-check versus identity-search split and the fingerprint mode.

Testing

make qualify

Docs-only change; no code paths touched. tools/check-docs-mdx passes (OK: all doc files are MDX-safe), including the ${{ ... }} expressions inside the YAML fences. The lychee job in fern-docs-ci.yaml runs with --offline, so it gates local links and anchors only; the five new external URLs were each fetched and confirmed to return the expected content. The one new intra-repo anchor (supply-chain-verification.md#monitoring-your-signing-identity) resolves, and no duplicate heading slugs were introduced.

Risk Assessment

  • Low — Isolated change, well-tested, easy to revert
  • Medium — Touches multiple components or has broader impact
  • High — Breaking change, affects critical paths, or complex rollout

Rollout notes: N/A. Additive documentation only; no existing headings renamed or restructured, so inbound anchor links are unaffected.

Checklist

  • Tests pass locally (make test with -race)
  • Linter passes (make lint)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality
  • I updated docs if user-facing behavior changed
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)

@lockwobr
lockwobr requested a review from a team as a code owner July 29, 2026 20:39
@lockwobr lockwobr added area/docs theme/supply-chain SLSA, SBOM, Sigstore, and provenance verification labels Jul 29, 2026
@lockwobr lockwobr self-assigned this Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Coverage data unavailable for this run. This can happen if the qualification workflow was cancelled or failed before generating coverage artifacts.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds documentation for monitoring signing identities through Rekor, covering keyless, KMS, public-good, private, and disabled transparency-log configurations. Includes identity extraction commands, checkpoint handling, response guidance, related references, and a pointer from artifact verification documentation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: almaslennikov

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the documentation change to monitor signing identities.
Description check ✅ Passed The description explains the documentation scope, motivation, implementation approach, testing, and risk for this changeset.
Linked Issues check ✅ Passed The PR satisfies issue #1462 by documenting Rekor monitoring for keyless and KMS identities across public and private deployments.
Out of Scope Changes check ✅ Passed All changes are documentation, references, and related guidance within the scope of issue #1462.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/rekor-signer-identity-monitoring

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/integrator/supply-chain-verification.md`:
- Around line 712-714: Revise step “Re-verify what you already published” to
clarify that --require-creator only confirms signer identity, not artifact
authenticity after compromise. Instruct users to compare each artifact’s digest
and provenance with an independent release record, and quarantine any
unrecognized artifacts.
- Around line 507-518: Update the signing-mode table to separate private Fulcio
selection from Rekor selection: keep a private-Fulcio row whose log reflects the
independently selected Rekor v2 default, and add a distinct Rekor v1 row that
applies only when --rekor-url is used. Ensure the surrounding text and row
descriptions do not imply --fulcio-url selects Rekor v1.
- Around line 660-665: Update the certSubject and issuer regex values in the
monitoredValues example to anchor both patterns with ^ and $, ensuring only the
exact certificate identity subject and issuer are matched.
- Around line 581-586: Update the workflow examples in supply-chain verification
documentation: add a reviewed full-length SHA ref for the NVIDIA/aicr checkout,
replace the actions/setup-go@v7 tag with its reviewed full-length SHA, and
replace the v1 reusable workflow’s `@main` reference with its reviewed full-length
SHA.
- Around line 593-601: Update the checkpoint artifact selection in the gh api/jq
pipeline to restrict candidates to artifacts produced by trusted runs from this
repository’s main branch before sorting and selecting the newest unexpired
artifact. Preserve the existing no-checkpoint handling and download flow, while
ensuring fork PR artifacts cannot be selected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 00da2987-4f24-4b2b-a172-551f7a60c58c

📥 Commits

Reviewing files that changed from the base of the PR and between 905bec6 and f401ab8.

📒 Files selected for processing (2)
  • docs/integrator/supply-chain-verification.md
  • docs/user/artifact-verification.md

Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/integrator/supply-chain-verification.md`:
- Around line 643-647: Update the supply-chain verification guidance to
explicitly require pinning the source checked out by the earlier git clone
example for tools/rekor-monitor. In addition to Actions, reusable workflows, and
ref values, instruct users to use a reviewed full-length commit SHA, or an
intentionally reviewed release ref, instead of the mutable default branch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 3370b051-b4c2-4909-b6b3-14434496738d

📥 Commits

Reviewing files that changed from the base of the PR and between f401ab8 and 799390e.

📒 Files selected for processing (1)
  • docs/integrator/supply-chain-verification.md

Comment thread docs/integrator/supply-chain-verification.md Outdated

@ArangoGutierrez ArangoGutierrez left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid section — the threat model is right, and I confirmed the two stated coverage gaps and the fork-rejection jq against the code (the select clauses match the production workflow exactly). Six things worth fixing, the version pin being the big one.

  1. The pinned tag predates the contract described right below it: at v0.18.0 the monitor never prints a CLASSIFICATION= line, writes no .scan/.stall companions, and realMain returns only 0, 1 or 2 — never 3. Following this verbatim wires a Sigstore or network blip to exit 1, which this page defines as a security finding. (docs/integrator/supply-chain-verification.md:544)
  2. Same version gap in the workflow example: at v0.18.0 there is no CLASSIFICATION= output to branch on, and the .scan/.stall paths uploaded below are never produced — which if-no-files-found: ignore then quietly hides. The CLASSIFICATION= hardening advice further down cannot be applied at this ref. (docs/integrator/supply-chain-verification.md:592)
  3. This pairs an email SAN with the GitHub Actions issuer, a combination Fulcio never issues — under that issuer the SAN is the workflow identity URL, exactly as the table above states and as AICR's own monitor is configured. Upstream ANDs subject and issuer, so a copied config matches nothing and the monitor stays green while watching an identity that cannot exist. Same pairing in the shell example above. (docs/integrator/supply-chain-verification.md:577)
  4. issuers is matched against the certificate's OIDC issuer extension (1.3.6.1.4.1.57264.1.8), which carries the identity provider that authenticated the signer — not the Fulcio CA that issued the cert. A private Fulcio URL here never matches; this wants the IdP issuer. (docs/integrator/supply-chain-verification.md:689)
  5. git clone --branch only accepts a branch or tag name, so this instruction cannot be followed as written — a SHA fails with 'fatal: Remote branch not found in upstream origin'. A clone followed by git checkout would work. (docs/integrator/supply-chain-verification.md:648)
  6. Worth a one-line note on the branch assumption: this literal main rejects every artifact in a repo whose default branch is named differently, leaving the monitor permanently in first-run state — baselining and scanning nothing, on every run, without saying so. (docs/integrator/supply-chain-verification.md:614)

Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated

@yuanchen8911 yuanchen8911 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a well-researched section and the signing-mode table, tool flag descriptions, upstream workflow inputs, and coverage-gap framing all check out against the code. But the two copy-paste workflows and the v1/private-log guidance have several silent false-negative paths, and the examples pin a tool version that lacks the behavior the text documents. Since silent false negatives are exactly what this section exists to prevent, these need fixing before merge. Details inline; the short list:

  1. Both examples pin v0.18.0, which predates the CLASSIFICATION/exit-code/resume behavior the prose documents.
  2. The v2 example's SAN/issuer pair can never match a real certificate, and the v1 example puts the Fulcio CA URL in the OIDC issuers field. Both configurations run green while matching nothing.
  3. A missing or expired checkpoint artifact silently re-baselines the monitor at the current head, permanently skipping the gap.
  4. The tool has no acknowledgment path for legitimate matches, so an actively signing identity wedges the monitor into permanent re-alerting.
  5. The upstream reusable workflow cannot sustain identity coverage on the public-good v1 log and cannot verify a private v1 log, so the "Monitoring Rekor v1 and a private Rekor" section recommends a tool that works for neither of its two headline cases.
  6. Private Fulcio into the public v2 log is a third coverage gap: tools/rekor-monitor silently skips entries whose chain doesn't validate against the public Fulcio roots.
  7. The incident-response steps assume interactive keyless with a public bundle; the containment and re-verification guidance doesn't hold for CI workload identities, KMS, or evidence artifacts.

Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md

@njhensley njhensley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed with a multi-persona panel (docs-accuracy, security/supply-chain, CI-DX) plus adversarial verification against the resolved code at a5335c96.

The standing feedback from @yuanchen8911 and @ArangoGutierrez already covers the crux issues — the v0.18.0 pin lacking the CLASSIFICATION=/exit-3/.scan/.stall contract, the SAN/issuer pairs that can never match, git clone --branch <sha>, the hard-coded head_branch == "main", and the coverage-gap framing — and I independently reproduced those against the code; they still hold at this head. Rather than restate them, the inline comments below are only the net-new findings those reviews did not raise, so this isn't piling on.

Net-new (inline):

  • 🟠 The v1 example runs an unpinned @main third-party reusable workflow with id-token: write — the copied block can mint OIDC as the reader's repo. Production grants no such token and pins nothing to @main.
  • 🟡 The v1 workflow's top-level permissions: read-all is over-broad and inconsistent with the v2 example's permissions: {}.
  • 🟡 The signing-mode table keys its KMS/private/v1 rows on flags (--rekor-url, --signing-key, --signing-config, --tlog-upload) that exist only on aicr bundle — the validate --push / evidence publish / evidence sign paths are keyless-only, always Rekor v2 (pkg/cli/validate_evidence.go:117).
  • 🔵 The v2 example drops production's workflow_dispatch, the retention-days rationale, and the retry/atomic-write fetch wrapper.

Nothing here is a hard blocker on its own; the merge-blocking items are the ones already in @yuanchen8911's standing review. This is really strong, carefully-researched work — the fix set is small and mostly mechanical.

Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md
Comment thread docs/integrator/supply-chain-verification.md
Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment thread docs/integrator/supply-chain-verification.md Outdated
lockwobr added a commit that referenced this pull request Jul 31, 2026
Addresses review on #1959. The section documented behavior the pinned
version could not perform and examples that could never match.

- Repin both examples to d4f7bef (#1929). v0.18.0 predates the
  documented contract: no CLASSIFICATION= line, no .scan/.stall state,
  and exit codes 0/1/2 with no 3, so a network blip would have read as
  a security finding. The commit is in no tag. Use git checkout
  --detach, since git clone --branch resolves only branches and tags.
- Fix the identity pairs. Both examples paired an email SAN with the
  GitHub Actions issuer, which Fulcio never issues together; matching
  is AND-ed, so a copied config matched nothing and the monitor stayed
  green while watching an identity that cannot exist.
- Correct the v1 issuers field: it matches the certificate's OIDC
  issuer extension, the IdP that authenticated the signer, not the
  Fulcio CA.
- Make bootstrap explicit. A hard-coded main filter and artifact
  expiry both silently re-baselined and exited clean. Scheduled runs
  now fail closed when no checkpoint is found; bootstrap is a
  workflow_dispatch input; the branch comes from the repository's
  actual default branch.
- Demote the Rekor v1 cases to coverage gaps: upstream's v1 identity
  scan cannot keep up with log growth, and private v1 fails at
  verifier setup because the checkpoint key is resolved from the
  public TUF root. Keep the config format and KMS fingerprint content.
- Add a third gap: private Fulcio into public-good v2 is monitorable
  by neither tool, since entries failing chain validation are skipped.
- State the alerting limitation: a match holds the cursor and
  re-alerts every run, and the only suppression is --known-tags-file.
- SHA-pin the upstream reusable workflow in the example itself. It
  runs with id-token: write, which upstream requires, so unpinned
  third-party code could mint an OIDC token as the reader's repo.
- Tighten the v1 example to permissions: {}, add workflow_dispatch to
  the v2 example, scope flag-keyed table rows to aicr bundle, split
  the response guidance by signing mode, and fix the retention-days
  rationale.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/integrator/supply-chain-verification.md`:
- Around line 722-724: Update the private Rekor v1 documentation example
following the unsupported-workflow guidance: remove the private `url` value and
clearly label the configuration-shape block as non-turnkey, or replace it with a
direct-binary example that uses `--tuf-repository` and `--tuf-root-path`. Ensure
no copyable workflow implies private-Rekor monitoring is supported.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: d5d47c41-53af-44a4-b89d-61369a0c51c5

📥 Commits

Reviewing files that changed from the base of the PR and between a5335c9 and d3fc34e.

📒 Files selected for processing (1)
  • docs/integrator/supply-chain-verification.md

Comment thread docs/integrator/supply-chain-verification.md
lockwobr added a commit that referenced this pull request Jul 31, 2026
Addresses review on #1959. The section documented behavior the pinned
version could not perform and examples that could never match.

- Repin both examples to d4f7bef (#1929). v0.18.0 predates the
  documented contract: no CLASSIFICATION= line, no .scan/.stall state,
  and exit codes 0/1/2 with no 3, so a network blip would have read as
  a security finding. The commit is in no tag. Use git checkout
  --detach, since git clone --branch resolves only branches and tags.
- Fix the identity pairs. Both examples paired an email SAN with the
  GitHub Actions issuer, which Fulcio never issues together; matching
  is AND-ed, so a copied config matched nothing and the monitor stayed
  green while watching an identity that cannot exist.
- Correct the v1 issuers field: it matches the certificate's OIDC
  issuer extension, the IdP that authenticated the signer, not the
  Fulcio CA.
- Make bootstrap explicit. A hard-coded main filter and artifact
  expiry both silently re-baselined and exited clean. Scheduled runs
  now fail closed when no checkpoint is found; bootstrap is a
  workflow_dispatch input; the branch comes from the repository's
  actual default branch.
- Demote the Rekor v1 cases to coverage gaps: upstream's v1 identity
  scan cannot keep up with log growth, and private v1 fails at
  verifier setup because the checkpoint key is resolved from the
  public TUF root. Keep the config format and KMS fingerprint content.
- Add a third gap: private Fulcio into public-good v2 is monitorable
  by neither tool, since entries failing chain validation are skipped.
- State the alerting limitation: a match holds the cursor and
  re-alerts every run, and the only suppression is --known-tags-file.
- SHA-pin the upstream reusable workflow in the example itself. It
  runs with id-token: write, which upstream requires, so unpinned
  third-party code could mint an OIDC token as the reader's repo.
- Tighten the v1 example to permissions: {}, add workflow_dispatch to
  the v2 example, scope flag-keyed table rows to aicr bundle, split
  the response guidance by signing mode, and fix the retention-days
  rationale.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
@lockwobr
lockwobr force-pushed the docs/rekor-signer-identity-monitoring branch from d3fc34e to 7f05dc2 Compare July 31, 2026 22:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/integrator/supply-chain-verification.md`:
- Around line 558-561: Update both tag-based examples in
docs/integrator/supply-chain-verification.md:558-561 and
docs/integrator/supply-chain-verification.md:677-683 to use legitimate tag data
by generating a known-tag file for the shell example and passing that same file
via --known-tags-file in both the shell command and scheduled workflow.

In `@docs/user/artifact-verification.md`:
- Around line 358-363: Update the verification documentation paragraph around
“transparency log” and “signing identity” to qualify unexpected entries as
possible indicators of unauthorized use, not proof, since authorized automation
or approved signers may share the identity. Describe Rekor as the durable source
for monitoring such activity while preserving the existing explanation of
keyless signing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 273ec689-8d84-49d8-a011-f91995ca3bfa

📥 Commits

Reviewing files that changed from the base of the PR and between d3fc34e and 7f05dc2.

📒 Files selected for processing (2)
  • docs/integrator/supply-chain-verification.md
  • docs/user/artifact-verification.md

Comment thread docs/integrator/supply-chain-verification.md Outdated
Comment on lines +358 to +363
Verification is only half the picture. It proves that an artifact you hold came
from the identity you expect, but it cannot tell you that somebody else signed
something *as you*: an entry in the transparency log under your signing identity
that you did not produce means the identity was used without you. Keyless signing
leaves no local trace of a signing event, so the log is the only place that
misuse shows up. For what each signing mode records and how to watch for it, see

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Qualify the misuse claim.

An unexpected entry can indicate unauthorized use. It does not prove unauthorized use because authorized automation or another approved signer may use the same identity. Replace the absolute wording in Lines 360-363 with a qualified statement, and describe Rekor as the durable monitoring source.

Proposed wording
- that you did not produce means the identity was used without you. Keyless signing
- leaves no local trace of a signing event, so the log is the only place that
- misuse shows up.
+ that you did not authorize may indicate unauthorized use. Keyless signing
+ leaves no local trace of a signing event, so the log provides the durable
+ record for detecting this misuse.

This matches Issue #1462, which requests that an unexpected entry may indicate unauthorized use.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Verification is only half the picture. It proves that an artifact you hold came
from the identity you expect, but it cannot tell you that somebody else signed
something *as you*: an entry in the transparency log under your signing identity
that you did not produce means the identity was used without you. Keyless signing
leaves no local trace of a signing event, so the log is the only place that
misuse shows up. For what each signing mode records and how to watch for it, see
Verification is only half the picture. It proves that an artifact you hold came
from the identity you expect, but it cannot tell you that somebody else signed
something *as you*: an entry in the transparency log under your signing identity
that you did not authorize may indicate unauthorized use. Keyless signing
leaves no local trace of a signing event, so the log provides the durable
record for detecting this misuse. For what each signing mode records and how to watch for it, see
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/user/artifact-verification.md` around lines 358 - 363, Update the
verification documentation paragraph around “transparency log” and “signing
identity” to qualify unexpected entries as possible indicators of unauthorized
use, not proof, since authorized automation or approved signers may share the
identity. Describe Rekor as the durable source for monitoring such activity
while preserving the existing explanation of keyless signing.

@yuanchen8911
yuanchen8911 self-requested a review August 1, 2026 00:38

@yuanchen8911 yuanchen8911 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All previous findings were fixed and the threads are resolved. There's a blocking issue remaining, please take a look: both examples watch a refs/tags/.* release identity but never pass --known-tags-file (inline comment below). Two small same-pass fixes are also inline, and one item to defer.

On your recipe sign-catalog question: keep the text scoped to the user-facing surface as you have it. Documenting a Hidden: true CI-only command in an integrator doc adds noise without helping the reader.

One follow-up rather than a change here: neither the doc examples nor the production workflow set persist-credentials: false on actions/checkout. The example faithfully mirrors production, so I'd rather harden both together in a focused follow-up than have the doc diverge. Exposure is low (the persisted token is scoped to contents: read + actions: read).

--file checkpoint_v2.txt \
--restore-zip checkpoint.zip \
--cert-subject "${CERT_SUBJECT}" \
--cert-issuer "${CERT_ISSUER}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is blocking, and applies equally to the shell example at lines 558-562: both examples watch a refs/tags/.* release identity but never pass --known-tags-file. Per the limitation stated just above, on an identity match the tool holds the cursor and returns without persisting the chunk's progress, so the reader's first legitimate release after baseline leaves the monitor re-alerting every run and — the part that matters — entries in later chunks remain unscanned until the finding is triaged. The only triage path is the flag the examples omit, so a verbatim copy suspends the monitor's core function on the first ordinary use of the watched identity. The prose says a tag-bearing release identity is turnkey via --known-tags-file; the copyable blocks for exactly that identity should wire it.

Two constraints on the fix:

  • The allowlist must come from an authoritative record of legitimately signed releases, not raw repository tags — an attacker-pushed or never-signed tag in git tag --list would be pre-suppressed. Production's own step is the copyable pattern: it derives known-tags.txt from the release workflow's completed run history (.github/workflows/rekor-monitor.yaml, the runs.json to known-tags.txt step), precisely because repo tags are deleted for ephemeral RCs while run history persists (Rekor v2 monitor: release identity / log consistency alert #1902).

  • Worth carrying over production's caveat too: an attacker re-signing an existing release tag is suppressed by this mechanism; a per-tag entry-count/provenance check is the tracked follow-up.

For the shell example, a comment showing the run-history derivation (or pointing at production's step) is enough; for the workflow example, add the fetch step and the flag.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and this is the same failure mode this PR keeps hitting: the prose states a limitation correctly, then the copyable block below it does not account for it. The section says a tag-bearing release identity is turnkey via --known-tags-file, and then neither example passed it. Fixed in 247ceed.

Your second constraint is the part I would have got wrong on my own, so I took production verbatim rather than improvising. The workflow example now carries the Fetch signed release tags step from .github/workflows/rekor-monitor.yaml, including its jq unchanged:

jq -rs '[.[].workflow_runs[] | select(.head_branch != null) | .head_branch] | unique | .[]' runs.json > known-tags.txt

with RELEASE_WORKFLOW_FILE in env and production's note to change it and CERT_SUBJECT together, plus the rationale that the allowlist must come from an authoritative record rather than git tag --list and that run history persists after ephemeral RC tags are deleted (#1902). The one substitution is plain gh api --paginate in place of .github/scripts/gh-api-retry.sh, since a reader's repo has no such script; the jq -rs slurp is kept because --paginate emits one object per page. The shell example gets the flag plus a comment stating the derivation and the never-from-git tag --list constraint.

Production's caveat is carried as its own paragraph: an attacker re-signing an existing release tag is suppressed because that tag is legitimately allowlisted, and the allowlist keys on a completed release run rather than proof the signing step succeeded. Cited #1887 as the tracked follow-up, which is what docs/contributor/maintaining.md names for the same gap.

tree head and scans nothing, and every later run scans only the window added
since. The tool writes two companions alongside it, `<file>.scan` and
`<file>.stall`, holding partial progress and catch-up trend so that a large
backlog is scanned across several bounded runs; all three must survive between

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small accuracy fix: "all three must survive between runs or the scan restarts" is true of <file> and <file>.scan, but not .stall. A missing .scan makes readProgress() return 0 and the window rescans from the start; a missing .stall only resets the catch-up convergence history feeding the degraded classification — scan progress is untouched (checkpoint.go: readProgress vs readScanTrend). Suggest splitting the clause: the checkpoint and .scan must survive or the scan restarts; .stall only preserves the stall-detection history.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, thanks. Fixed in 247ceed. Verified before rewriting: progressPath() is .scan (checkpoint.go:112) and readProgress returns 0 when absent, so the window rescans from the start; stallPath() is .stall (checkpoint.go:161) and readScanTrend returns the zero value, feeding only bestRemaining/stall/passes for the degraded classification. The clause is now split so .scan carries the must-survive requirement and .stall is described as costing stall detection rather than scan progress.

something *as you*: an entry in the transparency log under your signing identity
that you did not produce means the identity was used without you. Keyless signing
leaves no local trace of a signing event, so the log is the only place that
misuse shows up. For what each signing mode records and how to watch for it, see

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Means" overstates what the entry proves: an identity legitimately shared with CI automation or another approved signer produces entries you did not personally make, and the integrator guide's own "rule yourself out first" step anticipates exactly that. Suggest "may indicate the identity was used without you" (or similar), keeping the point that the log is the only durable record. The same absolute wording appears in docs/integrator/supply-chain-verification.md line 471 ("means your identity was used without you") — please fix both in the same pass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and it was inconsistent with the section's own "rule yourself out first" step, which exists precisely because a shared or automated identity produces entries you did not personally make. Fixed in both files in 247ceed: may indicate that the identity was used without you in the integrator guide and the matching change in docs/user/artifact-verification.md, keeping the point that the log is the only durable record.

Users of the signing paths upload to a transparency log by default but
were never told to watch that log for their own identity. An entry under
your identity that you did not produce is the signal the identity was
used without you, and for keyless signing it is the only signal: no
private key on disk to audit, and a short-lived Fulcio certificate.

Adds a Monitoring Your Signing Identity section to the integrator guide
and a pointer from the user verification page.

The upstream sigstore/rekor-monitor reusable workflow cannot cover the
default path: it resolves its target from Sigstore's default signing
config, which lists only Rekor v1, while AICR signing has defaulted to
Rekor v2 since #1650. The section routes by log version instead, using
tools/rekor-monitor for v2 and the upstream workflow for v1 and private
v1, and states the two remaining coverage gaps rather than hiding them.

Fixes #1462

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
- Split the private-Sigstore table row: --fulcio-url selects the CA, not
  the log, so a private CA alone still publishes to public-good Rekor v2;
  only --rekor-url / --signing-config change the log.
- Inline the checkpoint-artifact trust filter into the sample workflow
  (same-repo, head_branch main) instead of leaving it to prose. A fork
  pull_request run can upload a same-named artifact, and a poisoned
  checkpoint passes the consistency proof while collapsing the
  identity-scan window.
- Anchor the Rekor v1 certSubject and issuers regexes, matching the
  guidance given for the v2 flags. Upstream compiles both with
  regexp.Compile and matches with MatchString.
- Correct the response guidance: --require-creator narrows the set to
  artifacts signed by that identity but cannot separate yours from the
  attacker's within it, since a compromised identity satisfies the check.
  Establish legitimacy from a record the attacker does not control.
- Pin the checkout ref for the cloned tool rather than floating on our
  default branch, and broaden the pinning advice to every external
  reference in the examples.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
The shell example cloned NVIDIA/aicr's default branch, so the monitor
being trusted could change between runs, and the pinning guidance
enumerated actions, the reusable workflow, and ref: but not the clone.
Pin the clone to v0.18.0 and extend the guidance to cover it.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
Addresses review on #1959. The section documented behavior the pinned
version could not perform and examples that could never match.

- Repin both examples to d4f7bef (#1929). v0.18.0 predates the
  documented contract: no CLASSIFICATION= line, no .scan/.stall state,
  and exit codes 0/1/2 with no 3, so a network blip would have read as
  a security finding. The commit is in no tag. Use git checkout
  --detach, since git clone --branch resolves only branches and tags.
- Fix the identity pairs. Both examples paired an email SAN with the
  GitHub Actions issuer, which Fulcio never issues together; matching
  is AND-ed, so a copied config matched nothing and the monitor stayed
  green while watching an identity that cannot exist.
- Correct the v1 issuers field: it matches the certificate's OIDC
  issuer extension, the IdP that authenticated the signer, not the
  Fulcio CA.
- Make bootstrap explicit. A hard-coded main filter and artifact
  expiry both silently re-baselined and exited clean. Scheduled runs
  now fail closed when no checkpoint is found; bootstrap is a
  workflow_dispatch input; the branch comes from the repository's
  actual default branch.
- Demote the Rekor v1 cases to coverage gaps: upstream's v1 identity
  scan cannot keep up with log growth, and private v1 fails at
  verifier setup because the checkpoint key is resolved from the
  public TUF root. Keep the config format and KMS fingerprint content.
- Add a third gap: private Fulcio into public-good v2 is monitorable
  by neither tool, since entries failing chain validation are skipped.
- State the alerting limitation: a match holds the cursor and
  re-alerts every run, and the only suppression is --known-tags-file.
- SHA-pin the upstream reusable workflow in the example itself. It
  runs with id-token: write, which upstream requires, so unpinned
  third-party code could mint an OIDC token as the reader's repo.
- Tighten the v1 example to permissions: {}, add workflow_dispatch to
  the v2 example, scope flag-keyed table rows to aicr bundle, split
  the response guidance by signing mode, and fix the retention-days
  rationale.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
The subsection states that a private Rekor v1 fails at verifier setup
and that the reusable workflow cannot pass private trust material, then
the example below it still set url to a private log and told readers to
do the same. Remove the url, label the block as illustrating the
monitoredValues shape rather than being a turnkey recipe, and point at
the direct-binary path for private trust.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
Both examples watch a tag-bearing release identity, and the section
states that such an identity is turnkey via --known-tags-file, but
neither example passed it. Since an identity match holds the cursor
without persisting the chunk's progress, a verbatim copy leaves the
monitor re-alerting every run and, more importantly, leaves later
chunks unscanned until the finding is triaged.

Derive the allowlist from the release workflow's completed run history,
copying production's step verbatim, rather than from git tag --list: an
attacker-pushed or never-signed tag would otherwise be pre-suppressed,
and run history persists after ephemeral RC tags are deleted. Carry
production's residual-gap caveat too, since an attacker re-signing an
existing release tag is suppressed by this mechanism.

Also correct two smaller inaccuracies:
- Only the checkpoint and .scan must survive between runs; losing
  .stall costs stall detection, not scan progress, since it feeds the
  degraded classification rather than readProgress.
- An entry you did not produce may indicate misuse rather than meaning
  it, since an identity shared with CI automation legitimately produces
  entries you did not personally make. Softened in both files.

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
@lockwobr
lockwobr force-pushed the docs/rekor-signer-identity-monitoring branch from 7f05dc2 to 247ceed Compare August 3, 2026 23:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs size/L theme/supply-chain SLSA, SBOM, Sigstore, and provenance verification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(supply-chain): guide users to monitor their own signing identity

4 participants