A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
73
fork

Configure Feed

Select the types of activity you want to include in your feed.

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#

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

See Ratify Integration Guide


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


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

  1. atcr-verify CLI tool (Week 1-2)

    • ATProto signature verification
    • Trust policy support
    • Multiple output formats
    • Offline mode
  2. OCI Referrers API (Week 2-3)

    • AppView endpoint implementation
    • ORAS artifact serving
    • Integration with existing SBOM pattern
  3. CI/CD Container Image (Week 3)

    • Universal verification image
    • Documentation for GitHub Actions, GitLab CI
    • Example workflows
  4. Documentation (Week 4-5)

    • Integration guides
    • Trust policy examples
    • Troubleshooting guides

Deliverables:

  • atcr-verify binary (Linux, macOS, Windows)
  • atcr.io/atcr/verify:latest container image
  • OCI Referrers API implementation
  • Complete documentation

Phase 2: Kubernetes Integration (3-4 weeks)#

Goal: Production-ready Kubernetes admission control

  1. OPA Gatekeeper Provider (Week 1-2)

    • External data provider service
    • Helm chart for deployment
    • Example policies
  2. Ratify Plugin (Week 2-3)

    • Verifier plugin implementation
    • Testing with Ratify
    • Documentation
  3. Kubernetes Examples (Week 4)

    • Deployment manifests
    • Policy examples
    • Integration testing

Deliverables:

  • atcr-gatekeeper-provider service
  • Ratify plugin binary
  • Kubernetes deployment examples
  • Production deployment guide

Phase 3: Runtime Verification (2-3 weeks)#

Goal: Pull-time verification

  1. Containerd Plugin (Week 1-2)

    • Bindir verifier implementation
    • Configuration documentation
    • Testing with Docker, nerdctl
  2. 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)

  1. Hold-as-CA (Week 1-2, optional)

    • Certificate generation
    • Notation signature creation
    • Trust store distribution
    • Only if enterprise customers request
  2. 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#

  1. Week 1: Add verification to CI/CD (audit mode)
  2. Week 2: Enforce in CI/CD
  3. Week 3: Add Kubernetes admission control (audit mode)
  4. 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:

  1. Verify Referrers API is implemented
  2. Re-push image to generate signature
  3. 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:

  1. Check internet connectivity
  2. Verify DID is valid
  3. 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:

  1. Add DID to trustedDIDs list
  2. Check signature age vs. maxAge
  3. Verify policy scope matches image

See Also#