Artifact Attestations enters public beta

GitHub has announced the public beta of Artifact Attestations, a feature designed to give developers a verifiable link between software artifacts and the source code and build processes that produced them. Built on Sigstore, the open source signing and verification project, Artifact Attestations lets project maintainers create tamper-proof records of their build provenance without managing their own signing infrastructure.

Consumers of attested artifacts can use the metadata as a basis for policy checks through tools such as Rego and Cue. Initial verification support ships with GitHub CLI, with Kubernetes ecosystem support planned later this year.

Flow chart demonstrating that if a customer Actions workflow is in a public repository, it can be attested with Public Good Sigstore, and stored in a public transparency log. If it is in a private repository, attestation happens with GitHub Sigstore, and the attestation is stored in a private transparency log.

Setting up attestations in a workflow

Enabling Artifact Attestations requires minimal configuration. A maintainer adds a small block of YAML to their GitHub Actions workflow and installs the GitHub CLI tool for verification.

First, the workflow must be granted write access to the attestations store:

permissions:
  id-token: write
  attestations: write
  contents: read

Next, the workflow directs the attestation action to run after the artifact is generated:

- name: Attest Build Provenance
uses: actions/attest-build-provenance@897ed5eab6ed058a474202017ada7f40bfa52940 # v1.0.0
with:
subject-path: "bin/my-artifact.tar.gz"

Once the build completes and the artifact is downloaded, verification uses GitHub CLI (version 2.49.0 or greater) with the name of the organization that owns the repository where the action ran:

gh attestation verify my-artifact.tar.gz -o my-organization

For offline or air-gapped verification, the attestation document itself can be downloaded and stored. Certificate details can be inspected, and verified attestation contents can be extracted as JSON for piping into a policy engine like OPA.

package attestation.slsa1
import future.keywords.if

approved_repos := [
"https://github.com/sigstore/sigstore-js",
"https://github.com/github/example",
]

# Fail closed
default allow := false

# Allow if the repository is in the approved_repos list and the predicateType matches
allow {
some i
# Check if the predicateType matches the required type
input[i].verificationResult.statement.predicateType == "https://slsa.dev/provenance/v1"

# Attempt to safely assign the repo variable
repo := input[i].verificationResult.statement.predicate.buildDefinition.externalParameters.workflow.repository

repo == approved_repos[_]
}

As an example, attestation JSON can be used to verify that a file came from an allowed repository in a policy:

$ gh attestation verify -R github/example --format json myfile.zip | \
opa eval --stdin-input -f raw \
-d policy.rego "data.attestation.slsa1.allow == true"

true

Attesting SBOMs alongside artifacts

Builds that already generate a Software Bill of Materials (SBOM) can associate it with a final artifact using the new attest-sbom action. The action takes the artifact path, wraps the SBOM in an in-toto attestation predicate, signs it with GitHub's internal Sigstore instance, and stores the result in the attestation store. Projects without existing SBOM generation can use anchore/sbom-action, which supports container images and a range of language ecosystems.

To associate an SBOM with a build artifact:

Grant the workflow write permission for the attestation store:

permissions:
  id-token: write
  attestations: write
  contents: read

Generate an SBOM from the build output using a tool like Anchore's Syft:

- uses: anchore/sbom-action@v0
with:
path: ./build/
format: 'spdx-json'
output-file: 'sbom.spdx.json'

Use the attest-sbom action to wrap the SBOM contents in an in-toto predicate, sign it, associate it with the artifact, and send it to the attestation store:

- uses: actions/attest-sbom@v1
with:
subject-path: 'bin/my-artifact.tar.gz'
sbom-path: 'sbom.spdx.json'

How the signing flow works

Artifact Attestations replaces public key infrastructure management with trust in the GitHub account's workload identity. Each signing operation uses a temporary keypair. The public key is embedded in a certificate bound to the build system's workload identity, while the private key remains only in process memory and is discarded immediately after signing. This avoids the complexities of certificate revocation lists and long-lived human identity keys.

The signing flow works as follows:

  • When an attestation action runs, the Sigstore client requests the GitHub Actions OIDC token for that workflow run. It generates a key pair and sends the public half and the OIDC token to Fulcio, the certificate authority. For public repositories, Fulcio from the Sigstore Public Good Instance issues the certificate; for private repositories, GitHub's internal Fulcio instance handles issuance so no customer information leaves GitHub.
  • Fulcio validates the token signature and mints a short-lived X.509 certificate binding the public key to the workflow's OIDC identity.
  • The client calculates a SHA-256 digest of the artifact and writes an in-toto statement binding the subject to a SLSA predicate containing data from the OIDC token's claims.
  • The private key seals the in-toto statement in a DSSE signing envelope, after which the key is discarded. The envelope's signature goes to the Timestamp Authority for a counter-signature proving the signature was produced during the certificate's 10-minute validity window.
  • The complete sigstore bundle is stored in GitHub's attestation store. For private repositories the flow ends there; for public repositories the attestation is also written to the Sigstore Public Good Instance's Rekor immutable ledger.

GitHub as a root certificate authority

To enable signing on GitHub Actions and verification anywhere, including offline, GitHub established itself as a root certificate authority in October 2023, running an X.509 certificate authority and an RFC 3161 timestamp server. The trust root is managed by a quorum of hardware tokens held by employees across different geographies and roles, with tooling from the TUF project. Intermediate certificates reside in Azure KeyVault Managed HSMs and sign leaf certificates issued by Sigstore Fulcio and Sigstore Timestamp Authority. Leaf signing certificates are valid for only 10 minutes, eliminating the need for certificate revocation lists.

Public and private modes

Artifact Attestations operates in two modes depending on repository visibility. Attestations generated in public repos are written to the Sigstore Public Good Instance and appear on its public immutable ledger. For private repositories on GitHub Enterprise plans, attestations go to an internal, private database with no information published to public ledgers or logs.

What attestations do and don't guarantee

Provenance alone does not make an artifact or build process secure. What it provides is a tamper-proof guarantee that the thing being executed is exactly the thing that was built, which blocks certain attack vectors. Effective security still requires code review for all patches and timely dependency updates.

The attestation provides an unforgeable paper trail tying an artifact to a specific GitHub Actions workflow run. Future work includes supporting additional artifact types associated with the build process, such as vulnerability reports and other in-toto predicate types. Kubernetes support and new release guarantees are also expected later this year.