Sigstore attestations#
Sigstore is a way to cryptographically sign packages (or any binary artifacts). It was pioneered in the container space, but has been adopted by many packaging ecosystems: PyPI, Python releases, Rust crates, Homebrew, and Rubygems.
Rattler-build supports creating Sigstore attestations for conda packages, allowing you to cryptographically sign your packages and provide verifiable provenance information.
What does a Sigstore attestation provide?#
A Sigstore attestation ties the producer of a package (for example, a GitHub Actions workflow) to the package artifact. When the attestation is created, metadata about the artifact is registered in a "Transparency Log" which can be inspected at any time. The metadata contains information such as:
- The name and SHA256 hash of the package
- The CI workflow that built the package
- The repository Git hash that contained the CI workflow
- The organization and username that built the package
Using this information, you can attest that a given package was created and uploaded by a certain GitHub organization, and this is transparently logged on both the server and the Sigstore public good instance.
The attestation follows CEP-27, which standardizes the in-toto attestation format with a Conda-specific predicate containing:
- The SHA256 hash of the package (guaranteed to be unique)
- The full filename (
{name}-{version}-{buildstring}.conda) - Optionally, the target channel URL (e.g.,
https://prefix.dev/my-channel)
Automatic attestation generation#
The easiest way to create Sigstore attestations is using the --generate-attestation flag when publishing to prefix.dev:
This automatically:
- Builds your package(s) from the recipe
- Creates a Sigstore attestation using the OIDC identity from your CI environment
- Uploads both the package and attestation to prefix.dev
Requirements
The --generate-attestation flag only works when:
- Uploading to prefix.dev channels
- Using Trusted Publishing (OIDC authentication)
- Running in a supported CI environment (e.g., GitHub Actions)
GitHub Actions example#
Here's a complete example workflow using automatic attestation generation:
name: Build and publish with attestation
on: [push]
jobs:
build:
runs-on: ubuntu-latest
# These permissions are needed for OIDC authentication
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up rattler-build
uses: prefix-dev/rattler-build-action@v0.2.34
- name: Build and publish with attestation
run: |
rattler-build publish ./recipe.yaml \
--to https://prefix.dev/my-channel \
--generate-attestation
Manual attestation with GitHub Actions#
If you need more control over the attestation process, you can use GitHub's official attest action to create the attestation separately:
name: Package and sign
on: [push]
jobs:
build:
runs-on: ubuntu-latest
# These permissions are needed to create a sigstore certificate
permissions:
id-token: write
contents: read
attestations: write
steps:
- uses: actions/checkout@v4
- name: Build conda package
uses: prefix-dev/rattler-build-action@v0.2.34
# Use GitHub's official attest action with the Conda predicate
- uses: actions/attest@v1
id: attest
with:
subject-path: "**/*.conda"
predicate-type: "https://schemas.conda.org/attestations-publish-1.schema.json"
predicate: '{"targetChannel": "https://prefix.dev/my-channel"}'
# Upload with the attestation bundle
- name: Upload the package
run: |
rattler-build upload prefix -c my-channel ./output/**/*.conda \
--attestation ${{ steps.attest.outputs.bundle-path }}
This approach gives you full control over the attestation creation and allows you to customize the predicate or add additional attestation metadata.
Source attestation verification#
Experimental
This feature requires the --experimental flag: rattler-build build --experimental -r recipe.yaml
In addition to signing built packages, rattler-build can also verify the attestations of source archives during the build. This lets you ensure that the source code you're building from was produced by a trusted publisher (e.g., a specific GitHub Actions workflow).
How it works#
Add an attestation block to a URL source in your recipe:
source:
url: https://files.pythonhosted.org/packages/.../flask-3.1.1.tar.gz
sha256: "6489f1..."
attestation:
publishers:
- github:pallets/flask
When rattler-build downloads the source, it will:
- Fetch the Sigstore attestation bundle (automatically derived for PyPI packages, or from
bundle_url) - Verify the bundle signature against the Sigstore transparency log
- Check that the attestation identity matches one of the listed publishers
If verification fails, the build is aborted.
PyPI sources#
For packages hosted on PyPI, the attestation bundle URL is automatically derived from the PyPI attestation API. You only need to specify the publisher:
source:
url: https://files.pythonhosted.org/packages/.../flask-3.1.1.tar.gz
sha256: "6489f1..."
attestation:
publishers:
- github:pallets/flask
GitHub release sources#
For source archives from GitHub releases, specify the bundle_url pointing to the .sigstore.json bundle:
source:
url: https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz
sha256: "eb33e5..."
attestation:
bundle_url: https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz.sigstore.json
publishers:
- github:facebook/zstd
Publisher format#
Publishers are specified in github:owner/repo format. The identity is matched against the Sigstore certificate's Subject Alternative Name (SAN), which for GitHub Actions is the workflow identity.
Verifying attestations#
Once packages are published with attestations, they can be verified using several tools:
Using the GitHub CLI#
gh attestation verify my-package-0.1.0-h123_0.conda \
--owner my-org \
--predicate-type "https://schemas.conda.org/attestations-publish-1.schema.json"
Using cosign#
cosign verify-blob \
--certificate-identity-regexp "https://github.com/my-org/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
my-package-0.1.0-h123_0.conda
Using sigstore-python#
pip install sigstore
sigstore verify identity \
--cert-identity "https://github.com/my-org/my-repo/.github/workflows/build.yml@refs/heads/main" \
--cert-oidc-issuer "https://token.actions.githubusercontent.com" \
my-package-0.1.0-h123_0.conda
Viewing attestations#
You can find attestations for packages published to prefix.dev in several places:
- GitHub: View attestations in your repository's attestations tab (e.g.,
https://github.com/my-org/my-repo/attestations) - Sigstore public goods instance: Search by package hash at search.sigstore.dev
- prefix.dev: View attestations on the package page
Security benefits#
Sigstore attestations provide several security benefits:
-
Unforgeability: Attestations cryptographically bind a package to its producer, preventing forgery of provenance metadata.
-
Transparency: All attestations are logged in a public, append-only transparency log. This means attackers cannot perform targeted attacks without leaving a public trace.
-
No long-lived keys: Sigstore uses ephemeral keys bound to identities (like GitHub Actions workflows), eliminating the risk of key compromise.
-
Build provenance: Machine identities in the attestation provide verifiable information about exactly which workflow, repository, and commit produced the package.