A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
README.md

Ratify ATProto Verifier Plugin#

This is a reference implementation of a Ratify verifier plugin for ATProto signatures.

Overview#

Ratify is a verification framework that integrates with OPA Gatekeeper to enforce signature policies in Kubernetes. This plugin adds support for verifying ATProto signatures on ATCR container images.

Architecture#

Kubernetes Pod Creation
       ↓
OPA Gatekeeper (admission webhook)
       ↓
Ratify (verification engine)
       ↓
ATProto Verifier Plugin ← This plugin
       ↓
   1. Fetch signature artifact from registry
   2. Parse ATProto signature metadata
   3. Resolve DID to public key
   4. Fetch repository commit from PDS
   5. Verify ECDSA K-256 signature
   6. Check trust policy
       ↓
   Return: Allow/Deny

Files#

  • verifier.go - Main verifier implementation
  • config.go - Configuration and trust policy
  • resolver.go - DID and PDS resolution
  • crypto.go - K-256 signature verification
  • Dockerfile - Build custom Ratify image with plugin
  • deployment.yaml - Kubernetes deployment manifest
  • verifier-crd.yaml - Ratify Verifier custom resource

Prerequisites#

  • Go 1.21+
  • Ratify source code (for building plugin)
  • Kubernetes cluster with OPA Gatekeeper installed
  • Access to ATCR registry

Building#

# Clone Ratify
git clone https://github.com/ratify-project/ratify.git
cd ratify

# Copy plugin files
cp -r /path/to/examples/plugins/ratify-verifier plugins/verifier/atproto/

# Build plugin
CGO_ENABLED=0 go build -o atproto-verifier \
  -ldflags="-w -s" \
  ./plugins/verifier/atproto

# Build custom Ratify image with plugin
docker build -f Dockerfile.with-atproto -t atcr.io/atcr/ratify-with-atproto:latest .

Deployment#

1. Deploy Ratify with Plugin#

# Push custom image
docker push atcr.io/atcr/ratify-with-atproto:latest

# Deploy Ratify
kubectl apply -f deployment.yaml

2. Configure Verifier#

# Create Verifier custom resource
kubectl apply -f verifier-crd.yaml

3. Configure Trust Policy#

# Create ConfigMap with trust policy
kubectl create configmap atcr-trust-policy \
  --from-file=trust-policy.yaml \
  -n gatekeeper-system

4. Create Gatekeeper Constraint#

kubectl apply -f constraint.yaml

5. Test#

# Try to create pod with signed image (should succeed)
kubectl run test-signed --image=atcr.io/alice/myapp:latest

# Try to create pod with unsigned image (should fail)
kubectl run test-unsigned --image=atcr.io/malicious/fake:latest

Configuration#

Trust Policy Format#

# trust-policy.yaml
version: 1.0

trustedDIDs:
  did:plc:alice123:
    name: "Alice (DevOps)"
    validFrom: "2024-01-01T00:00:00Z"
    expiresAt: null

  did:plc:bob456:
    name: "Bob (Security)"
    validFrom: "2024-06-01T00:00:00Z"
    expiresAt: "2025-12-31T23:59:59Z"

policies:
  - name: production
    scope: "atcr.io/*/prod-*"
    require:
      signature: true
      trustedDIDs:
        - did:plc:alice123
        - did:plc:bob456
    action: enforce

Verifier Configuration#

apiVersion: config.ratify.deislabs.io/v1beta1
kind: Verifier
metadata:
  name: atproto-verifier
spec:
  name: atproto
  artifactType: application/vnd.atproto.signature.v1+json
  address: /.ratify/plugins/atproto-verifier
  parameters:
    trustPolicyPath: /config/trust-policy.yaml
    didResolverTimeout: 10s
    pdsTimeout: 10s
    cacheEnabled: true
    cacheTTL: 300s

Implementation Details#

Verifier Interface#

The plugin implements Ratify's ReferenceVerifier interface:

type ReferenceVerifier interface {
    Name() string
    Type() string
    CanVerify(artifactType string) bool
    VerifyReference(
        ctx context.Context,
        subjectRef common.Reference,
        referenceDesc ocispecs.ReferenceDescriptor,
        store referrerstore.ReferrerStore,
    ) (VerifierResult, error)
}

Verification Flow#

  1. Artifact Fetch: Download signature artifact from registry via Ratify's store
  2. Parse Metadata: Extract ATProto signature metadata (DID, PDS, commit CID)
  3. DID Resolution: Resolve DID to public key via PLC directory or did:web
  4. Commit Fetch: Get repository commit from PDS via XRPC
  5. Signature Verify: Verify ECDSA K-256 signature over commit bytes
  6. Trust Check: Validate DID against trust policy
  7. Result: Return success/failure with metadata

Error Handling#

The plugin returns detailed error information:

type VerifierResult struct {
    IsSuccess bool
    Name      string
    Type      string
    Message   string
    Extensions map[string]interface{}
}

Extensions include:

  • did - Signer's DID
  • handle - Signer's handle (if available)
  • signedAt - Signature timestamp
  • commitCid - ATProto commit CID
  • pdsEndpoint - PDS URL
  • error - Error details (if verification failed)

Troubleshooting#

Plugin Not Found#

# Check plugin is in image
kubectl exec -n gatekeeper-system deployment/ratify -c ratify -- ls -la /.ratify/plugins/

# Check logs
kubectl logs -n gatekeeper-system deployment/ratify -c ratify

Verification Failing#

# Check Ratify logs for details
kubectl logs -n gatekeeper-system deployment/ratify -c ratify | grep atproto

# Check Verifier status
kubectl get verifier atproto-verifier -o yaml

# Test DID resolution manually
curl https://plc.directory/did:plc:alice123

Trust Policy Issues#

# Check ConfigMap exists
kubectl get configmap atcr-trust-policy -n gatekeeper-system

# View policy contents
kubectl get configmap atcr-trust-policy -n gatekeeper-system -o yaml

Performance Considerations#

Caching#

The plugin caches:

  • DID documents (TTL: 5 minutes)
  • PDS endpoints (TTL: 5 minutes)
  • Public keys (TTL: 5 minutes)

Configure via cacheEnabled and cacheTTL parameters.

Timeouts#

Configure timeouts for external calls:

  • didResolverTimeout - DID resolution (default: 10s)
  • pdsTimeout - PDS XRPC calls (default: 10s)

Rate Limiting#

Consider implementing rate limiting for:

  • DID resolution (PLC directory)
  • PDS XRPC calls
  • Signature verification

Security Considerations#

Trust Policy Management#

  • Store trust policy in version control
  • Review DID additions/removals carefully
  • Set expiration dates for temporary access
  • Audit trust policy changes

Private Key Protection#

  • Plugin only uses public keys
  • No private keys needed for verification
  • DID resolution is read-only
  • PDS queries are read-only

Denial of Service#

  • Implement timeouts for all external calls
  • Cache DID documents to reduce load
  • Rate limit verification requests
  • Monitor verification latency

See Also#

Support#

For issues or questions: