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
# Install cosignbrew install cosign
# Or download from GitHub releaseswget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64chmod +x cosign-linux-amd64sudo mv cosign-linux-amd64 /usr/local/bin/cosignGenerate Signing Keys
# Generate key paircosign generate-key-pair
# Enter password for private key# Creates cosign.key and cosign.pubSign Container Image
# Push image to registrydocker push localhost:8080/my-app:1.0.0
# Sign the imagecosign sign --key cosign.key localhost:8080/my-app:1.0.0With keyless signing (Sigstore):
# Sign using OIDC identitycosign sign localhost:8080/my-app:1.0.0Verify Signature
# Verify with public keycosign verify --key cosign.pub localhost:8080/my-app:1.0.0
# Verify keyless signaturecosign verify \ --certificate-identity=user@example.com \ --certificate-oidc-issuer=https://accounts.google.com \ localhost:8080/my-app:1.0.0GPG Signing
Generate GPG Key
# Generate new GPG keygpg --full-generate-key
# List keysgpg --list-keys
# Export public keygpg --armor --export your-email@example.com > public.key
# Export private key (keep secure!)gpg --armor --export-secret-key your-email@example.com > private.keySign Files with GPG
# Sign a filegpg --detach-sign --armor artifact.tar.gz# Creates artifact.tar.gz.asc
# Sign and encryptgpg --sign --armor artifact.tar.gzVerify GPG Signature
# Import public keygpg --import public.key
# Verify signaturegpg --verify artifact.tar.gz.asc artifact.tar.gzLinux Package Signing
RPM Signing
Configure RPM signing:
# Create GPG key for RPM signinggpg --full-generate-key
# Import key to RPM databaserpm --import public.key
# Configure ~/.rpmmacroscat > ~/.rpmmacros <<EOF%_signature gpg%_gpg_name your-email@example.comEOFSign RPM package:
# Sign packagerpm --addsign package.rpm
# Verify signaturerpm --checksig package.rpmDebian Package Signing
Sign Debian packages:
# Sign packagedpkg-sig --sign builder package.deb
# Verify signaturedpkg-sig --verify package.debCreate signed repository:
# Create Release fileapt-ftparchive release . > Release
# Sign Release filegpg --clearsign -o InRelease Releasegpg -abs -o Release.gpg Release
# Export public key for usersgpg --armor --export your-email@example.com > repository.keyAlpine Package Signing
Sign APK packages:
# Generate signing keyopenssl genrsa -out signing.key 2048openssl rsa -in signing.key -pubout -out signing.pub
# Sign packageabuild-sign package.apkSigning Key Management
Artifact Keeper provides an API for managing signing keys.
API Endpoints
POST /api/v1/signing/keys # Upload signing keyGET /api/v1/signing/keys # List keysGET /api/v1/signing/keys/{id} # Get key detailsDELETE /api/v1/signing/keys/{id} # Delete keyPOST /api/v1/signing/verify # Verify signatureUpload Signing Key
POST /api/v1/signing/keysContent-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
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
POST /api/v1/signing/verifyContent-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
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:
POST /api/v1/signing/policiesContent-Type: application/json
{ "name": "require-signatures", "repositories": ["production/*"], "rules": [...]}Enforcement
When signing is required:
# Unsigned artifact upload failsdocker push localhost:8080/production/app:1.0.0Error: Signature required for repository "production/app"Please sign the artifact before pushing
# Signed artifact succeedscosign sign --key cosign.key localhost:8080/production/app:1.0.0docker push localhost:8080/production/app:1.0.0Success: Artifact uploaded and signature verifiedIntegration with CI/CD
GitHub Actions with Cosign
name: Build, Sign, and Pushon: [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 -PgpgConfiguration 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:
rekor: enabled: true url: "https://rekor.sigstore.dev" log_signatures: true verify_inclusion: trueSignatures are logged to Rekor:
# Sign and logcosign sign --rekor-url https://rekor.sigstore.dev \ localhost:8080/my-app:1.0.0
# Verify with transparency logcosign verify --rekor-url https://rekor.sigstore.dev \ localhost:8080/my-app:1.0.0Search Transparency Logs
# Search for signaturesrekor-cli search --artifact localhost:8080/my-app:1.0.0
# Get log entryrekor-cli get --uuid <uuid>Signature Storage
Signature Artifacts
Signatures can be stored as:
- Attached Signatures: Stored alongside artifact
- OCI Artifacts: Signatures as OCI artifacts (recommended)
- Separate Files: .sig or .asc files
OCI Signature Format
Cosign stores signatures as OCI artifacts:
registry.example.com/my-app:1.0.0registry.example.com/my-app:sha256-<digest>.sigView signatures:
# List signaturescosign tree localhost:8080/my-app:1.0.0Attestations
Sign and verify attestations about artifacts:
Create Attestation
# Create SLSA provenance attestationcosign attest --key cosign.key \ --predicate provenance.json \ --type slsaprovenance \ localhost:8080/my-app:1.0.0Verify Attestation
# Verify attestationcosign verify-attestation --key cosign.pub \ --type slsaprovenance \ localhost:8080/my-app:1.0.0Attestation 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
- Build artifact in secure environment
- Run security scans
- Generate attestations (SBOM, provenance)
- Sign artifact and attestations
- Upload to registry
- Log to transparency log
- 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:
cosign tree localhost:8080/my-app:1.0.0Verify with correct key:
cosign verify --key cosign.pub localhost:8080/my-app:1.0.0Check certificate details:
cosign verify localhost:8080/my-app:1.0.0 --insecure-ignore-tlogKey Issues
Test GPG key:
gpg --list-keysgpg --test-signVerify key permissions:
chmod 600 cosign.keyOIDC Issues
For keyless signing, verify OIDC token:
cosign sign --verbose localhost:8080/my-app:1.0.0See Also
- Security Scanning - Scan artifacts for vulnerabilities
- Security Policies - Enforce security policies
- Docker Guide - Container image management