ATProto Signature Verification Examples#
This directory contains practical examples for verifying ATProto signatures on ATCR container images.
Files#
Scripts#
-
atcr-verify.sh- Standalone signature verification script- Verifies ATProto signatures using shell commands
- Requires:
curl,jq,crane,oras - Does everything except full cryptographic verification
- Use this until the
atcr-verifyCLI tool is built
-
verify-and-pull.sh- Secure image pull wrapper- Verifies signatures before pulling images
- Can be used as a
docker pullreplacement - Configurable via environment variables
Configuration#
-
trust-policy.yaml- Example trust policy configuration- Defines which DIDs to trust
- Specifies policies for different image scopes
- Includes audit logging and reporting settings
-
kubernetes-webhook.yaml- Kubernetes admission controller- Validates signatures before pod creation
- Includes webhook deployment, service, and configuration
- Uses trust policy ConfigMap
Quick Start#
1. Verify an Image#
# Make script executable
chmod +x atcr-verify.sh
# Verify an image
./atcr-verify.sh atcr.io/alice/myapp:latest
Output:
═══════════════════════════════════════════════════
ATProto Signature Verification
═══════════════════════════════════════════════════
Image: atcr.io/alice/myapp:latest
═══════════════════════════════════════════════════
[1/7] Resolving image digest...
→ sha256:abc123...
[2/7] Discovering ATProto signature artifacts...
→ Found 1 signature(s)
→ Signature digest: sha256:sig789...
→ Signed by DID: did:plc:alice123
[3/7] Fetching signature metadata...
→ DID: did:plc:alice123
→ Handle: alice.bsky.social
→ PDS: https://bsky.social
→ Record: at://did:plc:alice123/io.atcr.manifest/abc123
→ Signed at: 2025-10-31T12:34:56.789Z
[4/7] Resolving DID to public key...
→ Public key: zQ3shokFTS3brHcD...
[5/7] Querying PDS for signed record...
→ Record CID: bafyreig7...
[6/7] Verifying record integrity...
→ Record digest matches image digest
[7/7] Cryptographic signature verification...
⚠ Full cryptographic verification requires ATProto crypto library
═══════════════════════════════════════════════════
✓ Verification Completed
═══════════════════════════════════════════════════
Signed by: alice.bsky.social (did:plc:alice123)
Signed at: 2025-10-31T12:34:56.789Z
PDS: https://bsky.social
Record: at://did:plc:alice123/io.atcr.manifest/abc123
Signature: sha256:sig789...
═══════════════════════════════════════════════════
2. Secure Pull#
# Make script executable
chmod +x verify-and-pull.sh
# Pull image with verification
./verify-and-pull.sh atcr.io/alice/myapp:latest
# With Docker options
./verify-and-pull.sh atcr.io/alice/myapp:latest --platform linux/amd64
Create an alias for convenience:
# Add to ~/.bashrc or ~/.zshrc
alias docker-pull-secure='/path/to/verify-and-pull.sh'
# Use it
docker-pull-secure atcr.io/alice/myapp:latest
3. Deploy Kubernetes Webhook#
# 1. Generate TLS certificates for webhook
openssl req -x509 -newkey rsa:4096 -keyout tls.key -out tls.crt \
-days 365 -nodes -subj "/CN=atcr-verify-webhook.atcr-system.svc"
# 2. Create namespace and secret
kubectl create namespace atcr-system
kubectl create secret tls atcr-verify-webhook-certs \
--cert=tls.crt --key=tls.key -n atcr-system
# 3. Update CA bundle in kubernetes-webhook.yaml
cat tls.crt | base64 -w 0
# Copy output and replace caBundle in kubernetes-webhook.yaml
# 4. Deploy webhook
kubectl apply -f kubernetes-webhook.yaml
# 5. Enable verification for a namespace
kubectl label namespace production atcr-verify=enabled
# 6. Test with a pod
kubectl run test-pod --image=atcr.io/alice/myapp:latest -n production
Prerequisites#
For Scripts#
Install required tools:
macOS (Homebrew):
brew install curl jq crane oras
Linux (apt):
# curl and jq
sudo apt-get install curl jq
# crane
curl -sL "https://github.com/google/go-containerregistry/releases/download/v0.15.2/go-containerregistry_Linux_x86_64.tar.gz" | tar -xz crane
sudo mv crane /usr/local/bin/
# oras
curl -LO "https://github.com/oras-project/oras/releases/download/v1.0.0/oras_1.0.0_linux_amd64.tar.gz"
tar -xzf oras_1.0.0_linux_amd64.tar.gz
sudo mv oras /usr/local/bin/
For Kubernetes Webhook#
Requirements:
- Kubernetes cluster (1.16+)
kubectlconfigured- Permission to create namespaces and webhooks
- Webhook container image (build from source or use pre-built)
Configuration#
Environment Variables (verify-and-pull.sh)#
VERIFY_SCRIPT- Path to atcr-verify.sh (default: ./atcr-verify.sh)TRUST_POLICY- Path to trust policy (default: ./trust-policy.yaml)REQUIRE_VERIFICATION- Require verification (default: true)SKIP_ATCR_IMAGES- Skip verification for non-ATCR images (default: false)
Example:
# Skip verification for non-ATCR images
SKIP_ATCR_IMAGES=true ./verify-and-pull.sh docker.io/library/nginx:latest
# Allow pulling even if verification fails (NOT RECOMMENDED)
REQUIRE_VERIFICATION=false ./verify-and-pull.sh atcr.io/alice/myapp:latest
Trust Policy#
Edit trust-policy.yaml to customize:
-
Add your DIDs:
trustedDIDs: did:plc:your-did: name: "Your Name" validFrom: "2024-01-01T00:00:00Z" -
Define policies:
policies: - name: my-policy scope: "atcr.io/myorg/*" require: signature: true trustedDIDs: - did:plc:your-did action: enforce -
Use with verification:
# When atcr-verify CLI is available: atcr-verify IMAGE --policy trust-policy.yaml
Integration Patterns#
CI/CD (GitHub Actions)#
- name: Verify image signature
run: |
chmod +x examples/verification/atcr-verify.sh
./examples/verification/atcr-verify.sh ${{ env.IMAGE }}
- name: Deploy if verified
if: success()
run: kubectl set image deployment/app app=${{ env.IMAGE }}
CI/CD (GitLab CI)#
verify:
script:
- chmod +x examples/verification/atcr-verify.sh
- ./examples/verification/atcr-verify.sh $IMAGE
deploy:
dependencies: [verify]
script:
- kubectl set image deployment/app app=$IMAGE
Docker Alias#
# ~/.bashrc or ~/.zshrc
function docker() {
if [ "$1" = "pull" ] && [[ "$2" =~ ^atcr\.io/ ]]; then
echo "Using secure pull with signature verification..."
/path/to/verify-and-pull.sh "${@:2}"
else
command docker "$@"
fi
}
Systemd Service#
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=docker.service
[Service]
Type=oneshot
ExecStartPre=/path/to/verify-and-pull.sh atcr.io/myorg/myapp:latest
ExecStart=/usr/bin/docker run atcr.io/myorg/myapp:latest
Restart=on-failure
[Install]
WantedBy=multi-user.target
Troubleshooting#
"No ATProto signature found"#
Cause: Image doesn't have a signature artifact
Solutions:
- Check if image exists:
crane digest IMAGE - Re-push image to generate signature
- Verify referrers API is working:
curl "https://atcr.io/v2/REPO/referrers/DIGEST"
"Failed to resolve DID"#
Cause: DID resolution failed
Solutions:
- Check internet connectivity
- Verify DID is valid:
curl https://plc.directory/DID - Check if DID document has verificationMethod
"Failed to fetch record from PDS"#
Cause: PDS is unreachable or record doesn't exist
Solutions:
- Check PDS endpoint:
curl PDS_URL/xrpc/com.atproto.server.describeServer - Verify record URI is correct
- Check if record exists in PDS
Webhook Pods Don't Start#
Cause: Webhook is rejecting all pods
Solutions:
- Check webhook logs:
kubectl logs -n atcr-system -l app=atcr-verify-webhook - Disable webhook temporarily:
kubectl delete validatingwebhookconfiguration atcr-verify - Fix issue and re-deploy
- Test with labeled namespace first
Security Best Practices#
-
Always verify in production
- Enable webhook for production namespaces
- Set
failurePolicy: Failto block on errors
-
Use trust policies
- Define specific trusted DIDs
- Don't trust all signatures blindly
- Set expiration dates for temporary access
-
Monitor verification
- Enable audit logging
- Review verification failures
- Track signature coverage
-
Rotate keys regularly
- Update DID documents when keys change
- Revoke compromised keys immediately
- Monitor for unexpected key changes
-
Secure webhook deployment
- Use TLS for webhook communication
- Restrict webhook RBAC permissions
- Keep webhook image updated
Next Steps#
- Test verification with your images
- Customize trust policy for your organization
- Deploy webhook to test clusters first
- Monitor verification in CI/CD pipelines
- Gradually roll out to production
See Also#
- ATProto Signatures - Technical details
- Signature Integration - Integration guide
- SBOM Scanning - Similar ORAS pattern
Support#
For issues or questions:
- GitHub Issues: https://github.com/your-org/atcr/issues
- Documentation: https://docs.atcr.io
- Security: security@yourorg.com