How to Sign Artifacts
Sign artifacts when pushing to provide cryptographic proof of provenance.
Prerequisites
- blobber installed
- For keyless signing: Access to an OIDC provider (GitHub, Google, etc.)
- For key-based signing: A private key file (PEM format)
Sign with Keyless Signing (Recommended)
Keyless signing uses your OIDC identity (e.g., GitHub account) and requires no key management.
Step 1: Push with the --sign flag
blobber push --sign ./config ghcr.io/myorg/config:v1
Step 2: Complete OIDC authentication
A browser window opens for authentication. Sign in with your identity provider.
After authentication, blobber:
- Generates an ephemeral key pair
- Obtains a certificate from Fulcio
- Signs the manifest
- Records the signature in Rekor
- Stores the signature as an OCI referrer
Output:
sha256:abc123...
Sign with a Private Key
For environments without OIDC access (air-gapped, certain CI systems).
Step 1: Generate a key (if needed)
openssl ecparam -genkey -name prime256v1 -noout -out private.pem
Step 2: Push with the key
blobber push --sign --sign-key private.pem ./config ghcr.io/myorg/config:v1
Step 3: (Optional) Add to Rekor for auditability
Key-based signatures can still be recorded in Rekor:
blobber push --sign --sign-key private.pem --rekor-url https://rekor.sigstore.dev ./config ghcr.io/myorg/config:v1
Sign with an Encrypted Key
If your private key is password-protected:
blobber push --sign --sign-key private.pem --sign-key-pass "your-password" ./config ghcr.io/myorg/config:v1
Or via environment variable:
export BLOBBER_SIGN_KEY_PASS="your-password"
blobber push --sign --sign-key private.pem ./config ghcr.io/myorg/config:v1
Use Custom Sigstore Infrastructure
For private Sigstore deployments:
blobber push --sign \
--fulcio-url https://fulcio.internal.example.com \
--rekor-url https://rekor.internal.example.com \
./config ghcr.io/myorg/config:v1
Sign in CI/CD (GitHub Actions)
GitHub Actions provides OIDC tokens automatically:
jobs:
push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # Required for OIDC signing
steps:
- uses: actions/checkout@v4
- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push with signing
run: blobber push --sign ./config ghcr.io/${{ github.repository }}/config:${{ github.sha }}
The signature will be bound to your GitHub Actions workflow identity.
Sign Using the Go Library
Keyless Signing
import (
"github.com/meigma/blobber"
"github.com/meigma/blobber/sigstore"
)
// Create a keyless signer
signer, err := sigstore.NewSigner(
sigstore.WithEphemeralKey(),
sigstore.WithFulcio("https://fulcio.sigstore.dev"),
sigstore.WithRekor("https://rekor.sigstore.dev"),
)
if err != nil {
return err
}
// Create client with signer
client, err := blobber.NewClient(
blobber.WithSigner(signer),
)
if err != nil {
return err
}
// Push will automatically sign
digest, err := client.Push(ctx, "ghcr.io/org/config:v1", files)
Key-Based Signing
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"github.com/meigma/blobber"
"github.com/meigma/blobber/sigstore"
)
// Generate or load your key
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
// Create signer with the key
signer, err := sigstore.NewSigner(
sigstore.WithPrivateKey(key),
)
if err != nil {
return err
}
client, err := blobber.NewClient(
blobber.WithSigner(signer),
)
From PEM File
pemData, _ := os.ReadFile("private.pem")
signer, err := sigstore.NewSigner(
sigstore.WithPrivateKeyPEM(pemData, nil), // nil password for unencrypted
sigstore.WithRekor("https://rekor.sigstore.dev"), // optional
)
Verify Your Signature Was Created
List referrers to confirm the signature exists:
# Using crane (from google/go-containerregistry)
crane manifest ghcr.io/myorg/config:v1 | jq -r '.digest' | xargs -I {} \
crane referrers ghcr.io/myorg/config@{}
Or verify by pulling with verification:
blobber pull --verify --verify-unsafe ghcr.io/myorg/config:v1 ./output
Troubleshooting
"no keypair configured"
You must provide either --sign-key for key-based signing or use keyless (default with just --sign).
"failed to get Fulcio certificate"
- Check network connectivity to
fulcio.sigstore.dev - Ensure OIDC authentication completed successfully
- For CI, verify
id-token: writepermission is set
"failed to submit to Rekor"
- Check network connectivity to
rekor.sigstore.dev - Verify the Rekor URL is correct for private deployments
Browser doesn't open for OIDC
In headless environments (CI, containers), Sigstore uses device flow or environment-provided OIDC tokens. Ensure your CI system supports OIDC.
See Also
- How to Verify Signatures - Verify signed artifacts
- About Signing - Understanding signing concepts
- CLI Reference: push - All push flags