Skip to content

Artifact Signing and Verification

Artifact Keeper supports cryptographic signing and verification of artifacts to ensure authenticity, integrity, and establish content trust throughout your software supply chain.

Overview

Artifact signing provides:

  • Authenticity: Verify artifacts come from trusted sources
  • Integrity: Ensure artifacts haven’t been tampered with
  • Non-repudiation: Cryptographic proof of origin
  • Compliance: Meet regulatory requirements for software provenance

Supported Signing Methods

Container Images

  • Cosign: Sigstore’s container signing tool
  • Docker Content Trust: Notary-based signing
  • OCI Signatures: OCI artifact manifest signatures

Packages

  • GPG Signatures: Universal PGP/GPG signing
  • Language-Specific:
    • RPM: GPG signing
    • Debian/APK: GPG signing
    • Maven: PGP signatures
    • npm: Package signing

Cosign Integration

Cosign is the recommended method for signing container images.

Installation

Terminal window
# Install cosign
brew install cosign
# Or download from GitHub releases
wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign

Generate Signing Keys

Terminal window
# Generate key pair
cosign generate-key-pair
# Enter password for private key
# Creates cosign.key and cosign.pub

Sign Container Image

Terminal window
# Push image to registry
docker push localhost:8080/my-app:1.0.0
# Sign the image
cosign sign --key cosign.key localhost:8080/my-app:1.0.0

With keyless signing (Sigstore):

Terminal window
# Sign using OIDC identity
cosign sign localhost:8080/my-app:1.0.0

Verify Signature

Terminal window
# Verify with public key
cosign verify --key cosign.pub localhost:8080/my-app:1.0.0
# Verify keyless signature
cosign verify \
--certificate-identity=user@example.com \
--certificate-oidc-issuer=https://accounts.google.com \
localhost:8080/my-app:1.0.0

GPG Signing

Generate GPG Key

Terminal window
# Generate new GPG key
gpg --full-generate-key
# List keys
gpg --list-keys
# Export public key
gpg --armor --export your-email@example.com > public.key
# Export private key (keep secure!)
gpg --armor --export-secret-key your-email@example.com > private.key

Sign Files with GPG

Terminal window
# Sign a file
gpg --detach-sign --armor artifact.tar.gz
# Creates artifact.tar.gz.asc
# Sign and encrypt
gpg --sign --armor artifact.tar.gz

Verify GPG Signature

Terminal window
# Import public key
gpg --import public.key
# Verify signature
gpg --verify artifact.tar.gz.asc artifact.tar.gz

Linux Package Signing

RPM Signing

Configure RPM signing:

Terminal window
# Create GPG key for RPM signing
gpg --full-generate-key
# Import key to RPM database
rpm --import public.key
# Configure ~/.rpmmacros
cat > ~/.rpmmacros <<EOF
%_signature gpg
%_gpg_name your-email@example.com
EOF

Sign RPM package:

Terminal window
# Sign package
rpm --addsign package.rpm
# Verify signature
rpm --checksig package.rpm

Debian Package Signing

Sign Debian packages:

Terminal window
# Sign package
dpkg-sig --sign builder package.deb
# Verify signature
dpkg-sig --verify package.deb

Create signed repository:

Terminal window
# Create Release file
apt-ftparchive release . > Release
# Sign Release file
gpg --clearsign -o InRelease Release
gpg -abs -o Release.gpg Release
# Export public key for users
gpg --armor --export your-email@example.com > repository.key

Alpine Package Signing

Sign APK packages:

Terminal window
# Generate signing key
openssl genrsa -out signing.key 2048
openssl rsa -in signing.key -pubout -out signing.pub
# Sign package
abuild-sign package.apk

Signing Key Management

Artifact Keeper provides an API for managing signing keys.

API Endpoints

POST /api/v1/signing/keys # Upload signing key
GET /api/v1/signing/keys # List keys
GET /api/v1/signing/keys/{id} # Get key details
DELETE /api/v1/signing/keys/{id} # Delete key
POST /api/v1/signing/verify # Verify signature

Upload Signing Key

Terminal window
POST /api/v1/signing/keys
Content-Type: application/json
{
"name": "production-signing-key",
"type": "gpg",
"public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...",
"repositories": ["production/*"],
"metadata": {
"owner": "security-team",
"environment": "production"
}
}

List Signing Keys

Terminal window
GET /api/v1/signing/keys
# Response
{
"keys": [
{
"id": "key-123",
"name": "production-signing-key",
"type": "gpg",
"fingerprint": "1234 5678 90AB CDEF",
"repositories": ["production/*"],
"created_at": "2024-01-15T10:00:00Z",
"expires_at": "2025-01-15T10:00:00Z"
}
]
}

Verify Signature via API

Terminal window
POST /api/v1/signing/verify
Content-Type: application/json
{
"artifact": {
"name": "my-app",
"version": "1.0.0",
"repository": "production/apps"
},
"signature_type": "cosign"
}
# Response
{
"valid": true,
"signer": {
"identity": "ci-system@example.com",
"key_id": "key-123",
"timestamp": "2024-01-15T10:30:00Z"
},
"certificate": {
"subject": "ci-system@example.com",
"issuer": "https://accounts.google.com",
"valid_from": "2024-01-15T10:00:00Z",
"valid_to": "2024-01-15T11:00:00Z"
}
}

Repository Signing Policies

Enforce signing requirements per repository.

Configure Signing Policy

