From 11ccd7a2441f1e96aeb4b502fb07865bbe1aa533 Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 04:49:33 +0900 Subject: [PATCH 1/8] docs(security): strengthen release provenance guidance Document the organization preference for SLSA Build L3+ provenance, SBOM attestations, and linked artifacts metadata. Clarify when to use SLSA GitHub Generator, reusable workflow attestation, direct actions/attest, and SBOM release assets. Signed-off-by: Yunseo Kim --- SECURITY.md | 27 ++- docs/security/slsa-compliance-framework.md | 7 + docs/security/workflow-hardening.md | 228 ++++++++++++++++++++- 3 files changed, 251 insertions(+), 11 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index c5f7085..2f9ff16 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -74,12 +74,14 @@ This organization follows the [SLSA (Supply-chain Levels for Software Artifacts) ### At a Glance -- Build L1/L2 required; Build L3 target +- Build L1/L2 required; Build L3+ target wherever feasible - Source L1/L2 required; Source L3 target - Source L4 not achievable in a 1-person organization - SHA-pinned workflows, hardened runners, least-privilege permissions - Lockfiles committed, dependency review, OSV scanning - Signed commits, protected branches, OIDC, release integrity +- Build provenance and SBOM attestations for released artifacts +- Linked artifacts metadata for registry-published release artifacts ### Detailed Requirements @@ -149,7 +151,12 @@ jobs: - **GPG-signed commits** — All commits on `main` must be GPG-signed (enforced by repository rulesets) - **Linear history** — Squash-merge-only policy prevents history rewriting; force-push to `main` is blocked - **CI gate** — All required status checks must pass before any merge to `main` -- **Artifact attestations** — All released artifacts must include signed attestations +- **SLSA Build L3+ provenance** — Released artifacts should use SLSA GitHub Generator builders or reusable workflow based attestation to produce hardened Build L3+ provenance wherever feasible +- **Baseline build provenance attestations** — If an L3+ path is not available for a repository yet, released artifacts that consumers run, install, deploy, or download must still include signed provenance attestations +- **SBOM attestations and release assets** — Released binaries and container images must include signed SPDX and CycloneDX SBOM attestations when the build can generate them, and public releases should publish the same SBOM files as release assets +- **Linked artifacts metadata** — Registry-published release artifacts should upload storage metadata to GitHub's linked artifacts page through `actions/attest` or the artifact metadata API + +Workflow implementation requirements for provenance, SBOM attestations, and linked artifacts uploads are documented in [Workflow Hardening: Artifact Attestations](./docs/security/workflow-hardening.md#artifact-attestations). ## Verifying Artifacts @@ -191,6 +198,22 @@ gh attestation verify oci://ghcr.io/windlass-tech/my-image@sha256:abc123... \ -R windlass-tech/my-repo ``` +### Verify SBOM Attestations + +SBOM attestations require the SBOM predicate type. Verify each published SBOM format separately: + +```bash +# SPDX +gh attestation verify ./my-artifact \ + -R windlass-tech/my-repo \ + --predicate-type https://spdx.dev/Document/v2.3 + +# CycloneDX +gh attestation verify ./my-artifact \ + -R windlass-tech/my-repo \ + --predicate-type https://cyclonedx.org/bom +``` + ### Verify SLSA Provenance For artifacts with SLSA provenance generated by slsa-github-generator: diff --git a/docs/security/slsa-compliance-framework.md b/docs/security/slsa-compliance-framework.md index e0fe3c0..32ad9a1 100644 --- a/docs/security/slsa-compliance-framework.md +++ b/docs/security/slsa-compliance-framework.md @@ -88,6 +88,13 @@ Build L0 represents the absence of SLSA Build Track guarantees. No requirements - Cache poisoning must be prevented between builds - All external interactions must be captured in provenance +Implementation for this organization: + +- Prefer SLSA GitHub Generator builders when they fit the project ecosystem and release workflow +- Use reusable workflow based artifact attestations when a supported SLSA builder is not a good fit +- Use direct `actions/attest` provenance only as the baseline path when Build L3+ isolation is not yet feasible +- Document the verification command and expected signer workflow for each release-producing repository + ## SLSA Source Track Requirements The SLSA Source Track ensures the integrity and trustworthiness of source code throughout the development lifecycle. It provides increasing guarantees about how source revisions are created, managed, and protected. diff --git a/docs/security/workflow-hardening.md b/docs/security/workflow-hardening.md index cec4444..466468b 100644 --- a/docs/security/workflow-hardening.md +++ b/docs/security/workflow-hardening.md @@ -37,6 +37,7 @@ When adding or modifying workflows, contributors must: 2. **Job-level elevation** — Grant additional permissions at the job level only when required: - `id-token: write` — Required for OIDC token generation - `attestations: write` — Required for artifact attestations + - `artifact-metadata: write` — Required to upload storage records to the organization's linked artifacts page - `packages: write` — Required for container registry pushes - `pull-requests: write` — Required for PR comments @@ -69,6 +70,7 @@ When adding or modifying workflows, contributors must: contents: read id-token: write # Required for OIDC attestations: write # Required for attestations + artifact-metadata: write # Required for linked artifact storage records packages: write # Required for GHCR steps: - name: Harden the runner (Audit all outbound calls) @@ -87,7 +89,9 @@ When adding or modifying workflows, contributors must: ## Artifact Attestations -All released artifacts must include cryptographically signed attestations establishing build provenance. +All released artifacts that consumers run, install, deploy, or download must include cryptographically signed artifact attestations. Attestations establish provenance and integrity by linking the artifact to the repository, workflow, commit SHA, triggering event, build environment, and OIDC identity that produced it. + +Do not attest every test-only build or individual source/documentation files. Attest release binaries, packages, container images, and manifests that identify released contents by digest. ### Required Permissions @@ -100,9 +104,19 @@ permissions: contents: read # Required to read source code ``` -### Generating Attestations +Container image release jobs also require `packages: write` when pushing to GHCR or another registry. Jobs that should appear on the organization's linked artifacts page must also include `artifact-metadata: write`. + +Artifact attestations are available for public repositories on current GitHub plans. Private or internal repositories require GitHub Enterprise Cloud. GitHub Enterprise Server does not support artifact attestations. + +### Build Provenance Attestations + +The organization default is to produce SLSA Build L3+ provenance wherever feasible. Choose the provenance path in this order: + +1. **SLSA GitHub Generator builder** — Use when the project ecosystem and release flow match a supported builder. This is the preferred path for L3+ provenance because the builder is a trusted reusable workflow that builds the artifact and generates provenance with stronger isolation. +2. **Reusable workflow with `actions/attest`** — Use when a dedicated SLSA builder is not a good fit, but the build can be moved into a trusted reusable workflow. This follows GitHub's artifact-attestation path for SLSA Build L3 by isolating the build instructions in a reusable workflow and verifying the expected signer workflow. +3. **Direct `actions/attest` in the release workflow** — Use only as the baseline provenance path when Build L3+ is not yet feasible. It still creates signed GitHub artifact attestations and satisfies the release provenance requirement, but it should not be described as the repository's L3+ implementation by itself. -Use the `actions/attest` action to generate SLSA-compliant provenance: +Direct `actions/attest` baseline example: ```yaml - name: Generate artifact attestation @@ -111,7 +125,7 @@ Use the `actions/attest` action to generate SLSA-compliant provenance: subject-path: "${{ github.workspace }}/my-artifact" ``` -For container images: +For container images, attest the image by digest and push the attestation to the registry: ```yaml - name: Generate container attestation @@ -122,22 +136,215 @@ For container images: push-to-registry: true ``` +The `subject-name` must be the fully qualified image name without a tag, and `subject-digest` must be the immutable `sha256:...` digest from the image build/push step. `push-to-registry: true` is required when the attestation should upload registry storage metadata to the linked artifacts page, and `actions/attest` supports that option only with `subject-name` plus `subject-digest`. + +For reusable workflow based L3 provenance, generate the artifact and the `actions/attest` provenance inside the reusable workflow. Both the caller and reusable workflow must grant `contents: read`, `id-token: write`, and `attestations: write`; container builds also need `packages: write`. Verification policy must use `--signer-workflow`, and `--signer-repo` when the reusable workflow lives in another repository. + +### SBOM Attestations + +Released binaries and container images must also have SBOM attestations when the build can produce them. Prefer generating both SPDX and CycloneDX SBOMs because downstream consumers and scanners do not all accept the same format. Generate each SBOM during the release workflow, then run one `actions/attest` step per SBOM file with `sbom-path`. + +`actions/attest` accepts a single JSON-formatted SPDX or CycloneDX SBOM file per attestation. Each SBOM file must be 16 MB or smaller and cannot be combined with custom `predicate-type`, `predicate`, or `predicate-path` inputs in the same step. + +This policy requires released artifacts to include provenance and SBOM attestations. `anchore/sbom-action` is only the example SBOM generator used in this document. Projects may use another SBOM generation tool if it produces valid SPDX or CycloneDX JSON for `actions/attest` or an equivalent attestation workflow. + +When a project uses a different SBOM generator, configure workflow permissions and tool-specific settings according to that tool's requirements. The permission examples below apply to `anchore/sbom-action`; other tools may need different read, write, registry, or release permissions. + +For public releases, generate local SBOM files for attestation and publish the same SBOM files as release assets whenever possible. Attestation provides cryptographic binding to the released artifact. Release assets make the SBOMs easy to download for auditors, license review, offline storage, and third-party scanners. Release asset uploads do not create linked artifacts storage records by themselves. + +#### SBOM Permissions by Purpose + +Use the narrowest permissions that match the release job's behavior: + +| Purpose | Required permissions | Notes | +| :----------------------------------------- | :---------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | +| Local SBOM generation for attestation only | `contents: read`, plus `id-token: write` and `attestations: write` for attest | Set `upload-artifact: false` and `upload-release-assets: false` on `anchore/sbom-action`. | +| Workflow artifact upload | `contents: write` | Required by `anchore/sbom-action` when it uploads generated SBOMs as workflow artifacts. | +| Release asset upload | `actions: read`, `contents: write` | Needed so Anchore can read workflow artifacts and write release assets. Grant only on release jobs. | +| Release asset upload plus attestation | `actions: read`, `contents: write`, `id-token: write`, `attestations: write` | Add `packages: write` for container registry pushes and `artifact-metadata: write` for linked records. | + +`anchore/sbom-action` defaults to `upload-artifact: true` and `upload-release-assets: true`. If the SBOM is only an intermediate file for `actions/attest`, disable both upload behaviors explicitly. If the workflow is creating a GitHub Release, leave release publishing enabled and grant `actions: read` plus `contents: write` at the job level. + +Binary example: + +```yaml +- name: Generate SPDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: spdx-json + output-file: sbom.spdx.json + upload-artifact: false + upload-release-assets: false + +- name: Generate CycloneDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: cyclonedx-json + output-file: sbom.cyclonedx.json + upload-artifact: false + upload-release-assets: false + +- name: Generate SPDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.spdx.json + +- name: Generate CycloneDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.cyclonedx.json +``` + +Release asset publishing example: + +```yaml +permissions: + actions: read # Required to read workflow artifacts for release publishing + contents: write # Required to write SBOM files to the GitHub Release + id-token: write # Required for attestation signing + attestations: write # Required to persist SBOM attestations + artifact-metadata: write # Required for linked artifact storage records + +steps: + - name: Generate and publish SPDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: spdx-json + output-file: sbom.spdx.json + artifact-name: sbom.spdx.json + upload-artifact: true + upload-release-assets: true + + - name: Generate and publish CycloneDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: cyclonedx-json + output-file: sbom.cyclonedx.json + artifact-name: sbom.cyclonedx.json + upload-artifact: true + upload-release-assets: true + + - name: Generate SPDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.spdx.json + + - name: Generate CycloneDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.cyclonedx.json +``` + +Container image example: + +```yaml +- name: Generate SPDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + sbom-path: sbom.spdx.json + push-to-registry: true + +- name: Generate CycloneDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + sbom-path: sbom.cyclonedx.json + push-to-registry: true +``` + +SBOM attestations do not replace vulnerability scanning. They provide signed dependency metadata that consumers and auditors can verify alongside build provenance. + +### Linked Artifacts Page Uploads + +For container images and other registry-published release artifacts, workflows should upload storage metadata to the organization's linked artifacts page so security and compliance reviewers can trace artifacts to their source repository, build run, storage location, attestations, and deployment context. + +The `actions/attest` action automatically creates a linked artifacts storage record when both conditions are true: + +- `push-to-registry: true` is set on the attestation step +- The job has `artifact-metadata: write` + +For `actions/attest`, `push-to-registry: true` requires `subject-name` and `subject-digest`. Use it for container images and other registry artifacts that have a fully qualified registry name and immutable digest. Do not add `push-to-registry: true` to file-path attestations that use `subject-path`; those attestations are still valid, but they do not create linked artifacts storage records through `actions/attest`. + +Storage record creation is enabled by default when `push-to-registry: true` is set. Set `create-storage-record: false` only when the artifact must not appear on the linked artifacts page. Storage records can be created only for artifacts built from organization-owned repositories. + +For non-registry release assets that still need linked artifacts metadata, use the artifact metadata REST API or an approved integration instead of forcing `push-to-registry` into a file-path attestation. + +Recommended container release pattern: + +```yaml +permissions: + contents: read + id-token: write + attestations: write + packages: write + artifact-metadata: write + +steps: + - name: Build and push image + id: build + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + + - name: Generate artifact attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + push-to-registry: true +``` + +If an artifact is not attested, or if deployment/runtime records must be uploaded, use the artifact metadata REST API or an approved integration such as JFrog Artifactory, Dynatrace, or Microsoft Defender for Cloud. Linked artifacts records store metadata only; they do not store artifact files. + ### Attestation Modes | Mode | Input | Description | -| ------------------------ | ------------------------------ | -------------------------------------------- | +| :----------------------- | :----------------------------- | :------------------------------------------- | | **Provenance** (default) | `subject-path` only | Auto-generates SLSA build provenance | | **SBOM** | `sbom-path` provided | Creates attestation from SPDX/CycloneDX SBOM | | **Custom** | `predicate-type` + `predicate` | User-defined predicate | +### Verification Expectations + +Consumers verify build provenance with `gh attestation verify`. SBOM attestations must be verified with the SBOM predicate type, such as `https://spdx.dev/Document/v2.3` for SPDX SBOMs. + +```bash +# Verify SPDX SBOM attestation +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --predicate-type https://spdx.dev/Document/v2.3 + +# Verify CycloneDX SBOM attestation +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --predicate-type https://cyclonedx.org/bom +``` + +For reusable workflow builders, verification policy should pin the expected signing workflow with `--signer-workflow`, and use `--signer-repo` when the reusable workflow lives in a separate repository. + ## SLSA GitHub Generator -For language-specific builds, use the [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) to generate SLSA Build Level 3 provenance: +For language-specific builds, prefer the [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) when a supported builder fits the project. These builders are the organization's default path for SLSA Build L3+ provenance because they build the artifact and generate provenance inside a trusted reusable workflow. ### Available Builders | Ecosystem | Builder | Status | -| ----------- | ------------------------------------------------------------------------------------ | ------ | +| :---------- | :----------------------------------------------------------------------------------- | :----- | | Go | `slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml` | Stable | | Node.js/npm | `slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml` | Beta | | Maven | `slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml` | Beta | @@ -162,8 +369,11 @@ jobs: ### GitHub Security -- [GitHub Artifact Attestations](https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds) -- [GitHub Artifact Attestations - Increase Security](https://docs.github.com/en/actions/security-guides/using-artifact-attestations/increase-security-for-your-builds) +- [GitHub Artifact Attestations](https://docs.github.com/en/actions/concepts/security/artifact-attestations) +- [Using artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations) +- [Using artifact attestations and reusable workflows to achieve SLSA v1 Build Level 3](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/increase-security-rating) +- [GitHub Linked Artifacts](https://docs.github.com/en/code-security/concepts/supply-chain-security/linked-artifacts) +- [Uploading storage and deployment data to the linked artifacts page](https://docs.github.com/en/code-security/how-tos/secure-your-supply-chain/establish-provenance-and-integrity/upload-linked-artifacts) - [GitHub Reusable Workflows](https://docs.github.com/en/actions/sharing-automations/reusing-workflows) - [actions/attest](https://github.com/actions/attest) - [GitHub Actions Security Hardening](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions) From 3d1aa79ba55af806a58db96b68d4d1c54f14d80f Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 05:41:42 +0900 Subject: [PATCH 2/8] docs(security): consolidate workflow hardening guidance Move OIDC and artifact verification details into the workflow hardening guide. Clarify SLSA GitHub Generator builder versus generator options and add the GitHub SLSA Level 3 attestation reference. Signed-off-by: Yunseo Kim --- docs/security/workflow-hardening.md | 170 ++++++++++++++++++++++------ 1 file changed, 136 insertions(+), 34 deletions(-) diff --git a/docs/security/workflow-hardening.md b/docs/security/workflow-hardening.md index 466468b..02d1661 100644 --- a/docs/security/workflow-hardening.md +++ b/docs/security/workflow-hardening.md @@ -87,6 +87,39 @@ When adding or modifying workflows, contributors must: - Deployment branch policies - Wait timers where appropriate +## OIDC and Cloud Authentication + +Use OpenID Connect (OIDC) for authentication to cloud providers instead of long-lived credentials stored as GitHub secrets. OIDC credentials are short-lived, scoped to the workflow identity, and controlled by provider-side trust policies. + +Supported providers: + +- AWS — `aws-actions/configure-aws-credentials` +- Azure — `azure/login` +- Google Cloud — `google-github-actions/auth` + +### AWS OIDC Example + +```yaml +permissions: + id-token: write + contents: read + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@e3dd6a429c905ace6919b0a7664b96b2b5dc3c81 # v4.0.2 + with: + role-to-assume: arn:aws:iam::123456789012:role/github-deploy-role + aws-region: us-east-1 + + - name: Deploy + run: aws s3 sync ./dist s3://my-bucket/ +``` + ## Artifact Attestations All released artifacts that consumers run, install, deploy, or download must include cryptographically signed artifact attestations. Attestations establish provenance and integrity by linking the artifact to the repository, workflow, commit SHA, triggering event, build environment, and OIDC identity that produced it. @@ -112,11 +145,51 @@ Artifact attestations are available for public repositories on current GitHub pl The organization default is to produce SLSA Build L3+ provenance wherever feasible. Choose the provenance path in this order: -1. **SLSA GitHub Generator builder** — Use when the project ecosystem and release flow match a supported builder. This is the preferred path for L3+ provenance because the builder is a trusted reusable workflow that builds the artifact and generates provenance with stronger isolation. -2. **Reusable workflow with `actions/attest`** — Use when a dedicated SLSA builder is not a good fit, but the build can be moved into a trusted reusable workflow. This follows GitHub's artifact-attestation path for SLSA Build L3 by isolating the build instructions in a reusable workflow and verifying the expected signer workflow. -3. **Direct `actions/attest` in the release workflow** — Use only as the baseline provenance path when Build L3+ is not yet feasible. It still creates signed GitHub artifact attestations and satisfies the release provenance requirement, but it should not be described as the repository's L3+ implementation by itself. +1. **SLSA GitHub Generator builder** — Use when a hosted builder can both build the artifact and generate provenance for the project's ecosystem. +2. **SLSA GitHub Generator generator** — Use when the release workflow already builds the artifact and only needs SLSA provenance generation for an existing file or container image. +3. **Reusable workflow with `actions/attest`** — Use when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. +4. **Direct `actions/attest` in the release workflow** — Use only as the baseline provenance path when Build L3+ is not yet feasible. + +#### SLSA GitHub Generator + +The [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) project provides both builders and generators. Builders perform the build and generate provenance together. Generators only generate provenance for artifacts that were already produced by the repository's release workflow. Prefer a builder when it fits the project ecosystem; use a generator when the build flow is too custom for a hosted builder or the artifact already exists. + +Available builders and generators: + +| Kind | Target | Workflow | What it does | Status | +| :------------ | :--------------------------------- | :----------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :----- | +| **Builder** | Go projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml` | Builds and generates provenance | Stable | +| **Builder** | Node.js/npm packages | `slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml` | Builds and generates provenance | Beta | +| **Builder** | Maven packages | `slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml` | Builds and generates provenance | Beta | +| **Builder** | Gradle projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_gradle_slsa3.yml` | Builds and generates provenance | Beta | +| **Builder** | Bazel projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_bazel_slsa3.yml` | Builds and generates provenance | WIP | +| **Builder** | Artifacts built inside a container | `slsa-framework/slsa-github-generator/.github/workflows/builder_container-based_slsa3.yml` | Runs a configured container build and generates provenance | Beta | +| **Generator** | Existing file artifacts | `slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml` | Generates provenance for arbitrary file-based artifacts, for any ecosystem and programming language | Stable | +| **Generator** | Existing container images | `slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml` | Generate provenance for container images | Stable | -Direct `actions/attest` baseline example: +> [!IMPORTANT] +> SLSA builders and generators must be referenced by tag (e.g., `@v2.1.0`) for `slsa-verifier` to validate the trusted reusable workflow. This is an intentional exception to the SHA-pinning requirement. + +```yaml +jobs: + build: + uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@v2.1.0 + with: + go-version: "1.26" + # ... other inputs +``` + +#### Reusable Workflow Attestation + +Use this path when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. This follows GitHub's artifact-attestation path for SLSA Build L3 by isolating the build instructions in a reusable workflow and verifying the expected signer workflow. + +Generate the artifact and the `actions/attest` provenance inside the reusable workflow. Both the caller and reusable workflow must grant `contents: read`, `id-token: write`, and `attestations: write`; container builds also need `packages: write`. Verification policy must use `--signer-workflow`, and `--signer-repo` when the reusable workflow lives in another repository. + +#### Direct `actions/attest` Baseline + +Use direct `actions/attest` only when Build L3+ is not yet feasible. It still creates signed GitHub artifact attestations and satisfies the release provenance requirement, but it should not be described as the repository's SLSA Build L3+ implementation by itself. + +Direct baseline example: ```yaml - name: Generate artifact attestation @@ -138,8 +211,6 @@ For container images, attest the image by digest and push the attestation to the The `subject-name` must be the fully qualified image name without a tag, and `subject-digest` must be the immutable `sha256:...` digest from the image build/push step. `push-to-registry: true` is required when the attestation should upload registry storage metadata to the linked artifacts page, and `actions/attest` supports that option only with `subject-name` plus `subject-digest`. -For reusable workflow based L3 provenance, generate the artifact and the `actions/attest` provenance inside the reusable workflow. Both the caller and reusable workflow must grant `contents: read`, `id-token: write`, and `attestations: write`; container builds also need `packages: write`. Verification policy must use `--signer-workflow`, and `--signer-repo` when the reusable workflow lives in another repository. - ### SBOM Attestations Released binaries and container images must also have SBOM attestations when the build can produce them. Prefer generating both SPDX and CycloneDX SBOMs because downstream consumers and scanners do not all accept the same format. Generate each SBOM during the release workflow, then run one `actions/attest` step per SBOM file with `sbom-path`. @@ -321,48 +392,78 @@ If an artifact is not attested, or if deployment/runtime records must be uploade ### Verification Expectations -Consumers verify build provenance with `gh attestation verify`. SBOM attestations must be verified with the SBOM predicate type, such as `https://spdx.dev/Document/v2.3` for SPDX SBOMs. +Consumers verify build provenance with `gh attestation verify`. For reusable workflow builders, verification policy should pin the expected signing workflow with `--signer-workflow`, and use `--signer-repo` when the reusable workflow lives in a separate repository. + +Verification confirms: + +1. **Authenticity** — The artifact was built by the claimed repository +2. **Integrity** — The artifact has not been tampered with since build +3. **Provenance** — The artifact's build process is documented +4. **Source** — The exact source code revision used to build the artifact is known +5. **Build environment** — The workflow that produced the artifact is identified + +#### Install Verification Tools ```bash -# Verify SPDX SBOM attestation -gh attestation verify ./my-artifact \ - -R windlasstech/my-repo \ - --predicate-type https://spdx.dev/Document/v2.3 +# macOS +brew install gh + +# Ubuntu/Debian +sudo apt install gh + +# SLSA verifier for slsa-github-generator provenance +go install github.com/slsa-framework/slsa-verifier/cli/slsa-verifier@v2.0.0 +``` -# Verify CycloneDX SBOM attestation +#### Verify Binary Attestations + +```bash +# Verify a downloaded binary +gh attestation verify ./my-artifact -R windlasstech/my-repo + +# Verify with a specific workflow gh attestation verify ./my-artifact \ -R windlasstech/my-repo \ - --predicate-type https://cyclonedx.org/bom + --signer-workflow windlasstech/my-repo/.github/workflows/release.yml ``` -For reusable workflow builders, verification policy should pin the expected signing workflow with `--signer-workflow`, and use `--signer-repo` when the reusable workflow lives in a separate repository. +#### Verify Container Image Attestations + +```bash +# Verify a container image +gh attestation verify oci://ghcr.io/windlasstech/my-image:latest \ + -R windlasstech/my-repo + +# Verify by digest (recommended) +gh attestation verify oci://ghcr.io/windlasstech/my-image@sha256:abc123... \ + -R windlasstech/my-repo +``` -## SLSA GitHub Generator +#### Verify SBOM Attestations -For language-specific builds, prefer the [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) when a supported builder fits the project. These builders are the organization's default path for SLSA Build L3+ provenance because they build the artifact and generate provenance inside a trusted reusable workflow. +SBOM attestations must be verified with the SBOM predicate type, such as `https://spdx.dev/Document/v2.3` for SPDX SBOMs. Verify each published SBOM format separately: -### Available Builders +```bash +# SPDX +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --predicate-type https://spdx.dev/Document/v2.3 -| Ecosystem | Builder | Status | -| :---------- | :----------------------------------------------------------------------------------- | :----- | -| Go | `slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml` | Stable | -| Node.js/npm | `slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml` | Beta | -| Maven | `slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml` | Beta | -| Gradle | `slsa-framework/slsa-github-generator/.github/workflows/builder_gradle_slsa3.yml` | Beta | -| Generic | `slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml` | Stable | +# CycloneDX +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --predicate-type https://cyclonedx.org/bom +``` -### Reference Requirements +#### Verify SLSA Provenance -> [!IMPORTANT] -> SLSA generators must be referenced by tag (e.g., `@v2.1.0`) for `slsa-verifier` to validate the trusted builder. This is an intentional exception to the SHA-pinning requirement. +For artifacts with SLSA provenance generated by slsa-github-generator: -```yaml -jobs: - build: - uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@v2.1.0 - with: - go-version: "1.26" - # ... other inputs +```bash +slsa-verifier verify-artifact my-artifact \ + --provenance-path my-artifact.intoto.jsonl \ + --source-uri github.com/windlasstech/my-repo \ + --source-tag v1.0.0 ``` ## References @@ -372,6 +473,7 @@ jobs: - [GitHub Artifact Attestations](https://docs.github.com/en/actions/concepts/security/artifact-attestations) - [Using artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations) - [Using artifact attestations and reusable workflows to achieve SLSA v1 Build Level 3](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/increase-security-rating) +- [Enhance build security and reach SLSA Level 3 with GitHub Artifact Attestations](https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/) - [GitHub Linked Artifacts](https://docs.github.com/en/code-security/concepts/supply-chain-security/linked-artifacts) - [Uploading storage and deployment data to the linked artifacts page](https://docs.github.com/en/code-security/how-tos/secure-your-supply-chain/establish-provenance-and-integrity/upload-linked-artifacts) - [GitHub Reusable Workflows](https://docs.github.com/en/actions/sharing-automations/reusing-workflows) From d4180444bef62b4e3314d60ff68746e475cdcaaf Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 05:41:54 +0900 Subject: [PATCH 3/8] docs(security): streamline security policy overview Keep SECURITY.md focused on policy-level reporting, monitoring, and supply-chain requirements. Move detailed workflow and artifact verification guidance behind companion document links. Signed-off-by: Yunseo Kim --- SECURITY.md | 198 +++++++++++----------------------------------------- 1 file changed, 42 insertions(+), 156 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 2f9ff16..b6ca569 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -68,6 +68,39 @@ Please do not: - Degrade service availability - Social engineer, spam, or perform destructive testing +## Security Monitoring + +### Audit Logging + +- All workflow runs are logged via GitHub's audit log +- Access to secrets is logged +- Deployment activity is tracked + +### Vulnerability Scanning + +- Dependabot alerts are enabled on all repositories +- Code scanning with CodeQL runs on all PRs +- OSV Scanner runs on PRs and scheduled full scans +- Secret scanning prevents credential leakage + +### OpenSSF Scorecard + +This organization uses [OpenSSF Scorecard](https://securityscorecards.dev/) to continuously monitor security posture: + +- Binary artifacts +- Branch protection +- Code review +- Dependency update tool +- Fuzzing +- License +- Maintained +- Pinned dependencies +- SAST +- Security policy +- Signed releases +- Token permissions +- Vulnerabilities + ## Supply Chain Integrity This organization follows the [SLSA (Supply-chain Levels for Software Artifacts)](https://slsa.dev/) framework to ensure software supply chain security. Detailed implementation guidance is available in the companion documents linked below. @@ -75,7 +108,7 @@ This organization follows the [SLSA (Supply-chain Levels for Software Artifacts) ### At a Glance - Build L1/L2 required; Build L3+ target wherever feasible -- Source L1/L2 required; Source L3 target +- Source L1/L2 required; Source L3 controls followed wherever feasible - Source L4 not achievable in a 1-person organization - SHA-pinned workflows, hardened runners, least-privilege permissions - Lockfiles committed, dependency review, OSV scanning @@ -91,59 +124,12 @@ This organization follows the [SLSA (Supply-chain Levels for Software Artifacts) | Workflow hardening | [docs/security/workflow-hardening.md](./docs/security/workflow-hardening.md) | | Dependency security | [docs/security/dependency-security.md](./docs/security/dependency-security.md) | -### Source Integrity - -#### Commit Signing - -All commits to protected branches must be cryptographically signed: - -- **GPG signing** — Traditional approach using GPG keys -- **SSH signing** — Alternative to GPG using SSH keys -- **Sigstore gitsign** — Keyless signing linking to OIDC identity (recommended) - -#### Branch Protection +### Source and Workflow Integrity -All repositories must enforce: +Source and workflow controls are implemented through signed commits, protected branches, SHA-pinned actions, hardened runners, least-privilege workflow permissions, and OIDC-based cloud authentication. -- Require signed commits -- Require pull request reviews (minimum 1 reviewer) -- Require status checks to pass before merging -- Require linear history (no merge commits) -- Include administrators in restrictions -- Restrict force pushes - -### OIDC and Cloud Authentication - -Use OpenID Connect (OIDC) for authentication to cloud providers instead of long-lived credentials stored as secrets. - -#### Supported Providers - -- AWS — `aws-actions/configure-aws-credentials` -- Azure — `azure/login` -- Google Cloud — `google-github-actions/auth` - -#### AWS OIDC Example - -```yaml -permissions: - id-token: write - contents: read - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@e3dd6a429c905ace6919b0a7664b96b2b5dc3c81 # v4.0.2 - with: - role-to-assume: arn:aws:iam::123456789012:role/github-deploy-role - aws-region: us-east-1 - - - name: Deploy - run: aws s3 sync ./dist s3://my-bucket/ -``` +- Source track requirements, branch protection controls, and commit signing expectations are documented in [SLSA Compliance Framework: SLSA Source Track Requirements](./docs/security/slsa-compliance-framework.md#slsa-source-track-requirements). +- GitHub Actions hardening, permission patterns, and OIDC provider examples are documented in [Workflow Hardening](./docs/security/workflow-hardening.md). ### Release Integrity @@ -160,117 +146,17 @@ Workflow implementation requirements for provenance, SBOM attestations, and link ## Verifying Artifacts -Consumers can verify the authenticity and provenance of artifacts from this organization using the GitHub CLI: - -### Install GitHub CLI - -```bash -# macOS -brew install gh - -# Ubuntu/Debian -sudo apt install gh - -# Or download from https://cli.github.com/ -``` - -### Verify Binary Attestations - -```bash -# Verify a downloaded binary -gh attestation verify ./my-artifact -R windlass-tech/my-repo - -# Verify with specific workflow -gh attestation verify ./my-artifact \ - -R windlass-tech/my-repo \ - --signer-workflow windlass-tech/my-repo/.github/workflows/release.yml -``` - -### Verify Container Image Attestations - -```bash -# Verify a container image -gh attestation verify oci://ghcr.io/windlass-tech/my-image:latest \ - -R windlass-tech/my-repo - -# Verify by digest (recommended) -gh attestation verify oci://ghcr.io/windlass-tech/my-image@sha256:abc123... \ - -R windlass-tech/my-repo -``` - -### Verify SBOM Attestations - -SBOM attestations require the SBOM predicate type. Verify each published SBOM format separately: - -```bash -# SPDX -gh attestation verify ./my-artifact \ - -R windlass-tech/my-repo \ - --predicate-type https://spdx.dev/Document/v2.3 - -# CycloneDX -gh attestation verify ./my-artifact \ - -R windlass-tech/my-repo \ - --predicate-type https://cyclonedx.org/bom -``` - -### Verify SLSA Provenance - -For artifacts with SLSA provenance generated by slsa-github-generator: - -```bash -# Install slsa-verifier -go install github.com/slsa-framework/slsa-verifier/cli/slsa-verifier@v2.0.0 - -# Verify provenance -slsa-verifier verify-artifact my-artifact \ - --provenance-path my-artifact.intoto.jsonl \ - --source-uri github.com/windlass-tech/my-repo \ - --source-tag v1.0.0 -``` - -### What Verification Checks +Consumers can verify the authenticity, integrity, and provenance of artifacts from this organization using GitHub artifact attestations and SLSA provenance verification tools. Verification confirms: 1. **Authenticity** — The artifact was built by the claimed repository 2. **Integrity** — The artifact has not been tampered with since build 3. **Provenance** — The artifact's build process is documented -4. **Source** — The exact source code (commit SHA) used to build -5. **Build environment** — The workflow that produced the artifact - -## Security Monitoring - -### Audit Logging - -- All workflow runs are logged via GitHub's audit log -- Access to secrets is logged -- Deployment activity is tracked +4. **Source** — The exact source code revision used to build the artifact is known +5. **Build environment** — The workflow that produced the artifact is identified -### Vulnerability Scanning - -- Dependabot alerts are enabled on all repositories -- Code scanning with CodeQL runs on all PRs -- OSV Scanner runs on PRs and scheduled full scans -- Secret scanning prevents credential leakage - -### Security Scorecard - -This organization uses [OpenSSF Scorecard](https://securityscorecards.dev/) to continuously monitor security posture: - -- Binary artifacts -- Branch protection -- Code review -- Dependency update tool -- Fuzzing -- License -- Maintained -- Pinned dependencies -- SAST -- Security policy -- Signed releases -- Token permissions -- Vulnerabilities +Detailed verification commands for binaries, container images, SBOM attestations, and SLSA provenance are documented in [Workflow Hardening: Verification Expectations](./docs/security/workflow-hardening.md#verification-expectations). ## References From 6c9176050694eb191fcbe85249ff3735271d1f28 Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 05:42:11 +0900 Subject: [PATCH 4/8] docs(security): clarify dependency defense layers Add a dependency defense overview that explains how lockfiles, updates, cooldowns, dependency review, and OSV scanning fit together. Nest Dependabot cooldown guidance under update automation and remove redundant comparison tables. Signed-off-by: Yunseo Kim --- docs/security/dependency-security.md | 42 ++++++++++++---------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/docs/security/dependency-security.md b/docs/security/dependency-security.md index 9541dfb..9696d8e 100644 --- a/docs/security/dependency-security.md +++ b/docs/security/dependency-security.md @@ -5,6 +5,18 @@ All projects must commit dependency lockfiles to version control to ensure reproducible builds and enable security auditing. +## Dependency Defense Overview + +Dependency security uses layered controls so each tool covers a different point in the lifecycle: + +| Control | Timing | Scope | Primary outcome | +| :-------------------- | :--------------------------- | :--------------------------- | :------------------------------------------- | +| **Lockfiles** | During development and build | Resolved dependency graph | Reproducible builds and reviewable diffs | +| **Dependabot** | Continuous and scheduled | Existing dependency versions | Update PRs for vulnerable or stale packages | +| **Cooldowns** | Before version update PRs | Newly published versions | Time for malicious releases to be detected | +| **Dependency Review** | Pull request | Newly changed dependencies | Blocks vulnerable or non-compliant additions | +| **OSV Scanner** | Pull request and schedule | Full dependency tree | Finds known vulnerabilities across projects | + ## Lockfile Requirements | Ecosystem | Lockfile | Commit Required | @@ -26,14 +38,14 @@ All projects must commit dependency lockfiles to version control to ensure repro - Security updates should be applied immediately - Major version updates require review and testing -## Dependabot Cooldown Configuration +### Dependabot Cooldown Configuration Cooldown periods delay version update PRs to allow community vetting of new releases. This mitigates supply chain attacks by providing time for malicious packages to be detected and yanked before adoption. > [!NOTE] > Security updates bypass cooldowns and are created immediately. Cooldowns apply only to version updates. -### Ecosystem-Specific Recommendations +#### Ecosystem-Specific Recommendations | Ecosystem | Patch | Minor | Major | Rationale | | :------------------------ | :-------- | :--------- | :--------- | :------------------------------------------------------------------------------------ | @@ -47,14 +59,14 @@ Cooldown periods delay version update PRs to allow community vetting of new rele > [!IMPORTANT] > SemVer-based cooldown (`semver-major-days`, `semver-minor-days`, `semver-patch-days`) is only supported by package ecosystems that use Semantic Versioning. Ecosystems like **GitHub Actions**, **Docker**, **Terraform**, and **Bazel** only support `default-days`. -### SemVer Cooldown Support by Ecosystem +#### SemVer Cooldown Support by Ecosystem | Support | Ecosystems | | :------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SemVer + default-days** | `bundler`, `bun`, `cargo`, `composer`, `dotnet_sdk`, `elm`, `gomod`, `gradle`, `hex`, `julia`, `maven`, `npm`, `nuget`, `opentofu`, `pip`, `pub`, `swift`, `uv` | | **default-days only** | `bazel`, `devcontainers`, `docker`, `docker_compose`, `github-actions`, `gitsubmodule`, `helm`, `terraform` | -### Cooldown Rationale +#### Cooldown Rationale **Why cooldowns matter:** @@ -68,7 +80,7 @@ Cooldown periods delay version update PRs to allow community vetting of new rele - **Minor (y in x.y.z)**: New features; moderate cooldown for API stability verification - **Major (x in x.y.z)**: Breaking changes; longest cooldown for migration planning and community feedback -### Rust-Specific Considerations +#### Rust-Specific Considerations The Rust ecosystem has unique characteristics affecting cooldown strategy: @@ -80,7 +92,7 @@ The Rust ecosystem has unique characteristics affecting cooldown strategy: 4. **Cargo.lock Pinning**: Unlike npm, Cargo.lock should always be committed. This creates natural review gates that complement cooldowns. -### Example Configuration +#### Example Configuration ```yaml # dependabot.yml - Production-grade Rust project @@ -120,15 +132,6 @@ The [Dependency Review Action](https://github.com/actions/dependency-review-acti > [!NOTE] > Dependency Review is available for all public repositories. For private repositories, GitHub Advanced Security is required. -### Key Differences from Dependabot - -| Feature | Dependabot | Dependency Review | -| :-------------- | :--------------------------------- | :------------------------------------ | -| **Timing** | Alerts on existing vulnerabilities | Blocks new vulnerabilities at PR time | -| **Scope** | Scans entire dependency tree | Scans only changed dependencies | -| **Action** | Creates update PRs | Fails PR checks to prevent merge | -| **Integration** | Standalone alerts | GitHub Actions workflow | - ### Required Workflow Template All repositories must implement Dependency Review with this hardened configuration: @@ -256,15 +259,6 @@ This ensures all PRs must pass dependency review before merging, regardless of i The [OSV Scanner](https://google.github.io/osv-scanner/) workflow detects known vulnerabilities in project dependencies using the Open Source Vulnerabilities database. It complements Dependency Review by scanning the entire dependency tree, not just changed dependencies. -### Key Differences from Dependency Review - -| Feature | Dependency Review | OSV Scanner | -| :----------- | :-------------------------- | :---------------------------------------- | -| **Timing** | Blocks new vulns at PR time | Scans all dependencies on PR and schedule | -| **Scope** | Only changed dependencies | Full dependency tree | -| **Database** | GitHub Advisory Database | Open Source Vulnerabilities (OSV) | -| **Output** | PR annotations and comments | SARIF for GitHub Security tab | - ### Recommended Defaults - `upload-sarif: true` — upload results to the repository's code scanning dashboard From 76a64d4a9e05b0673ead7872562bedab657c398b Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 05:42:25 +0900 Subject: [PATCH 5/8] docs(security): clarify feasible Source L3 controls Describe Source L3 as controls to follow wherever feasible rather than a guaranteed level for a 1-person organization. Require independent review when another trusted reviewer is available and call out human review for bot-authored PRs. Signed-off-by: Yunseo Kim --- docs/security/slsa-compliance-framework.md | 106 +++++++++------------ 1 file changed, 44 insertions(+), 62 deletions(-) diff --git a/docs/security/slsa-compliance-framework.md b/docs/security/slsa-compliance-framework.md index 32ad9a1..9b9ebf6 100644 --- a/docs/security/slsa-compliance-framework.md +++ b/docs/security/slsa-compliance-framework.md @@ -46,8 +46,8 @@ This organization follows the [SLSA (Supply-chain Levels for Software Artifacts) SLSA Source L3 - 🎯 Target - Continuous technical controls on protected branches + 🎯 Follow where feasible + Continuous technical controls on protected branches when practical SLSA Source L4 @@ -58,7 +58,7 @@ This organization follows the [SLSA (Supply-chain Levels for Software Artifacts) > [!NOTE] -> SLSA v1.2 defines Build Track levels 0-3 and Source Track levels 1-4. Build L0 represents no SLSA guarantees. Source L4 requires two-party review and is not achievable for a single-person organization. See [Source Track Achievability for 1-Person Organizations](#source-track-achievability-for-1-person-organizations) for details. +> SLSA v1.2 defines Build Track levels 0-3 and Source Track levels 1-4. Build L0 represents no SLSA guarantees. Source L4 requires two-party review and is not achievable for a single-person organization; see [the Source L4 section](#source-l4--two-party-review) for the structural limitation and compensating controls. ## SLSA Build Track Requirements @@ -156,96 +156,78 @@ Implementation for this organization: - Repository rulesets protect `main` and release branches with required status checks - All PRs must pass CI checks (markdown lint, dependency review, scorecard) before merge -- Required reviewers are enforced on all PRs to protected branches +- Reviewer requirements are enforced on protected branches when independent review is feasible - Status checks include: OpenSSF Scorecard, Dependency Review, CodeQL, OSV Scanner - Branch protection requires signed commits - The organization documents all technical controls in this policy -### Source L4 — Two-Party Review - -Changes to protected branches require review and agreement by two or more trusted persons prior to submission. - -Requirements: - -- Changes must be agreed to by two different trusted persons (uploader + reviewer, or two reviewers) -- Reviews must cover security-relevant properties of the code -- The final revision submitted must be the one reviewed (reset votes on changes) -- Approvals are context-specific (repo + branch) -- The SCS must present reviewers with a clear representation of the proposed change -- Trusted robots may be granted exceptions for automated changes (e.g., Dependabot) - -Achievability for this organization: - -- **Not achievable under a 1-person organization model.** Source L4 explicitly requires two distinct trusted persons for every change. A single individual cannot satisfy the "two-party" requirement by definition. -- See [Source Track Achievability for 1-Person Organizations](#source-track-achievability-for-1-person-organizations) for mitigation strategies and alternative controls. - -## Source Track Achievability for 1-Person Organizations - -### Maximum Achievable Level: Source L3 - -For a single-person organization, **Source L3 is the maximum realistically achievable level** under the SLSA v1.2 specification. Source L4 is fundamentally incompatible with a 1-person model because it requires two distinct trusted persons to review every change. - -### Why Source L4 Is Not Achievable +For a single-person organization, **Source L3 should be treated as a best-effort target rather than a guaranteed achievable level**. Repositories must follow Source L3 controls wherever feasible, but some controls depend on repository context and available trusted reviewers. In particular, independent human review is practical only when someone other than the last pusher can review the change; bot-authored PRs such as Dependabot updates may be easier to review independently than human-authored changes in a 1-person organization. -The SLSA Source L4 requirement for two-party review exists specifically to mitigate insider threats and unilateral changes. The specification states: +Practical implementation controls: -> Changes in protected branches MUST be agreed to by two or more trusted persons prior to submission. - -A "trusted person" is defined as a human authorized by the organization to propose and approve changes. A single individual cannot simultaneously be two different trusted persons. This is not a technical limitation but a structural requirement of the security model. - -### Achieving Source L3: Practical Implementation - -A 1-person organization can achieve Source L3 by implementing the following controls using GitHub features: - -1. **Branch Protection Rulesets** +1. **Branch protection rulesets** - Protect `main` and all release branches - - Require pull request reviews (even if self-reviewed, the mechanism is enforced) - Require status checks to pass before merging - Require signed commits - Block force pushes + - Require pull request review when a trusted reviewer other than the last pusher is available + - For bot-authored PRs, such as Dependabot updates, perform human review before merging -2. **Required Status Checks** +2. **Required status checks** - OpenSSF Scorecard analysis - Dependency Review - CodeQL code scanning - Markdown lint and format checks - Any repository-specific test suites -3. **Commit Signing Enforcement** +3. **Commit signing enforcement** - Require all commits on protected branches to be signed - - Use Sigstore gitsign for keyless signing (recommended) - - Alternative: GPG or SSH signing + - Use Sigstore gitsign for keyless signing when possible + - Allow GPG or SSH signing as alternatives -4. **Audit Logging** - - Enable GitHub audit logs for all repository events +4. **Audit logging and ruleset governance** + - Enable GitHub audit logs for repository events - Monitor for unexpected access patterns or policy violations - - Export logs for long-term retention + - Use organization-wide rulesets for consistency + - Document ruleset bypassers and bypass reasons -5. **Repository Rulesets (GitHub)** - - Use rulesets instead of legacy branch protection for granular control - - Apply rulesets organization-wide for consistency - - Require ruleset bypassers to be documented +### Source L4 — Two-Party Review -### Mitigating the Absence of Source L4 +Changes to protected branches require review and agreement by two or more trusted persons prior to submission. -While two-party review is not possible with one person, the following compensating controls reduce the risk of unilateral malicious changes: +Requirements: -| Control | Purpose | Implementation | -| :------------------------------ | :---------------------------- | :------------------------------------------------------------------------ | -| **Self-review checklist** | Force deliberate review | Maintain a security checklist that must be completed before self-approval | -| **Automated security scanning** | Detect malicious patterns | CodeQL, Semgrep, or similar tools scanning for suspicious code | -| **Immutable audit trail** | Enable post-hoc investigation | Signed commits + GitHub audit logs provide tamper-evident history | -| **External monitoring** | Detect unauthorized changes | OpenSSF Scorecard monitors branch protection and signed commits | -| **Artifact attestations** | Verify build integrity | All releases include signed SLSA Build provenance | +- Changes must be agreed to by two different trusted persons (uploader + reviewer, or two reviewers) +- Reviews must cover security-relevant properties of the code +- The final revision submitted must be the one reviewed (reset votes on changes) +- Approvals are context-specific (repo + branch) +- The SCS must present reviewers with a clear representation of the proposed change +- Trusted robots may be granted exceptions for automated changes (e.g., Dependabot) + +Achievability for this organization: + +- **Not achievable under a 1-person organization model.** Source L4 explicitly requires two distinct trusted persons for every change. A single individual cannot satisfy the "two-party" requirement by definition. +- This is not a technical limitation but a structural requirement of the security model. The requirement exists to mitigate insider threats and unilateral changes. + +## Mitigations and Transition Path + +While two-party review is not possible with one person, the following compensating controls reduce the risk of unilateral malicious changes: -## Transition Path to Source L4 +| Control | Purpose | Implementation | +| :------------------------------ | :----------------------------- | :------------------------------------------------------------------------------------------------------------------- | +| **Review when feasible** | Add independent human judgment | Require review by someone other than the last pusher whenever available; always review bot-authored PRs before merge | +| **Self-review checklist** | Force deliberate review | Maintain a security checklist for cases where no independent reviewer is available | +| **Automated security scanning** | Detect malicious patterns | CodeQL, Semgrep, or similar tools scanning for suspicious code | +| **Immutable audit trail** | Enable post-hoc investigation | Signed commits + GitHub audit logs provide tamper-evident history | +| **External monitoring** | Detect unauthorized changes | OpenSSF Scorecard monitors branch protection and signed commits | +| **Artifact attestations** | Verify build integrity | All releases include signed SLSA Build provenance | If the organization grows to multiple trusted contributors, the following steps enable Source L4: 1. Add at least one additional trusted person with write access 2. Configure branch protection to require 1 reviewer (GitHub minimum) 3. Document the review policy requiring security-relevant review -4. Maintain the existing Source L3 controls as baseline +4. Convert feasible Source L3 controls into enforced baseline requirements 5. Update this policy to reflect the new achievable level ## References From ea6c80fcc0b6637ce8ace0bdc068d3a78c9d4912 Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 05:54:55 +0900 Subject: [PATCH 6/8] docs(security): split artifact attestation guide Move release provenance, SBOM attestation, linked artifacts, and verification guidance into a dedicated security companion document. Leave workflow hardening focused on GitHub Actions permissions, runner security, action pinning, and OIDC configuration. Signed-off-by: Yunseo Kim --- docs/security/artifact-attestations.md | 366 +++++++++++++++++++++++++ docs/security/workflow-hardening.md | 353 +----------------------- 2 files changed, 369 insertions(+), 350 deletions(-) create mode 100644 docs/security/artifact-attestations.md diff --git a/docs/security/artifact-attestations.md b/docs/security/artifact-attestations.md new file mode 100644 index 0000000..165f558 --- /dev/null +++ b/docs/security/artifact-attestations.md @@ -0,0 +1,366 @@ +# Artifact Attestations + +> [!NOTE] +> This page is part of the Windlass organization security policy. Start with [SECURITY.md](../../SECURITY.md). + +All released artifacts that consumers run, install, deploy, or download must include cryptographically signed artifact attestations. Attestations establish provenance and integrity by linking the artifact to the repository, workflow, commit SHA, triggering event, build environment, and OIDC identity that produced it. + +Do not attest every test-only build or individual source/documentation files. Attest release binaries, packages, container images, and manifests that identify released contents by digest. + +## Required Permissions + +Workflows generating attestations require these permissions: + +```yaml +permissions: + id-token: write # Required for OIDC token to request signing certificate + attestations: write # Required to persist the attestation + contents: read # Required to read source code +``` + +Container image release jobs also require `packages: write` when pushing to GHCR or another registry. Jobs that should appear on the organization's linked artifacts page must also include `artifact-metadata: write`. + +Artifact attestations are available for public repositories on current GitHub plans. Private or internal repositories require GitHub Enterprise Cloud. GitHub Enterprise Server does not support artifact attestations. + +## Build Provenance Attestations + +The organization default is to produce SLSA Build L3+ provenance wherever feasible. Choose the provenance path in this order: + +1. **SLSA GitHub Generator builder** — Use when a hosted builder can both build the artifact and generate provenance for the project's ecosystem. +2. **SLSA GitHub Generator generator** — Use when the release workflow already builds the artifact and only needs SLSA provenance generation for an existing file or container image. +3. **Reusable workflow with `actions/attest`** — Use when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. +4. **Direct `actions/attest` in the release workflow** — Use only as the baseline provenance path when Build L3+ is not yet feasible. + +### SLSA GitHub Generator + +The [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) project provides both builders and generators. Builders perform the build and generate provenance together. Generators only generate provenance for artifacts that were already produced by the repository's release workflow. Prefer a builder when it fits the project ecosystem; use a generator when the build flow is too custom for a hosted builder or the artifact already exists. + +Available builders and generators: + +| Kind | Target | Workflow | What it does | Status | +| :------------ | :--------------------------------- | :----------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :----- | +| **Builder** | Go projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml` | Builds and generates provenance | Stable | +| **Builder** | Node.js/npm packages | `slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml` | Builds and generates provenance | Beta | +| **Builder** | Maven packages | `slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml` | Builds and generates provenance | Beta | +| **Builder** | Gradle projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_gradle_slsa3.yml` | Builds and generates provenance | Beta | +| **Builder** | Bazel projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_bazel_slsa3.yml` | Builds and generates provenance | WIP | +| **Builder** | Artifacts built inside a container | `slsa-framework/slsa-github-generator/.github/workflows/builder_container-based_slsa3.yml` | Runs a configured container build and generates provenance | Beta | +| **Generator** | Existing file artifacts | `slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml` | Generates provenance for arbitrary file-based artifacts, for any ecosystem and programming language | Stable | +| **Generator** | Existing container images | `slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml` | Generate provenance for container images | Stable | + +> [!IMPORTANT] +> SLSA builders and generators must be referenced by tag (e.g., `@v2.1.0`) for `slsa-verifier` to validate the trusted reusable workflow. This is an intentional exception to the SHA-pinning requirement. + +```yaml +jobs: + build: + uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@v2.1.0 + with: + go-version: "1.26" + # ... other inputs +``` + +### Reusable Workflow Attestation + +Use this path when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. This follows GitHub's artifact-attestation path for SLSA Build L3 by isolating the build instructions in a reusable workflow and verifying the expected signer workflow. + +Generate the artifact and the `actions/attest` provenance inside the reusable workflow. Both the caller and reusable workflow must grant `contents: read`, `id-token: write`, and `attestations: write`; container builds also need `packages: write`. Verification policy must use `--signer-workflow`, and `--signer-repo` when the reusable workflow lives in another repository. + +### Direct `actions/attest` Baseline + +Use direct `actions/attest` only when Build L3+ is not yet feasible. It still creates signed GitHub artifact attestations and satisfies the release provenance requirement, but it should not be described as the repository's SLSA Build L3+ implementation by itself. + +Direct baseline example: + +```yaml +- name: Generate artifact attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: "${{ github.workspace }}/my-artifact" +``` + +For container images, attest the image by digest and push the attestation to the registry: + +```yaml +- name: Generate container attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + push-to-registry: true +``` + +The `subject-name` must be the fully qualified image name without a tag, and `subject-digest` must be the immutable `sha256:...` digest from the image build/push step. `push-to-registry: true` is required when the attestation should upload registry storage metadata to the linked artifacts page, and `actions/attest` supports that option only with `subject-name` plus `subject-digest`. + +## SBOM Attestations + +Released binaries and container images must also have SBOM attestations when the build can produce them. Prefer generating both SPDX and CycloneDX SBOMs because downstream consumers and scanners do not all accept the same format. Generate each SBOM during the release workflow, then run one `actions/attest` step per SBOM file with `sbom-path`. + +`actions/attest` accepts a single JSON-formatted SPDX or CycloneDX SBOM file per attestation. Each SBOM file must be 16 MB or smaller and cannot be combined with custom `predicate-type`, `predicate`, or `predicate-path` inputs in the same step. + +This policy requires released artifacts to include provenance and SBOM attestations. `anchore/sbom-action` is only the example SBOM generator used in this document. Projects may use another SBOM generation tool if it produces valid SPDX or CycloneDX JSON for `actions/attest` or an equivalent attestation workflow. + +When a project uses a different SBOM generator, configure workflow permissions and tool-specific settings according to that tool's requirements. The permission examples below apply to `anchore/sbom-action`; other tools may need different read, write, registry, or release permissions. + +For public releases, generate local SBOM files for attestation and publish the same SBOM files as release assets whenever possible. Attestation provides cryptographic binding to the released artifact. Release assets make the SBOMs easy to download for auditors, license review, offline storage, and third-party scanners. Release asset uploads do not create linked artifacts storage records by themselves. + +### SBOM Permissions by Purpose + +Use the narrowest permissions that match the release job's behavior: + +| Purpose | Required permissions | Notes | +| :----------------------------------------- | :---------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | +| Local SBOM generation for attestation only | `contents: read`, plus `id-token: write` and `attestations: write` for attest | Set `upload-artifact: false` and `upload-release-assets: false` on `anchore/sbom-action`. | +| Workflow artifact upload | `contents: write` | Required by `anchore/sbom-action` when it uploads generated SBOMs as workflow artifacts. | +| Release asset upload | `actions: read`, `contents: write` | Needed so Anchore can read workflow artifacts and write release assets. Grant only on release jobs. | +| Release asset upload plus attestation | `actions: read`, `contents: write`, `id-token: write`, `attestations: write` | Add `packages: write` for container registry pushes and `artifact-metadata: write` for linked records. | + +`anchore/sbom-action` defaults to `upload-artifact: true` and `upload-release-assets: true`. If the SBOM is only an intermediate file for `actions/attest`, disable both upload behaviors explicitly. If the workflow is creating a GitHub Release, leave release publishing enabled and grant `actions: read` plus `contents: write` at the job level. + +Binary example: + +```yaml +- name: Generate SPDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: spdx-json + output-file: sbom.spdx.json + upload-artifact: false + upload-release-assets: false + +- name: Generate CycloneDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: cyclonedx-json + output-file: sbom.cyclonedx.json + upload-artifact: false + upload-release-assets: false + +- name: Generate SPDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.spdx.json + +- name: Generate CycloneDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.cyclonedx.json +``` + +Release asset publishing example: + +```yaml +permissions: + actions: read # Required to read workflow artifacts for release publishing + contents: write # Required to write SBOM files to the GitHub Release + id-token: write # Required for attestation signing + attestations: write # Required to persist SBOM attestations + artifact-metadata: write # Required for linked artifact storage records + +steps: + - name: Generate and publish SPDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: spdx-json + output-file: sbom.spdx.json + artifact-name: sbom.spdx.json + upload-artifact: true + upload-release-assets: true + + - name: Generate and publish CycloneDX SBOM + uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 + with: + path: ./dist/my-artifact + format: cyclonedx-json + output-file: sbom.cyclonedx.json + artifact-name: sbom.cyclonedx.json + upload-artifact: true + upload-release-assets: true + + - name: Generate SPDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.spdx.json + + - name: Generate CycloneDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-path: ./dist/my-artifact + sbom-path: sbom.cyclonedx.json +``` + +Container image example: + +```yaml +- name: Generate SPDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + sbom-path: sbom.spdx.json + push-to-registry: true + +- name: Generate CycloneDX SBOM attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + sbom-path: sbom.cyclonedx.json + push-to-registry: true +``` + +SBOM attestations do not replace vulnerability scanning. They provide signed dependency metadata that consumers and auditors can verify alongside build provenance. + +## Linked Artifacts Page Uploads + +For container images and other registry-published release artifacts, workflows should upload storage metadata to the organization's linked artifacts page so security and compliance reviewers can trace artifacts to their source repository, build run, storage location, attestations, and deployment context. + +The `actions/attest` action automatically creates a linked artifacts storage record when both conditions are true: + +- `push-to-registry: true` is set on the attestation step +- The job has `artifact-metadata: write` + +For `actions/attest`, `push-to-registry: true` requires `subject-name` and `subject-digest`. Use it for container images and other registry artifacts that have a fully qualified registry name and immutable digest. Do not add `push-to-registry: true` to file-path attestations that use `subject-path`; those attestations are still valid, but they do not create linked artifacts storage records through `actions/attest`. + +Storage record creation is enabled by default when `push-to-registry: true` is set. Set `create-storage-record: false` only when the artifact must not appear on the linked artifacts page. Storage records can be created only for artifacts built from organization-owned repositories. + +For non-registry release assets that still need linked artifacts metadata, use the artifact metadata REST API or an approved integration instead of forcing `push-to-registry` into a file-path attestation. + +Recommended container release pattern: + +```yaml +permissions: + contents: read + id-token: write + attestations: write + packages: write + artifact-metadata: write + +steps: + - name: Build and push image + id: build + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + + - name: Generate artifact attestation + uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 + with: + subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + subject-digest: "${{ steps.build.outputs.digest }}" + push-to-registry: true +``` + +If an artifact is not attested, or if deployment/runtime records must be uploaded, use the artifact metadata REST API or an approved integration such as JFrog Artifactory, Dynatrace, or Microsoft Defender for Cloud. Linked artifacts records store metadata only; they do not store artifact files. + +## Attestation Modes + +| Mode | Input | Description | +| :----------------------- | :----------------------------- | :------------------------------------------- | +| **Provenance** (default) | `subject-path` only | Auto-generates SLSA build provenance | +| **SBOM** | `sbom-path` provided | Creates attestation from SPDX/CycloneDX SBOM | +| **Custom** | `predicate-type` + `predicate` | User-defined predicate | + +## Verification Expectations + +Consumers verify build provenance with `gh attestation verify`. For reusable workflow builders, verification policy should pin the expected signing workflow with `--signer-workflow`, and use `--signer-repo` when the reusable workflow lives in a separate repository. + +Verification confirms: + +1. **Authenticity** — The artifact was built by the claimed repository +2. **Integrity** — The artifact has not been tampered with since build +3. **Provenance** — The artifact's build process is documented +4. **Source** — The exact source code revision used to build the artifact is known +5. **Build environment** — The workflow that produced the artifact is identified + +### Install Verification Tools + +```bash +# macOS +brew install gh + +# Ubuntu/Debian +sudo apt install gh + +# SLSA verifier for slsa-github-generator provenance +go install github.com/slsa-framework/slsa-verifier/cli/slsa-verifier@v2.0.0 +``` + +### Verify Binary Attestations + +```bash +# Verify a downloaded binary +gh attestation verify ./my-artifact -R windlasstech/my-repo + +# Verify with a specific workflow +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --signer-workflow windlasstech/my-repo/.github/workflows/release.yml +``` + +### Verify Container Image Attestations + +```bash +# Verify a container image +gh attestation verify oci://ghcr.io/windlasstech/my-image:latest \ + -R windlasstech/my-repo + +# Verify by digest (recommended) +gh attestation verify oci://ghcr.io/windlasstech/my-image@sha256:abc123... \ + -R windlasstech/my-repo +``` + +### Verify SBOM Attestations + +SBOM attestations must be verified with the SBOM predicate type, such as `https://spdx.dev/Document/v2.3` for SPDX SBOMs. Verify each published SBOM format separately: + +```bash +# SPDX +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --predicate-type https://spdx.dev/Document/v2.3 + +# CycloneDX +gh attestation verify ./my-artifact \ + -R windlasstech/my-repo \ + --predicate-type https://cyclonedx.org/bom +``` + +### Verify SLSA Provenance + +For artifacts with SLSA provenance generated by slsa-github-generator: + +```bash +slsa-verifier verify-artifact my-artifact \ + --provenance-path my-artifact.intoto.jsonl \ + --source-uri github.com/windlasstech/my-repo \ + --source-tag v1.0.0 +``` + +## References + +### GitHub Security + +- [GitHub Artifact Attestations](https://docs.github.com/en/actions/concepts/security/artifact-attestations) +- [Using artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations) +- [Using artifact attestations and reusable workflows to achieve SLSA v1 Build Level 3](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/increase-security-rating) +- [Enhance build security and reach SLSA Level 3 with GitHub Artifact Attestations](https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/) +- [GitHub Linked Artifacts](https://docs.github.com/en/code-security/concepts/supply-chain-security/linked-artifacts) +- [Uploading storage and deployment data to the linked artifacts page](https://docs.github.com/en/code-security/how-tos/secure-your-supply-chain/establish-provenance-and-integrity/upload-linked-artifacts) +- [GitHub Reusable Workflows](https://docs.github.com/en/actions/sharing-automations/reusing-workflows) +- [actions/attest](https://github.com/actions/attest) + +### SLSA + +- [SLSA GitHub Generator](https://github.com/slsa-framework/slsa-github-generator) +- [SLSA verifier](https://github.com/slsa-framework/slsa-verifier) diff --git a/docs/security/workflow-hardening.md b/docs/security/workflow-hardening.md index 02d1661..abd29e1 100644 --- a/docs/security/workflow-hardening.md +++ b/docs/security/workflow-hardening.md @@ -120,364 +120,17 @@ jobs: run: aws s3 sync ./dist s3://my-bucket/ ``` -## Artifact Attestations +## Release Artifact Integrity -All released artifacts that consumers run, install, deploy, or download must include cryptographically signed artifact attestations. Attestations establish provenance and integrity by linking the artifact to the repository, workflow, commit SHA, triggering event, build environment, and OIDC identity that produced it. +Release artifact provenance, SBOM attestations, linked artifacts uploads, and consumer verification commands are documented in [Artifact Attestations](./artifact-attestations.md). -Do not attest every test-only build or individual source/documentation files. Attest release binaries, packages, container images, and manifests that identify released contents by digest. - -### Required Permissions - -Workflows generating attestations require these permissions: - -```yaml -permissions: - id-token: write # Required for OIDC token to request signing certificate - attestations: write # Required to persist the attestation - contents: read # Required to read source code -``` - -Container image release jobs also require `packages: write` when pushing to GHCR or another registry. Jobs that should appear on the organization's linked artifacts page must also include `artifact-metadata: write`. - -Artifact attestations are available for public repositories on current GitHub plans. Private or internal repositories require GitHub Enterprise Cloud. GitHub Enterprise Server does not support artifact attestations. - -### Build Provenance Attestations - -The organization default is to produce SLSA Build L3+ provenance wherever feasible. Choose the provenance path in this order: - -1. **SLSA GitHub Generator builder** — Use when a hosted builder can both build the artifact and generate provenance for the project's ecosystem. -2. **SLSA GitHub Generator generator** — Use when the release workflow already builds the artifact and only needs SLSA provenance generation for an existing file or container image. -3. **Reusable workflow with `actions/attest`** — Use when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. -4. **Direct `actions/attest` in the release workflow** — Use only as the baseline provenance path when Build L3+ is not yet feasible. - -#### SLSA GitHub Generator - -The [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) project provides both builders and generators. Builders perform the build and generate provenance together. Generators only generate provenance for artifacts that were already produced by the repository's release workflow. Prefer a builder when it fits the project ecosystem; use a generator when the build flow is too custom for a hosted builder or the artifact already exists. - -Available builders and generators: - -| Kind | Target | Workflow | What it does | Status | -| :------------ | :--------------------------------- | :----------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- | :----- | -| **Builder** | Go projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml` | Builds and generates provenance | Stable | -| **Builder** | Node.js/npm packages | `slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml` | Builds and generates provenance | Beta | -| **Builder** | Maven packages | `slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml` | Builds and generates provenance | Beta | -| **Builder** | Gradle projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_gradle_slsa3.yml` | Builds and generates provenance | Beta | -| **Builder** | Bazel projects | `slsa-framework/slsa-github-generator/.github/workflows/builder_bazel_slsa3.yml` | Builds and generates provenance | WIP | -| **Builder** | Artifacts built inside a container | `slsa-framework/slsa-github-generator/.github/workflows/builder_container-based_slsa3.yml` | Runs a configured container build and generates provenance | Beta | -| **Generator** | Existing file artifacts | `slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml` | Generates provenance for arbitrary file-based artifacts, for any ecosystem and programming language | Stable | -| **Generator** | Existing container images | `slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml` | Generate provenance for container images | Stable | - -> [!IMPORTANT] -> SLSA builders and generators must be referenced by tag (e.g., `@v2.1.0`) for `slsa-verifier` to validate the trusted reusable workflow. This is an intentional exception to the SHA-pinning requirement. - -```yaml -jobs: - build: - uses: slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@v2.1.0 - with: - go-version: "1.26" - # ... other inputs -``` - -#### Reusable Workflow Attestation - -Use this path when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. This follows GitHub's artifact-attestation path for SLSA Build L3 by isolating the build instructions in a reusable workflow and verifying the expected signer workflow. - -Generate the artifact and the `actions/attest` provenance inside the reusable workflow. Both the caller and reusable workflow must grant `contents: read`, `id-token: write`, and `attestations: write`; container builds also need `packages: write`. Verification policy must use `--signer-workflow`, and `--signer-repo` when the reusable workflow lives in another repository. - -#### Direct `actions/attest` Baseline - -Use direct `actions/attest` only when Build L3+ is not yet feasible. It still creates signed GitHub artifact attestations and satisfies the release provenance requirement, but it should not be described as the repository's SLSA Build L3+ implementation by itself. - -Direct baseline example: - -```yaml -- name: Generate artifact attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-path: "${{ github.workspace }}/my-artifact" -``` - -For container images, attest the image by digest and push the attestation to the registry: - -```yaml -- name: Generate container attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" - subject-digest: "${{ steps.build.outputs.digest }}" - push-to-registry: true -``` - -The `subject-name` must be the fully qualified image name without a tag, and `subject-digest` must be the immutable `sha256:...` digest from the image build/push step. `push-to-registry: true` is required when the attestation should upload registry storage metadata to the linked artifacts page, and `actions/attest` supports that option only with `subject-name` plus `subject-digest`. - -### SBOM Attestations - -Released binaries and container images must also have SBOM attestations when the build can produce them. Prefer generating both SPDX and CycloneDX SBOMs because downstream consumers and scanners do not all accept the same format. Generate each SBOM during the release workflow, then run one `actions/attest` step per SBOM file with `sbom-path`. - -`actions/attest` accepts a single JSON-formatted SPDX or CycloneDX SBOM file per attestation. Each SBOM file must be 16 MB or smaller and cannot be combined with custom `predicate-type`, `predicate`, or `predicate-path` inputs in the same step. - -This policy requires released artifacts to include provenance and SBOM attestations. `anchore/sbom-action` is only the example SBOM generator used in this document. Projects may use another SBOM generation tool if it produces valid SPDX or CycloneDX JSON for `actions/attest` or an equivalent attestation workflow. - -When a project uses a different SBOM generator, configure workflow permissions and tool-specific settings according to that tool's requirements. The permission examples below apply to `anchore/sbom-action`; other tools may need different read, write, registry, or release permissions. - -For public releases, generate local SBOM files for attestation and publish the same SBOM files as release assets whenever possible. Attestation provides cryptographic binding to the released artifact. Release assets make the SBOMs easy to download for auditors, license review, offline storage, and third-party scanners. Release asset uploads do not create linked artifacts storage records by themselves. - -#### SBOM Permissions by Purpose - -Use the narrowest permissions that match the release job's behavior: - -| Purpose | Required permissions | Notes | -| :----------------------------------------- | :---------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | -| Local SBOM generation for attestation only | `contents: read`, plus `id-token: write` and `attestations: write` for attest | Set `upload-artifact: false` and `upload-release-assets: false` on `anchore/sbom-action`. | -| Workflow artifact upload | `contents: write` | Required by `anchore/sbom-action` when it uploads generated SBOMs as workflow artifacts. | -| Release asset upload | `actions: read`, `contents: write` | Needed so Anchore can read workflow artifacts and write release assets. Grant only on release jobs. | -| Release asset upload plus attestation | `actions: read`, `contents: write`, `id-token: write`, `attestations: write` | Add `packages: write` for container registry pushes and `artifact-metadata: write` for linked records. | - -`anchore/sbom-action` defaults to `upload-artifact: true` and `upload-release-assets: true`. If the SBOM is only an intermediate file for `actions/attest`, disable both upload behaviors explicitly. If the workflow is creating a GitHub Release, leave release publishing enabled and grant `actions: read` plus `contents: write` at the job level. - -Binary example: - -```yaml -- name: Generate SPDX SBOM - uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 - with: - path: ./dist/my-artifact - format: spdx-json - output-file: sbom.spdx.json - upload-artifact: false - upload-release-assets: false - -- name: Generate CycloneDX SBOM - uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 - with: - path: ./dist/my-artifact - format: cyclonedx-json - output-file: sbom.cyclonedx.json - upload-artifact: false - upload-release-assets: false - -- name: Generate SPDX SBOM attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-path: ./dist/my-artifact - sbom-path: sbom.spdx.json - -- name: Generate CycloneDX SBOM attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-path: ./dist/my-artifact - sbom-path: sbom.cyclonedx.json -``` - -Release asset publishing example: - -```yaml -permissions: - actions: read # Required to read workflow artifacts for release publishing - contents: write # Required to write SBOM files to the GitHub Release - id-token: write # Required for attestation signing - attestations: write # Required to persist SBOM attestations - artifact-metadata: write # Required for linked artifact storage records - -steps: - - name: Generate and publish SPDX SBOM - uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 - with: - path: ./dist/my-artifact - format: spdx-json - output-file: sbom.spdx.json - artifact-name: sbom.spdx.json - upload-artifact: true - upload-release-assets: true - - - name: Generate and publish CycloneDX SBOM - uses: anchore/sbom-action@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6 - with: - path: ./dist/my-artifact - format: cyclonedx-json - output-file: sbom.cyclonedx.json - artifact-name: sbom.cyclonedx.json - upload-artifact: true - upload-release-assets: true - - - name: Generate SPDX SBOM attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-path: ./dist/my-artifact - sbom-path: sbom.spdx.json - - - name: Generate CycloneDX SBOM attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-path: ./dist/my-artifact - sbom-path: sbom.cyclonedx.json -``` - -Container image example: - -```yaml -- name: Generate SPDX SBOM attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" - subject-digest: "${{ steps.build.outputs.digest }}" - sbom-path: sbom.spdx.json - push-to-registry: true - -- name: Generate CycloneDX SBOM attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" - subject-digest: "${{ steps.build.outputs.digest }}" - sbom-path: sbom.cyclonedx.json - push-to-registry: true -``` - -SBOM attestations do not replace vulnerability scanning. They provide signed dependency metadata that consumers and auditors can verify alongside build provenance. - -### Linked Artifacts Page Uploads - -For container images and other registry-published release artifacts, workflows should upload storage metadata to the organization's linked artifacts page so security and compliance reviewers can trace artifacts to their source repository, build run, storage location, attestations, and deployment context. - -The `actions/attest` action automatically creates a linked artifacts storage record when both conditions are true: - -- `push-to-registry: true` is set on the attestation step -- The job has `artifact-metadata: write` - -For `actions/attest`, `push-to-registry: true` requires `subject-name` and `subject-digest`. Use it for container images and other registry artifacts that have a fully qualified registry name and immutable digest. Do not add `push-to-registry: true` to file-path attestations that use `subject-path`; those attestations are still valid, but they do not create linked artifacts storage records through `actions/attest`. - -Storage record creation is enabled by default when `push-to-registry: true` is set. Set `create-storage-record: false` only when the artifact must not appear on the linked artifacts page. Storage records can be created only for artifacts built from organization-owned repositories. - -For non-registry release assets that still need linked artifacts metadata, use the artifact metadata REST API or an approved integration instead of forcing `push-to-registry` into a file-path attestation. - -Recommended container release pattern: - -```yaml -permissions: - contents: read - id-token: write - attestations: write - packages: write - artifact-metadata: write - -steps: - - name: Build and push image - id: build - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 - with: - context: . - push: true - tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} - - - name: Generate artifact attestation - uses: actions/attest@61d634515b50b54366a3498d04742794e07fc381 # v4.1.0 - with: - subject-name: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" - subject-digest: "${{ steps.build.outputs.digest }}" - push-to-registry: true -``` - -If an artifact is not attested, or if deployment/runtime records must be uploaded, use the artifact metadata REST API or an approved integration such as JFrog Artifactory, Dynatrace, or Microsoft Defender for Cloud. Linked artifacts records store metadata only; they do not store artifact files. - -### Attestation Modes - -| Mode | Input | Description | -| :----------------------- | :----------------------------- | :------------------------------------------- | -| **Provenance** (default) | `subject-path` only | Auto-generates SLSA build provenance | -| **SBOM** | `sbom-path` provided | Creates attestation from SPDX/CycloneDX SBOM | -| **Custom** | `predicate-type` + `predicate` | User-defined predicate | - -### Verification Expectations - -Consumers verify build provenance with `gh attestation verify`. For reusable workflow builders, verification policy should pin the expected signing workflow with `--signer-workflow`, and use `--signer-repo` when the reusable workflow lives in a separate repository. - -Verification confirms: - -1. **Authenticity** — The artifact was built by the claimed repository -2. **Integrity** — The artifact has not been tampered with since build -3. **Provenance** — The artifact's build process is documented -4. **Source** — The exact source code revision used to build the artifact is known -5. **Build environment** — The workflow that produced the artifact is identified - -#### Install Verification Tools - -```bash -# macOS -brew install gh - -# Ubuntu/Debian -sudo apt install gh - -# SLSA verifier for slsa-github-generator provenance -go install github.com/slsa-framework/slsa-verifier/cli/slsa-verifier@v2.0.0 -``` - -#### Verify Binary Attestations - -```bash -# Verify a downloaded binary -gh attestation verify ./my-artifact -R windlasstech/my-repo - -# Verify with a specific workflow -gh attestation verify ./my-artifact \ - -R windlasstech/my-repo \ - --signer-workflow windlasstech/my-repo/.github/workflows/release.yml -``` - -#### Verify Container Image Attestations - -```bash -# Verify a container image -gh attestation verify oci://ghcr.io/windlasstech/my-image:latest \ - -R windlasstech/my-repo - -# Verify by digest (recommended) -gh attestation verify oci://ghcr.io/windlasstech/my-image@sha256:abc123... \ - -R windlasstech/my-repo -``` - -#### Verify SBOM Attestations - -SBOM attestations must be verified with the SBOM predicate type, such as `https://spdx.dev/Document/v2.3` for SPDX SBOMs. Verify each published SBOM format separately: - -```bash -# SPDX -gh attestation verify ./my-artifact \ - -R windlasstech/my-repo \ - --predicate-type https://spdx.dev/Document/v2.3 - -# CycloneDX -gh attestation verify ./my-artifact \ - -R windlasstech/my-repo \ - --predicate-type https://cyclonedx.org/bom -``` - -#### Verify SLSA Provenance - -For artifacts with SLSA provenance generated by slsa-github-generator: - -```bash -slsa-verifier verify-artifact my-artifact \ - --provenance-path my-artifact.intoto.jsonl \ - --source-uri github.com/windlasstech/my-repo \ - --source-tag v1.0.0 -``` +Use this workflow hardening guide for GitHub Actions permissions, SHA-pinning, runner security, and OIDC configuration. Use the artifact attestation guide for release artifact signing and verification requirements. ## References ### GitHub Security -- [GitHub Artifact Attestations](https://docs.github.com/en/actions/concepts/security/artifact-attestations) -- [Using artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations) -- [Using artifact attestations and reusable workflows to achieve SLSA v1 Build Level 3](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/increase-security-rating) -- [Enhance build security and reach SLSA Level 3 with GitHub Artifact Attestations](https://github.blog/enterprise-software/devsecops/enhance-build-security-and-reach-slsa-level-3-with-github-artifact-attestations/) -- [GitHub Linked Artifacts](https://docs.github.com/en/code-security/concepts/supply-chain-security/linked-artifacts) -- [Uploading storage and deployment data to the linked artifacts page](https://docs.github.com/en/code-security/how-tos/secure-your-supply-chain/establish-provenance-and-integrity/upload-linked-artifacts) - [GitHub Reusable Workflows](https://docs.github.com/en/actions/sharing-automations/reusing-workflows) -- [actions/attest](https://github.com/actions/attest) - [GitHub Actions Security Hardening](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions) - [OIDC in GitHub Actions](https://docs.github.com/en/actions/security-guides/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers) From 1b797713d7a880b93f4d77cf892f2e6443b03708 Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 05:55:07 +0900 Subject: [PATCH 7/8] docs(security): link artifact attestation guide Add the artifact attestation guide to the security policy companion document list and point release integrity guidance at it. Connect the SLSA Build L3 implementation notes and mitigation table to the new canonical attestation guide. Signed-off-by: Yunseo Kim --- SECURITY.md | 8 +++++--- docs/security/slsa-compliance-framework.md | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index b6ca569..1f04763 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -122,6 +122,7 @@ This organization follows the [SLSA (Supply-chain Levels for Software Artifacts) | :------------------------ | :----------------------------------------------------------------------------------------- | | SLSA compliance framework | [docs/security/slsa-compliance-framework.md](./docs/security/slsa-compliance-framework.md) | | Workflow hardening | [docs/security/workflow-hardening.md](./docs/security/workflow-hardening.md) | +| Artifact attestations | [docs/security/artifact-attestations.md](./docs/security/artifact-attestations.md) | | Dependency security | [docs/security/dependency-security.md](./docs/security/dependency-security.md) | ### Source and Workflow Integrity @@ -142,7 +143,7 @@ Source and workflow controls are implemented through signed commits, protected b - **SBOM attestations and release assets** — Released binaries and container images must include signed SPDX and CycloneDX SBOM attestations when the build can generate them, and public releases should publish the same SBOM files as release assets - **Linked artifacts metadata** — Registry-published release artifacts should upload storage metadata to GitHub's linked artifacts page through `actions/attest` or the artifact metadata API -Workflow implementation requirements for provenance, SBOM attestations, and linked artifacts uploads are documented in [Workflow Hardening: Artifact Attestations](./docs/security/workflow-hardening.md#artifact-attestations). +Implementation requirements for provenance, SBOM attestations, linked artifacts uploads, and release verification are documented in [Artifact Attestations](./docs/security/artifact-attestations.md). ## Verifying Artifacts @@ -156,12 +157,13 @@ Verification confirms: 4. **Source** — The exact source code revision used to build the artifact is known 5. **Build environment** — The workflow that produced the artifact is identified -Detailed verification commands for binaries, container images, SBOM attestations, and SLSA provenance are documented in [Workflow Hardening: Verification Expectations](./docs/security/workflow-hardening.md#verification-expectations). +Detailed verification commands for binaries, container images, SBOM attestations, and SLSA provenance are documented in [Artifact Attestations: Verification Expectations](./docs/security/artifact-attestations.md#verification-expectations). ## References Detailed reference lists for each topic are available in the companion documents: - [SLSA Framework references](./docs/security/slsa-compliance-framework.md#references) -- [GitHub Security and Step Security references](./docs/security/workflow-hardening.md#references) +- [GitHub Actions and Step Security references](./docs/security/workflow-hardening.md#references) +- [Artifact attestation references](./docs/security/artifact-attestations.md#references) - [OSV Scanner and Additional Resources](./docs/security/dependency-security.md#references) diff --git a/docs/security/slsa-compliance-framework.md b/docs/security/slsa-compliance-framework.md index 9b9ebf6..42b781e 100644 --- a/docs/security/slsa-compliance-framework.md +++ b/docs/security/slsa-compliance-framework.md @@ -94,6 +94,7 @@ Implementation for this organization: - Use reusable workflow based artifact attestations when a supported SLSA builder is not a good fit - Use direct `actions/attest` provenance only as the baseline path when Build L3+ isolation is not yet feasible - Document the verification command and expected signer workflow for each release-producing repository +- Follow the implementation guide in [Artifact Attestations](./artifact-attestations.md) ## SLSA Source Track Requirements @@ -220,7 +221,7 @@ While two-party review is not possible with one person, the following compensati | **Automated security scanning** | Detect malicious patterns | CodeQL, Semgrep, or similar tools scanning for suspicious code | | **Immutable audit trail** | Enable post-hoc investigation | Signed commits + GitHub audit logs provide tamper-evident history | | **External monitoring** | Detect unauthorized changes | OpenSSF Scorecard monitors branch protection and signed commits | -| **Artifact attestations** | Verify build integrity | All releases include signed SLSA Build provenance | +| **Artifact attestations** | Verify build integrity | All releases follow [artifact attestation requirements](./artifact-attestations.md) | If the organization grows to multiple trusted contributors, the following steps enable Source L4: From a70cea61c84c93211947156941cc0837481e522b Mon Sep 17 00:00:00 2001 From: Yunseo Kim Date: Sun, 14 Jun 2026 06:16:06 +0900 Subject: [PATCH 8/8] docs(security): emphasize generic provenance generator Point custom release workflows toward the SLSA GitHub Generator generic generator README before adapting provenance examples. Clarify that the generic generator is the common fit for bespoke build and release jobs. Signed-off-by: Yunseo Kim --- docs/security/artifact-attestations.md | 59 +++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/docs/security/artifact-attestations.md b/docs/security/artifact-attestations.md index 165f558..0d4ccb9 100644 --- a/docs/security/artifact-attestations.md +++ b/docs/security/artifact-attestations.md @@ -9,7 +9,7 @@ Do not attest every test-only build or individual source/documentation files. At ## Required Permissions -Workflows generating attestations require these permissions: +Workflows generating GitHub artifact attestations with `actions/attest` require these permissions: ```yaml permissions: @@ -18,7 +18,7 @@ permissions: contents: read # Required to read source code ``` -Container image release jobs also require `packages: write` when pushing to GHCR or another registry. Jobs that should appear on the organization's linked artifacts page must also include `artifact-metadata: write`. +SLSA GitHub Generator jobs use a reusable workflow instead of `actions/attest`. Generic generator jobs require `actions: read`, `id-token: write`, and `contents: write` when uploading provenance to a GitHub Release. Container image release jobs also require `packages: write` when pushing to GHCR or another registry. Jobs that should appear on the organization's linked artifacts page must also include `artifact-metadata: write`. Artifact attestations are available for public repositories on current GitHub plans. Private or internal repositories require GitHub Enterprise Cloud. GitHub Enterprise Server does not support artifact attestations. @@ -27,13 +27,13 @@ Artifact attestations are available for public repositories on current GitHub pl The organization default is to produce SLSA Build L3+ provenance wherever feasible. Choose the provenance path in this order: 1. **SLSA GitHub Generator builder** — Use when a hosted builder can both build the artifact and generate provenance for the project's ecosystem. -2. **SLSA GitHub Generator generator** — Use when the release workflow already builds the artifact and only needs SLSA provenance generation for an existing file or container image. +2. **SLSA GitHub Generator generator** — Use when the release workflow already builds the artifact and only needs SLSA provenance generation for an existing file or container image. For most custom release workflows, start with the [generic generator README](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md). 3. **Reusable workflow with `actions/attest`** — Use when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. 4. **Direct `actions/attest` in the release workflow** — Use only as the baseline provenance path when Build L3+ is not yet feasible. ### SLSA GitHub Generator -The [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) project provides both builders and generators. Builders perform the build and generate provenance together. Generators only generate provenance for artifacts that were already produced by the repository's release workflow. Prefer a builder when it fits the project ecosystem; use a generator when the build flow is too custom for a hosted builder or the artifact already exists. +The [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) project provides both builders and generators. Builders perform the build and generate provenance together. Generators only generate provenance for artifacts that were already produced by the repository's release workflow. Prefer a builder when it fits the project ecosystem; use a generator when the build flow is too custom for a hosted builder or the artifact already exists. In practice, the [generic generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md) is the most likely fit for repositories that already have bespoke build and release jobs. Available builders and generators: @@ -51,6 +51,8 @@ Available builders and generators: > [!IMPORTANT] > SLSA builders and generators must be referenced by tag (e.g., `@v2.1.0`) for `slsa-verifier` to validate the trusted reusable workflow. This is an intentional exception to the SHA-pinning requirement. +Builder example: + ```yaml jobs: build: @@ -60,6 +62,48 @@ jobs: # ... other inputs ``` +Generic generator example for existing file artifacts: + +Before adapting this pattern, read the [SLSA GitHub Generator generic generator README](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md) for the latest supported triggers, inputs, outputs, private repository caveats, and `base64-subjects-as-file` guidance. + +```yaml +jobs: + build: + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + runs-on: ubuntu-latest + steps: + - name: Build artifacts + run: | + ./scripts/build-release.sh + + - name: Generate hashes + id: hash + shell: bash + run: | + echo "hashes=$(sha256sum dist/my-artifact | base64 -w0)" >> "$GITHUB_OUTPUT" + + - name: Upload release artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: my-artifact + path: dist/my-artifact + if-no-files-found: error + + provenance: + needs: [build] + permissions: + actions: read # Required to detect the GitHub Actions environment + id-token: write # Required to sign provenance + contents: write # Required when upload-assets publishes provenance to a release + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 + with: + base64-subjects: "${{ needs.build.outputs.hashes }}" + upload-assets: true +``` + +The generic generator expects `base64-subjects` to decode to `sha256sum`-formatted lines, such as `SHA256 artifact-name`. For many artifacts or runner masking issues, follow the [generic generator README](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md) and write the checksums to a file, then pass it with `base64-subjects-as-file` using the SLSA helper action. + ### Reusable Workflow Attestation Use this path when a dedicated SLSA builder or generator is not a good fit, but the build can be moved into a trusted reusable workflow. This follows GitHub's artifact-attestation path for SLSA Build L3 by isolating the build instructions in a reusable workflow and verifying the expected signer workflow. @@ -263,11 +307,13 @@ steps: If an artifact is not attested, or if deployment/runtime records must be uploaded, use the artifact metadata REST API or an approved integration such as JFrog Artifactory, Dynatrace, or Microsoft Defender for Cloud. Linked artifacts records store metadata only; they do not store artifact files. -## Attestation Modes +## `actions/attest` Attestation Modes + +These modes apply only to `actions/attest` usage. SLSA GitHub Generator workflows use `base64-subjects` or `base64-subjects-as-file` instead. | Mode | Input | Description | | :----------------------- | :----------------------------- | :------------------------------------------- | -| **Provenance** (default) | `subject-path` only | Auto-generates SLSA build provenance | +| **Provenance** (default) | `subject-path` only | Auto-generates GitHub artifact provenance | | **SBOM** | `sbom-path` provided | Creates attestation from SPDX/CycloneDX SBOM | | **Custom** | `predicate-type` + `predicate` | User-defined predicate | @@ -363,4 +409,5 @@ slsa-verifier verify-artifact my-artifact \ ### SLSA - [SLSA GitHub Generator](https://github.com/slsa-framework/slsa-github-generator) +- [SLSA GitHub Generator generic generator README](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md) - [SLSA verifier](https://github.com/slsa-framework/slsa-verifier)