ATCR Signature Verification Integration Strategy#
Overview#
This document provides a comprehensive overview of how to integrate ATProto signature verification into various tools and workflows. ATCR uses a layered approach that provides maximum compatibility while maintaining ATProto's decentralized philosophy.
Architecture Layers#
┌─────────────────────────────────────────────────────────┐
│ Layer 4: Applications & Workflows │
│ - CI/CD pipelines │
│ - Kubernetes admission control │
│ - Runtime verification │
│ - Security scanning │
└──────────────────────┬──────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Layer 3: Integration Methods │
│ - Plugins (Ratify, Gatekeeper, Containerd) │
│ - CLI tools (atcr-verify) │
│ - External services (webhooks, APIs) │
│ - (Optional) X.509 certificates (hold-as-CA) │
└──────────────────────┬──────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Layer 2: Signature Discovery │
│ - OCI Referrers API (GET /v2/.../referrers/...) │
│ - ORAS artifact format │
│ - artifactType: application/vnd.atproto.signature... │
└──────────────────────┬──────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Layer 1: ATProto Signatures (Foundation) │
│ - Manifests signed by PDS (K-256) │
│ - Signatures in ATProto repository commits │
│ - Public keys in DID documents │
│ - DID-based identity │
└─────────────────────────────────────────────────────────┘
Integration Approaches#
Approach 1: Plugin-Based (RECOMMENDED) ⭐#
Best for: Kubernetes, standard tooling, production deployments
Integrate through plugin systems of existing tools:
Ratify Verifier Plugin#
- Use case: Kubernetes admission control via Gatekeeper
- Effort: 2-3 weeks to build
- Maturity: CNCF Sandbox project, growing adoption
- Benefits:
- ✅ Standard plugin interface
- ✅ Works with existing Ratify deployments
- ✅ Policy-based enforcement
- ✅ Multi-verifier support (can combine with Notation, Cosign)
Implementation:
// Ratify plugin interface
type ReferenceVerifier interface {
VerifyReference(
ctx context.Context,
subjectRef common.Reference,
referenceDesc ocispecs.ReferenceDescriptor,
store referrerStore.ReferrerStore,
) (VerifierResult, error)
}
Deployment:
apiVersion: config.ratify.deislabs.io/v1beta1
kind: Verifier
metadata:
name: atcr-verifier
spec:
name: atproto
artifactType: application/vnd.atproto.signature.v1+json
parameters:
trustedDIDs:
- did:plc:alice123
OPA Gatekeeper External Provider#
- Use case: Kubernetes admission control with OPA policies
- Effort: 2-3 weeks to build
- Maturity: Very stable, widely adopted
- Benefits:
- ✅ Rego-based policies (flexible)
- ✅ External data provider API (standard)
- ✅ Can reuse existing Gatekeeper deployments
Implementation:
// External data provider
type Provider struct {
verifier *atproto.Verifier
}
func (p *Provider) Provide(ctx context.Context, req ProviderRequest) (*ProviderResponse, error) {
image := req.Keys["image"]
result, err := p.verifier.Verify(ctx, image)
return &ProviderResponse{
Data: map[string]bool{"verified": result.Verified},
}, nil
}
Policy:
package verify
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
startswith(container.image, "atcr.io/")
response := external_data({
"provider": "atcr-verifier",
"keys": ["image"],
"values": [container.image]
})
response.verified != true
msg := sprintf("Image %v has no valid ATProto signature", [container.image])
}
See Gatekeeper Integration Guide
Containerd 2.0 Image Verifier Plugin#
- Use case: Runtime verification at image pull time
- Effort: 1-2 weeks to build
- Maturity: New in Containerd 2.0 (Nov 2024)
- Benefits:
- ✅ Runtime enforcement (pull-time verification)
- ✅ Works for Docker, nerdctl, ctr
- ✅ Transparent to users
- ✅ No Kubernetes required
Limitation: CRI plugin integration still maturing
Implementation:
#!/bin/bash
# /usr/local/bin/containerd-verifiers/atcr-verifier
# Binary called by containerd on image pull
# Containerd passes image info via stdin
read -r INPUT
IMAGE=$(echo "$INPUT" | jq -r '.reference')
DIGEST=$(echo "$INPUT" | jq -r '.descriptor.digest')
# Verify signature
if atcr-verify "$IMAGE@$DIGEST" --quiet; then
exit 0 # Verified
else
exit 1 # Failed
fi
Configuration:
# /etc/containerd/config.toml
[plugins."io.containerd.image-verifier.v1.bindir"]
bin_dir = "/usr/local/bin/containerd-verifiers"
max_verifiers = 5
per_verifier_timeout = "10s"
See Containerd Integration Guide
Approach 2: CLI Tool (RECOMMENDED) ⭐#
Best for: CI/CD, scripts, general-purpose verification
Use atcr-verify CLI tool directly in workflows:
Command-Line Verification#
# Basic verification
atcr-verify atcr.io/alice/myapp:latest
# With trust policy
atcr-verify atcr.io/alice/myapp:latest --policy trust-policy.yaml
# JSON output for scripting
atcr-verify atcr.io/alice/myapp:latest --output json
# Quiet mode for exit codes
atcr-verify atcr.io/alice/myapp:latest --quiet && echo "Verified"
CI/CD Integration#
GitHub Actions:
- name: Verify image
run: atcr-verify ${{ env.IMAGE }} --policy .github/trust-policy.yaml
GitLab CI:
verify:
image: atcr.io/atcr/verify:latest
script:
- atcr-verify ${IMAGE} --policy trust-policy.yaml
Universal Container:
docker run --rm atcr.io/atcr/verify:latest verify IMAGE
Benefits:
- ✅ Works everywhere (not just Kubernetes)
- ✅ Simple integration (single binary)
- ✅ No plugin installation required
- ✅ Offline mode support
See atcr-verify CLI Documentation
Approach 3: External Services#
Best for: Custom admission controllers, API-based verification
Build verification as a service that tools can call:
Webhook Service#
// HTTP endpoint for verification
func (h *Handler) VerifyImage(w http.ResponseWriter, r *http.Request) {
image := r.URL.Query().Get("image")
result, err := h.verifier.Verify(r.Context(), image)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(map[string]interface{}{
"verified": result.Verified,
"did": result.Signature.DID,
"signedAt": result.Signature.SignedAt,
})
}
Usage from Kyverno#
verifyImages:
- imageReferences:
- "atcr.io/*/*"
attestors:
- entries:
- api:
url: http://atcr-verify.kube-system/verify?image={{ image }}
Benefits:
- ✅ Flexible integration
- ✅ Centralized verification logic
- ✅ Caching and rate limiting
- ✅ Can add additional checks (vulnerability scanning, etc.)
Approach 4: Hold-as-CA (OPTIONAL, ENTERPRISE ONLY)#
Best for: Enterprise X.509 PKI compliance requirements
⚠️ WARNING: This approach introduces centralization trade-offs. Only use if you have specific X.509 compliance requirements.
Hold services act as Certificate Authorities that issue X.509 certificates for users, enabling standard Notation verification.
When to use:
- Enterprise requires standard X.509 PKI
- Cannot deploy custom plugins
- Accept centralization trade-off for tool compatibility
When NOT to use:
- Default deployments (use plugins instead)
- Maximum decentralization required
- Don't need X.509 compliance
See Hold-as-CA Architecture for complete details and security implications.
Tool Compatibility Matrix#
| Tool | Discover | Verify | Integration Method | Priority | Effort |
|---|---|---|---|---|---|
| Kubernetes | |||||
| OPA Gatekeeper | ✅ | ✅ | External provider | HIGH | 2-3 weeks |
| Ratify | ✅ | ✅ | Verifier plugin | HIGH | 2-3 weeks |
| Kyverno | ✅ | ⚠️ | External service | MEDIUM | 2 weeks |
| Portieris | ❌ | ❌ | N/A (deprecated) | NONE | - |
| Runtime | |||||
| Containerd 2.0 | ✅ | ✅ | Bindir plugin | MED-HIGH | 1-2 weeks |
| CRI-O | ⚠️ | ⚠️ | Upstream contribution | MEDIUM | 3-4 weeks |
| Podman | ⚠️ | ⚠️ | Upstream contribution | MEDIUM | 3-4 weeks |
| CI/CD | |||||
| GitHub Actions | ✅ | ✅ | Custom action | HIGH | 1 week |
| GitLab CI | ✅ | ✅ | Container image | HIGH | 1 week |
| Jenkins/CircleCI | ✅ | ✅ | Container image | HIGH | 1 week |
| Scanners | |||||
| Trivy | ✅ | ❌ | N/A (not verifier) | NONE | - |
| Snyk | ❌ | ❌ | N/A (not verifier) | NONE | - |
| Anchore | ❌ | ❌ | N/A (not verifier) | NONE | - |
| Registries | |||||
| Harbor | ✅ | ⚠️ | UI integration | LOW | - |
| OCI Tools | |||||
| ORAS CLI | ✅ | ❌ | Already works | Document | - |
| Notation | ⚠️ | ⚠️ | Hold-as-CA | OPTIONAL | 3-4 weeks |
| Cosign | ❌ | ❌ | Not compatible | NONE | - |
| Crane | ✅ | ❌ | Already works | Document | - |
| Skopeo | ⚠️ | ⚠️ | Upstream contribution | LOW | 3-4 weeks |
Legend:
- ✅ Works / Feasible
- ⚠️ Partial / Requires changes
- ❌ Not applicable / Not feasible
Implementation Roadmap#
Phase 1: Foundation (4-5 weeks) ⭐#
Goal: Core verification capability
-
atcr-verify CLI tool (Week 1-2)
- ATProto signature verification
- Trust policy support
- Multiple output formats
- Offline mode
-
OCI Referrers API (Week 2-3)
- AppView endpoint implementation
- ORAS artifact serving
- Integration with existing SBOM pattern
-
CI/CD Container Image (Week 3)
- Universal verification image
- Documentation for GitHub Actions, GitLab CI
- Example workflows
-
Documentation (Week 4-5)
- Integration guides
- Trust policy examples
- Troubleshooting guides
Deliverables:
atcr-verifybinary (Linux, macOS, Windows)atcr.io/atcr/verify:latestcontainer image- OCI Referrers API implementation
- Complete documentation
Phase 2: Kubernetes Integration (3-4 weeks)#
Goal: Production-ready Kubernetes admission control
-
OPA Gatekeeper Provider (Week 1-2)
- External data provider service
- Helm chart for deployment
- Example policies
-
Ratify Plugin (Week 2-3)
- Verifier plugin implementation
- Testing with Ratify
- Documentation
-
Kubernetes Examples (Week 4)
- Deployment manifests
- Policy examples
- Integration testing
Deliverables:
atcr-gatekeeper-providerservice- Ratify plugin binary
- Kubernetes deployment examples
- Production deployment guide
Phase 3: Runtime Verification (2-3 weeks)#
Goal: Pull-time verification
-
Containerd Plugin (Week 1-2)
- Bindir verifier implementation
- Configuration documentation
- Testing with Docker, nerdctl
-
CRI-O/Podman Integration (Week 3, optional)
- Upstream contribution (if accepted)
- Policy.json extension
- Documentation
Deliverables:
- Containerd verifier binary
- Configuration guides
- Runtime verification examples
Phase 4: Optional Features (2-3 weeks)#
Goal: Enterprise features (if demanded)
-
Hold-as-CA (Week 1-2, optional)
- Certificate generation
- Notation signature creation
- Trust store distribution
- Only if enterprise customers request
-
Advanced Features (Week 3, as needed)
- Signature transparency log
- Multi-signature support
- Hardware token integration
Deliverables:
- Hold co-signing implementation (if needed)
- Advanced feature documentation
Decision Matrix#
Which Integration Approach Should I Use?#
┌─────────────────────────────────────────────────┐
│ Are you using Kubernetes? │
└───────────────┬─────────────────────────────────┘
│
┌────────┴────────┐
│ │
YES NO
│ │
↓ ↓
┌──────────────┐ ┌──────────────┐
│ Using │ │ CI/CD │
│ Gatekeeper? │ │ Pipeline? │
└──────┬───────┘ └──────┬───────┘
│ │
┌────┴────┐ ┌────┴────┐
YES NO YES NO
│ │ │ │
↓ ↓ ↓ ↓
External Ratify GitHub Universal
Provider Plugin Action CLI Tool
Use OPA Gatekeeper Provider if:#
- ✅ Already using Gatekeeper
- ✅ Want Rego-based policies
- ✅ Need flexible policy logic
Use Ratify Plugin if:#
- ✅ Using Ratify (or planning to)
- ✅ Want standard plugin interface
- ✅ Need multi-verifier support (Notation + Cosign + ATProto)
Use atcr-verify CLI if:#
- ✅ CI/CD pipelines
- ✅ Local development
- ✅ Non-Kubernetes environments
- ✅ Want simple integration
Use Containerd Plugin if:#
- ✅ Need runtime enforcement
- ✅ Want pull-time verification
- ✅ Using Containerd 2.0+
Use Hold-as-CA if:#
- ⚠️ Enterprise X.509 PKI compliance required
- ⚠️ Cannot deploy plugins
- ⚠️ Accept centralization trade-off
Best Practices#
1. Start Simple#
Begin with CLI tool integration in CI/CD:
# Add to .github/workflows/deploy.yml
- run: atcr-verify $IMAGE --policy .github/trust-policy.yaml
2. Define Trust Policies#
Create trust policies early:
# trust-policy.yaml
policies:
- name: production
scope: "atcr.io/*/prod-*"
require:
signature: true
trustedDIDs: [did:plc:devops-team]
action: enforce
3. Progressive Rollout#
- Week 1: Add verification to CI/CD (audit mode)
- Week 2: Enforce in CI/CD
- Week 3: Add Kubernetes admission control (audit mode)
- Week 4: Enforce in Kubernetes
4. Monitor and Alert#
Track verification metrics:
- Verification success/failure rates
- Policy violations
- Signature coverage (% of images signed)
5. Plan for Key Rotation#
- Document DID key rotation procedures
- Test key rotation in non-production
- Monitor for unexpected key changes
Common Patterns#
Pattern 1: Multi-Layer Defense#
1. CI/CD verification (atcr-verify)
↓ (blocks unsigned images from being pushed)
2. Kubernetes admission (Gatekeeper/Ratify)
↓ (blocks unsigned images from running)
3. Runtime verification (Containerd plugin)
↓ (blocks unsigned images from being pulled)
Pattern 2: Trust Policy Inheritance#
# Global policy
trustedDIDs:
- did:plc:security-team # Always trusted
# Environment-specific policies
staging:
trustedDIDs:
- did:plc:developers # Additional trust for staging
production:
trustedDIDs: [] # Only global trust (security-team)
Pattern 3: Offline Verification#
# Build environment (online)
atcr-verify export $IMAGE -o bundle.json
# Air-gapped environment (offline)
atcr-verify $IMAGE --offline --bundle bundle.json
Migration Guide#
From Docker Content Trust (DCT)#
DCT is deprecated. Migrate to ATCR signatures:
Old (DCT):
export DOCKER_CONTENT_TRUST=1
docker push myimage:latest
New (ATCR):
# Signatures created automatically on push
docker push atcr.io/myorg/myimage:latest
# Verify in CI/CD
atcr-verify atcr.io/myorg/myimage:latest
From Cosign#
Cosign and ATCR signatures can coexist:
Dual signing:
# Push to ATCR (ATProto signature automatic)
docker push atcr.io/myorg/myimage:latest
# Also sign with Cosign (if needed)
cosign sign atcr.io/myorg/myimage:latest
Verification:
# Verify ATProto signature
atcr-verify atcr.io/myorg/myimage:latest
# Or verify Cosign signature
cosign verify atcr.io/myorg/myimage:latest --key cosign.pub
Troubleshooting#
Signatures Not Found#
Symptom: atcr-verify reports "no signature found"
Diagnosis:
# Check if Referrers API works
curl "https://atcr.io/v2/OWNER/REPO/referrers/DIGEST"
# Check if signature artifact exists
oras discover atcr.io/OWNER/REPO:TAG
Solutions:
- Verify Referrers API is implemented
- Re-push image to generate signature
- Check AppView logs for signature creation errors
DID Resolution Fails#
Symptom: Cannot resolve DID to public key
Diagnosis:
# Test DID resolution
curl https://plc.directory/did:plc:XXXXXX
# Check DID document has verificationMethod
curl https://plc.directory/did:plc:XXXXXX | jq .verificationMethod
Solutions:
- Check internet connectivity
- Verify DID is valid
- Ensure DID document contains public key
Policy Violations#
Symptom: Verification fails with "trust policy violation"
Diagnosis:
# Verify with verbose output
atcr-verify IMAGE --policy policy.yaml --verbose
Solutions:
- Add DID to trustedDIDs list
- Check signature age vs. maxAge
- Verify policy scope matches image
See Also#
- ATProto Signatures - Technical foundation
- atcr-verify CLI - CLI tool documentation
- Signature Integration - Tool-specific guides
- Hold-as-CA - X.509 certificate approach (optional)
- Examples - Working code examples