signing-policy.yaml
name: "require-signatures"
description: "Require signed artifacts for production"
repositories:
- "production/*"
- "stable/*"
rules:
- name: "require-cosign-signature"
artifact_types: ["docker", "oci"]
signature_type: "cosign"
required: true
key_requirements:
- type: "keyless"
certificate_identity: "*@example.com"
certificate_oidc_issuer: "https://accounts.google.com"
- name: "require-gpg-signature"
artifact_types: ["rpm", "deb", "apk"]
signature_type: "gpg"
required: true
trusted_keys:
- "key-123"
- "key-456"

Apply policy:

Terminal window
POST /api/v1/signing/policies
Content-Type: application/json
{
"name": "require-signatures",
"repositories": ["production/*"],
"rules": [...]
}

Enforcement

When signing is required:

Terminal window
# Unsigned artifact upload fails
docker push localhost:8080/production/app:1.0.0
Error: Signature required for repository "production/app"
Please sign the artifact before pushing
# Signed artifact succeeds
cosign sign --key cosign.key localhost:8080/production/app:1.0.0
docker push localhost:8080/production/app:1.0.0
Success: Artifact uploaded and signature verified

Integration with CI/CD

GitHub Actions with Cosign

name: Build, Sign, and Push
on: [push]
jobs:
build-and-sign:
runs-on: ubuntu-latest
permissions:
id-token: write
packages: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.example.com
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build image
run: |
docker build -t registry.example.com/my-app:${{ github.sha }} .
docker push registry.example.com/my-app:${{ github.sha }}
- name: Sign image (keyless)
run: |
cosign sign --yes registry.example.com/my-app:${{ github.sha }}

With Private Keys

- name: Sign image (with key)
env:
COSIGN_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
echo "$COSIGN_KEY" > cosign.key
cosign sign --key cosign.key registry.example.com/my-app:${{ github.sha }}

Maven PGP Signing

- name: Sign and deploy Maven artifact
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
echo "$GPG_PRIVATE_KEY" | gpg --import
mvn clean deploy -Pgpg

Configuration in pom.xml:

<profiles>
<profile>
<id>gpg</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

Transparency Logs

Sigstore Rekor

Artifact Keeper can integrate with Rekor for transparency logging:

config/rekor.yaml
rekor:
enabled: true
url: "https://rekor.sigstore.dev"
log_signatures: true
verify_inclusion: true

Signatures are logged to Rekor:

Terminal window
# Sign and log
cosign sign --rekor-url https://rekor.sigstore.dev \
localhost:8080/my-app:1.0.0
# Verify with transparency log
cosign verify --rekor-url https://rekor.sigstore.dev \
localhost:8080/my-app:1.0.0

Search Transparency Logs

Terminal window
# Search for signatures
rekor-cli search --artifact localhost:8080/my-app:1.0.0
# Get log entry
rekor-cli get --uuid <uuid>

Signature Storage

Signature Artifacts

Signatures can be stored as:

  1. Attached Signatures: Stored alongside artifact
  2. OCI Artifacts: Signatures as OCI artifacts (recommended)
  3. Separate Files: .sig or .asc files

OCI Signature Format

Cosign stores signatures as OCI artifacts:

registry.example.com/my-app:1.0.0
registry.example.com/my-app:sha256-<digest>.sig

View signatures:

Terminal window
# List signatures
cosign tree localhost:8080/my-app:1.0.0

Attestations

Sign and verify attestations about artifacts:

Create Attestation

Terminal window
# Create SLSA provenance attestation
cosign attest --key cosign.key \
--predicate provenance.json \
--type slsaprovenance \
localhost:8080/my-app:1.0.0

Verify Attestation

Terminal window
# Verify attestation
cosign verify-attestation --key cosign.pub \
--type slsaprovenance \
localhost:8080/my-app:1.0.0

Attestation Types

  • SLSA Provenance: Build provenance information
  • SBOM: Software Bill of Materials
  • Vulnerability Scan: Scan results attestation
  • Custom: Application-specific attestations

Best Practices

Key Management

  • Use hardware security modules (HSM) for production keys
  • Rotate keys regularly
  • Use separate keys for different environments
  • Never commit private keys to version control
  • Use key management services (AWS KMS, Google KMS, Azure Key Vault)

Signing Workflow

  1. Build artifact in secure environment
  2. Run security scans
  3. Generate attestations (SBOM, provenance)
  4. Sign artifact and attestations
  5. Upload to registry
  6. Log to transparency log
  7. Verify before deployment

Verification

  • Always verify signatures before deployment
  • Use keyless signing when possible
  • Require attestations for production artifacts
  • Integrate verification into CI/CD gates
  • Monitor signature verification failures

Compliance

  • Document signing procedures
  • Maintain key inventory
  • Audit signature operations
  • Implement key rotation policies
  • Meet regulatory requirements (FIPS, Common Criteria)

Troubleshooting

Signature Verification Failures

Check signature exists:

Terminal window
cosign tree localhost:8080/my-app:1.0.0

Verify with correct key:

Terminal window
cosign verify --key cosign.pub localhost:8080/my-app:1.0.0

Check certificate details:

Terminal window
cosign verify localhost:8080/my-app:1.0.0 --insecure-ignore-tlog

Key Issues

Test GPG key:

Terminal window
gpg --list-keys
gpg --test-sign

Verify key permissions:

Terminal window
chmod 600 cosign.key

OIDC Issues

For keyless signing, verify OIDC token:

Terminal window
cosign sign --verbose localhost:8080/my-app:1.0.0

See Also