A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
0
fork

Configure Feed

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

at refactor 728 lines 16 kB view raw view rendered
1# atcr-verify CLI Tool 2 3## Overview 4 5`atcr-verify` is a command-line tool for verifying ATProto signatures on container images stored in ATCR. It provides cryptographic verification of image manifests using ATProto's DID-based trust model. 6 7## Features 8 9- ✅ Verify ATProto signatures via OCI Referrers API 10- ✅ DID resolution and public key extraction 11- ✅ PDS query and commit signature verification 12- ✅ Trust policy enforcement 13- ✅ Offline verification mode (with cached data) 14- ✅ Multiple output formats (human-readable, JSON, quiet) 15- ✅ Exit codes for CI/CD integration 16- ✅ Kubernetes admission controller integration 17 18## Installation 19 20### Binary Release 21 22```bash 23# Linux (x86_64) 24curl -L https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify-linux-amd64 -o atcr-verify 25chmod +x atcr-verify 26sudo mv atcr-verify /usr/local/bin/ 27 28# macOS (Apple Silicon) 29curl -L https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify-darwin-arm64 -o atcr-verify 30chmod +x atcr-verify 31sudo mv atcr-verify /usr/local/bin/ 32 33# Windows 34curl -L https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify-windows-amd64.exe -o atcr-verify.exe 35``` 36 37### From Source 38 39```bash 40git clone https://github.com/atcr-io/atcr.git 41cd atcr 42go install ./cmd/atcr-verify 43``` 44 45### Container Image 46 47```bash 48docker pull atcr.io/atcr/verify:latest 49 50# Run 51docker run --rm atcr.io/atcr/verify:latest verify IMAGE 52``` 53 54## Usage 55 56### Basic Verification 57 58```bash 59# Verify an image 60atcr-verify atcr.io/alice/myapp:latest 61 62# Output: 63# ✓ Image verified successfully 64# Signed by: alice.bsky.social (did:plc:alice123) 65# Signed at: 2025-10-31T12:34:56.789Z 66``` 67 68### With Trust Policy 69 70```bash 71# Verify against trust policy 72atcr-verify atcr.io/alice/myapp:latest --policy trust-policy.yaml 73 74# Output: 75# ✓ Image verified successfully 76# ✓ Trust policy satisfied 77# Policy: production-images 78# Trusted DID: did:plc:alice123 79``` 80 81### JSON Output 82 83```bash 84atcr-verify atcr.io/alice/myapp:latest --output json 85 86# Output: 87{ 88 "verified": true, 89 "image": "atcr.io/alice/myapp:latest", 90 "digest": "sha256:abc123...", 91 "signature": { 92 "did": "did:plc:alice123", 93 "handle": "alice.bsky.social", 94 "pds": "https://bsky.social", 95 "recordUri": "at://did:plc:alice123/io.atcr.manifest/abc123", 96 "commitCid": "bafyreih8...", 97 "signedAt": "2025-10-31T12:34:56.789Z", 98 "algorithm": "ECDSA-K256-SHA256" 99 }, 100 "trustPolicy": { 101 "satisfied": true, 102 "policy": "production-images", 103 "trustedDID": true 104 } 105} 106``` 107 108### Quiet Mode 109 110```bash 111# Exit code only (for scripts) 112atcr-verify atcr.io/alice/myapp:latest --quiet 113echo $? # 0 = verified, 1 = failed 114``` 115 116### Offline Mode 117 118```bash 119# Export verification bundle 120atcr-verify export atcr.io/alice/myapp:latest -o bundle.json 121 122# Verify offline (in air-gapped environment) 123atcr-verify atcr.io/alice/myapp:latest --offline --bundle bundle.json 124``` 125 126## Command Reference 127 128### verify 129 130Verify ATProto signature for an image. 131 132```bash 133atcr-verify verify IMAGE [flags] 134atcr-verify IMAGE [flags] # 'verify' subcommand is optional 135``` 136 137**Arguments:** 138- `IMAGE` - Image reference (registry/owner/repo:tag or @digest) 139 140**Flags:** 141- `--policy FILE` - Trust policy file (default: none) 142- `--output FORMAT` - Output format: text, json, quiet (default: text) 143- `--offline` - Offline mode (requires --bundle) 144- `--bundle FILE` - Verification bundle for offline mode 145- `--cache-dir DIR` - Cache directory for DID documents (default: ~/.atcr/cache) 146- `--no-cache` - Disable caching 147- `--timeout DURATION` - Verification timeout (default: 30s) 148- `--verbose` - Verbose output 149 150**Exit Codes:** 151- `0` - Verification succeeded 152- `1` - Verification failed 153- `2` - Invalid arguments 154- `3` - Network error 155- `4` - Trust policy violation 156 157**Examples:** 158 159```bash 160# Basic verification 161atcr-verify atcr.io/alice/myapp:latest 162 163# With specific digest 164atcr-verify atcr.io/alice/myapp@sha256:abc123... 165 166# With trust policy 167atcr-verify atcr.io/alice/myapp:latest --policy production-policy.yaml 168 169# JSON output for scripting 170atcr-verify atcr.io/alice/myapp:latest --output json | jq .verified 171 172# Quiet mode for CI/CD 173if atcr-verify atcr.io/alice/myapp:latest --quiet; then 174 echo "Deploy approved" 175fi 176``` 177 178### export 179 180Export verification bundle for offline verification. 181 182```bash 183atcr-verify export IMAGE [flags] 184``` 185 186**Arguments:** 187- `IMAGE` - Image reference to export bundle for 188 189**Flags:** 190- `-o, --output FILE` - Output file (default: stdout) 191- `--include-did-docs` - Include DID documents in bundle 192- `--include-commit` - Include ATProto commit data 193 194**Examples:** 195 196```bash 197# Export to file 198atcr-verify export atcr.io/alice/myapp:latest -o myapp-bundle.json 199 200# Export with all verification data 201atcr-verify export atcr.io/alice/myapp:latest \ 202 --include-did-docs \ 203 --include-commit \ 204 -o complete-bundle.json 205 206# Export for multiple images 207for img in $(cat images.txt); do 208 atcr-verify export $img -o bundles/$(echo $img | tr '/:' '_').json 209done 210``` 211 212### trust 213 214Manage trust policies and trusted DIDs. 215 216```bash 217atcr-verify trust COMMAND [flags] 218``` 219 220**Subcommands:** 221 222**`trust list`** - List trusted DIDs 223```bash 224atcr-verify trust list 225 226# Output: 227# Trusted DIDs: 228# - did:plc:alice123 (alice.bsky.social) 229# - did:plc:bob456 (bob.example.com) 230``` 231 232**`trust add DID`** - Add trusted DID 233```bash 234atcr-verify trust add did:plc:alice123 235atcr-verify trust add did:plc:alice123 --name "Alice (DevOps)" 236``` 237 238**`trust remove DID`** - Remove trusted DID 239```bash 240atcr-verify trust remove did:plc:alice123 241``` 242 243**`trust policy validate`** - Validate trust policy file 244```bash 245atcr-verify trust policy validate policy.yaml 246``` 247 248### version 249 250Show version information. 251 252```bash 253atcr-verify version 254 255# Output: 256# atcr-verify version 1.0.0 257# Go version: go1.21.5 258# Commit: 3b5b89b 259# Built: 2025-10-31T12:00:00Z 260``` 261 262## Trust Policy 263 264Trust policies define which signatures to trust and what to do when verification fails. 265 266### Policy File Format 267 268```yaml 269version: 1.0 270 271# Global settings 272defaultAction: enforce # enforce, audit, allow 273requireSignature: true 274 275# Policies matched by image pattern (first match wins) 276policies: 277 - name: production-images 278 description: "Production images must be signed by DevOps or Security" 279 scope: "atcr.io/*/prod-*" 280 require: 281 signature: true 282 trustedDIDs: 283 - did:plc:devops-team 284 - did:plc:security-team 285 minSignatures: 1 286 maxAge: 2592000 # 30 days in seconds 287 action: enforce 288 289 - name: staging-images 290 scope: "atcr.io/*/staging-*" 291 require: 292 signature: true 293 trustedDIDs: 294 - did:plc:devops-team 295 - did:plc:developers 296 minSignatures: 1 297 action: enforce 298 299 - name: dev-images 300 scope: "atcr.io/*/dev-*" 301 require: 302 signature: false 303 action: audit # Log but don't fail 304 305# Trusted DID registry 306trustedDIDs: 307 did:plc:devops-team: 308 name: "DevOps Team" 309 validFrom: "2024-01-01T00:00:00Z" 310 expiresAt: null 311 contact: "devops@example.com" 312 313 did:plc:security-team: 314 name: "Security Team" 315 validFrom: "2024-01-01T00:00:00Z" 316 expiresAt: null 317 318 did:plc:developers: 319 name: "Developer Team" 320 validFrom: "2024-06-01T00:00:00Z" 321 expiresAt: "2025-12-31T23:59:59Z" 322``` 323 324### Policy Matching 325 326Policies are evaluated in order. First match wins. 327 328**Scope patterns:** 329- `atcr.io/*/*` - All ATCR images 330- `atcr.io/myorg/*` - All images from myorg 331- `atcr.io/*/prod-*` - All images with "prod-" prefix 332- `atcr.io/myorg/myapp` - Specific repository 333- `atcr.io/myorg/myapp:v*` - Tag pattern matching 334 335### Policy Actions 336 337**`enforce`** - Reject if policy fails 338- Exit code 4 339- Blocks deployment 340 341**`audit`** - Log but allow 342- Exit code 0 (success) 343- Warning message printed 344 345**`allow`** - Always allow 346- No verification performed 347- Exit code 0 348 349### Policy Requirements 350 351**`signature: true`** - Require signature present 352 353**`trustedDIDs`** - List of trusted DIDs 354```yaml 355trustedDIDs: 356 - did:plc:alice123 357 - did:web:example.com 358``` 359 360**`minSignatures`** - Minimum number of signatures required 361```yaml 362minSignatures: 2 # Require 2 signatures 363``` 364 365**`maxAge`** - Maximum signature age in seconds 366```yaml 367maxAge: 2592000 # 30 days 368``` 369 370**`algorithms`** - Allowed signature algorithms 371```yaml 372algorithms: 373 - ECDSA-K256-SHA256 374``` 375 376## Verification Flow 377 378### 1. Image Resolution 379 380``` 381Input: atcr.io/alice/myapp:latest 382383Resolve tag to digest 384385Output: sha256:abc123... 386``` 387 388### 2. Signature Discovery 389 390``` 391Query OCI Referrers API: 392 GET /v2/alice/myapp/referrers/sha256:abc123 393 ?artifactType=application/vnd.atproto.signature.v1+json 394395Returns: List of signature artifacts 396397Download signature metadata blobs 398``` 399 400### 3. DID Resolution 401 402``` 403Extract DID from signature: did:plc:alice123 404405Query PLC directory: 406 GET https://plc.directory/did:plc:alice123 407408Extract public key from DID document 409``` 410 411### 4. PDS Query 412 413``` 414Get PDS endpoint from DID document 415416Query for manifest record: 417 GET {pds}/xrpc/com.atproto.repo.getRecord 418 ?repo=did:plc:alice123 419 &collection=io.atcr.manifest 420 &rkey=abc123 421422Get commit CID from record 423424Fetch commit data (includes signature) 425``` 426 427### 5. Signature Verification 428 429``` 430Extract signature bytes from commit 431432Compute commit hash (SHA-256) 433434Verify: ECDSA_K256(hash, signature, publicKey) 435436Result: Valid or Invalid 437``` 438 439### 6. Trust Policy Evaluation 440 441``` 442Check if DID is in trustedDIDs list 443444Check signature age < maxAge 445446Check minSignatures satisfied 447448Apply policy action (enforce/audit/allow) 449``` 450 451## Integration Examples 452 453### CI/CD Pipeline 454 455**GitHub Actions:** 456```yaml 457name: Deploy 458 459on: 460 push: 461 branches: [main] 462 463jobs: 464 verify-and-deploy: 465 runs-on: ubuntu-latest 466 steps: 467 - name: Install atcr-verify 468 run: | 469 curl -L https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify-linux-amd64 -o atcr-verify 470 chmod +x atcr-verify 471 sudo mv atcr-verify /usr/local/bin/ 472 473 - name: Verify image signature 474 run: | 475 atcr-verify ${{ env.IMAGE }} --policy .github/trust-policy.yaml 476 477 - name: Deploy to production 478 if: success() 479 run: kubectl set image deployment/app app=${{ env.IMAGE }} 480``` 481 482**GitLab CI:** 483```yaml 484verify: 485 stage: verify 486 image: atcr.io/atcr/verify:latest 487 script: 488 - atcr-verify ${IMAGE} --policy trust-policy.yaml 489 490deploy: 491 stage: deploy 492 dependencies: 493 - verify 494 script: 495 - kubectl set image deployment/app app=${IMAGE} 496``` 497 498**Jenkins:** 499```groovy 500pipeline { 501 agent any 502 503 stages { 504 stage('Verify') { 505 steps { 506 sh 'atcr-verify ${IMAGE} --policy trust-policy.yaml' 507 } 508 } 509 510 stage('Deploy') { 511 when { 512 expression { currentBuild.result == 'SUCCESS' } 513 } 514 steps { 515 sh 'kubectl set image deployment/app app=${IMAGE}' 516 } 517 } 518 } 519} 520``` 521 522### Kubernetes Admission Controller 523 524**Using as webhook backend:** 525 526```go 527// webhook server 528func (h *Handler) ValidatePod(w http.ResponseWriter, r *http.Request) { 529 var admReq admissionv1.AdmissionReview 530 json.NewDecoder(r.Body).Decode(&admReq) 531 532 pod := &corev1.Pod{} 533 json.Unmarshal(admReq.Request.Object.Raw, pod) 534 535 // Verify each container image 536 for _, container := range pod.Spec.Containers { 537 cmd := exec.Command("atcr-verify", container.Image, 538 "--policy", "/etc/atcr/trust-policy.yaml", 539 "--quiet") 540 541 if err := cmd.Run(); err != nil { 542 // Verification failed 543 admResp := admissionv1.AdmissionReview{ 544 Response: &admissionv1.AdmissionResponse{ 545 UID: admReq.Request.UID, 546 Allowed: false, 547 Result: &metav1.Status{ 548 Message: fmt.Sprintf("Image %s failed signature verification", container.Image), 549 }, 550 }, 551 } 552 json.NewEncoder(w).Encode(admResp) 553 return 554 } 555 } 556 557 // All images verified 558 admResp := admissionv1.AdmissionReview{ 559 Response: &admissionv1.AdmissionResponse{ 560 UID: admReq.Request.UID, 561 Allowed: true, 562 }, 563 } 564 json.NewEncoder(w).Encode(admResp) 565} 566``` 567 568### Pre-Pull Verification 569 570**Systemd service:** 571```ini 572# /etc/systemd/system/myapp.service 573[Unit] 574Description=My Application 575After=docker.service 576 577[Service] 578Type=oneshot 579ExecStartPre=/usr/local/bin/atcr-verify atcr.io/myorg/myapp:latest --policy /etc/atcr/policy.yaml 580ExecStartPre=/usr/bin/docker pull atcr.io/myorg/myapp:latest 581ExecStart=/usr/bin/docker run atcr.io/myorg/myapp:latest 582Restart=on-failure 583 584[Install] 585WantedBy=multi-user.target 586``` 587 588**Docker wrapper script:** 589```bash 590#!/bin/bash 591# docker-secure-pull.sh 592 593IMAGE="$1" 594 595# Verify before pulling 596if ! atcr-verify "$IMAGE" --policy ~/.atcr/trust-policy.yaml; then 597 echo "ERROR: Image signature verification failed" 598 exit 1 599fi 600 601# Pull if verified 602docker pull "$IMAGE" 603``` 604 605## Configuration 606 607### Config File 608 609Location: `~/.atcr/config.yaml` 610 611```yaml 612# Default trust policy 613defaultPolicy: ~/.atcr/trust-policy.yaml 614 615# Cache settings 616cache: 617 enabled: true 618 directory: ~/.atcr/cache 619 ttl: 620 didDocuments: 3600 # 1 hour 621 commits: 600 # 10 minutes 622 623# Network settings 624timeout: 30s 625retries: 3 626 627# Output settings 628output: 629 format: text # text, json, quiet 630 color: auto # auto, always, never 631 632# Registry settings 633registries: 634 atcr.io: 635 insecure: false 636 credentialsFile: ~/.docker/config.json 637``` 638 639### Environment Variables 640 641- `ATCR_CONFIG` - Config file path 642- `ATCR_POLICY` - Default trust policy file 643- `ATCR_CACHE_DIR` - Cache directory 644- `ATCR_OUTPUT` - Output format (text, json, quiet) 645- `ATCR_TIMEOUT` - Verification timeout 646- `HTTP_PROXY` / `HTTPS_PROXY` - Proxy settings 647- `NO_CACHE` - Disable caching 648 649## Library Usage 650 651`atcr-verify` can also be used as a Go library: 652 653```go 654import "github.com/atcr-io/atcr/pkg/verify" 655 656func main() { 657 verifier := verify.NewVerifier(verify.Config{ 658 Policy: policy, 659 Timeout: 30 * time.Second, 660 }) 661 662 result, err := verifier.Verify(ctx, "atcr.io/alice/myapp:latest") 663 if err != nil { 664 log.Fatal(err) 665 } 666 667 if !result.Verified { 668 log.Fatal("Verification failed") 669 } 670 671 fmt.Printf("Verified by %s\n", result.Signature.DID) 672} 673``` 674 675## Performance 676 677### Typical Verification Times 678 679- **First verification:** 500-1000ms 680 - OCI Referrers API: 50-100ms 681 - DID resolution: 50-150ms 682 - PDS query: 100-300ms 683 - Signature verification: 1-5ms 684 685- **Cached verification:** 50-150ms 686 - DID document cached 687 - Signature metadata cached 688 689### Optimization Tips 690 6911. **Enable caching** - DID documents change rarely 6922. **Use offline bundles** - For air-gapped environments 6933. **Parallel verification** - Verify multiple images concurrently 6944. **Local trust policy** - Avoid remote policy fetches 695 696## Troubleshooting 697 698### Verification Fails 699 700```bash 701atcr-verify atcr.io/alice/myapp:latest --verbose 702``` 703 704Common issues: 705- **No signature found** - Image not signed, check Referrers API 706- **DID resolution failed** - Network issue, check PLC directory 707- **PDS unreachable** - Network issue, check PDS endpoint 708- **Signature invalid** - Tampering detected or key mismatch 709- **Trust policy violation** - DID not in trusted list 710 711### Enable Debug Logging 712 713```bash 714ATCR_LOG_LEVEL=debug atcr-verify IMAGE 715``` 716 717### Clear Cache 718 719```bash 720rm -rf ~/.atcr/cache 721``` 722 723## See Also 724 725- [ATProto Signatures](./ATPROTO_SIGNATURES.md) - How ATProto signing works 726- [Integration Strategy](./INTEGRATION_STRATEGY.md) - Overview of integration approaches 727- [Signature Integration](./SIGNATURE_INTEGRATION.md) - Tool-specific guides 728- [Trust Policy Examples](../examples/verification/trust-policy.yaml)