A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
1# Image Signing with ATProto
2
3ATCR provides cryptographic verification of container images through ATProto's native signature system. Every manifest stored in a PDS is cryptographically signed, providing tamper-proof image verification.
4
5## Overview
6
7**Key Fact:** Every image pushed to ATCR is automatically signed via ATProto's repository commit signing. No additional signing tools or steps are required.
8
9When you push an image:
101. Manifest stored in your PDS as an `io.atcr.manifest` record
112. PDS signs the repository commit containing the manifest (ECDSA K-256)
123. Signature is part of the ATProto repository chain
134. Verification proves the manifest came from your DID and hasn't been tampered with
14
15**This document explains:**
16- How ATProto signatures work for ATCR images
17- How to verify signatures using standard and custom tools
18- Integration options for different use cases
19- When to use optional X.509 certificates (Hold-as-CA)
20
21## ATProto Signature Model
22
23### How It Works
24
25ATProto uses a **repository commit signing** model similar to Git:
26
27```
281. docker push atcr.io/alice/myapp:latest
29 ↓
302. AppView stores manifest in alice's PDS as io.atcr.manifest record
31 ↓
323. PDS creates repository commit containing the new record
33 ↓
344. PDS signs commit with alice's private key (ECDSA K-256)
35 ↓
365. Commit becomes part of alice's cryptographically signed repo chain
37```
38
39**What this proves:**
40- ✅ Manifest came from alice's PDS (DID-based identity)
41- ✅ Manifest content hasn't been tampered with
42- ✅ Manifest was created at a specific time (commit timestamp)
43- ✅ Manifest is part of alice's verifiable repository history
44
45**Trust model:**
46- Public keys distributed via DID documents (PLC directory, did:web)
47- Signatures use ECDSA K-256 (secp256k1)
48- Verification is decentralized (no central CA required)
49- Users control their own DIDs and can rotate keys
50
51### Signature Metadata
52
53In addition to ATProto's native commit signatures, ATCR creates **ORAS signature artifacts** that bridge ATProto signatures to the OCI ecosystem:
54
55```json
56{
57 "$type": "io.atcr.atproto.signature",
58 "version": "1.0",
59 "subject": {
60 "digest": "sha256:abc123...",
61 "mediaType": "application/vnd.oci.image.manifest.v1+json"
62 },
63 "atproto": {
64 "did": "did:plc:alice123",
65 "handle": "alice.bsky.social",
66 "pdsEndpoint": "https://bsky.social",
67 "recordUri": "at://did:plc:alice123/io.atcr.manifest/abc123",
68 "commitCid": "bafyreih8...",
69 "signedAt": "2025-10-31T12:34:56.789Z"
70 },
71 "signature": {
72 "algorithm": "ECDSA-K256-SHA256",
73 "keyId": "did:plc:alice123#atproto",
74 "publicKeyMultibase": "zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDdo1Ko4Z"
75 }
76}
77```
78
79**Stored as:**
80- OCI artifact with `artifactType: application/vnd.atproto.signature.v1+json`
81- Linked to image manifest via OCI Referrers API
82- Discoverable by standard OCI tools (ORAS, Cosign, Crane)
83
84## Verification
85
86### Quick Verification (Shell Script)
87
88For manual verification, use the provided shell scripts:
89
90```bash
91# Verify an image
92./examples/verification/atcr-verify.sh atcr.io/alice/myapp:latest
93
94# Output shows:
95# - DID and handle of signer
96# - PDS endpoint
97# - ATProto record URI
98# - Signature verification status
99```
100
101**See:** [examples/verification/README.md](../examples/verification/README.md) for complete examples including:
102- Standalone verification script
103- Secure pull wrapper (verify before pull)
104- Kubernetes webhook deployment
105- CI/CD integration examples
106
107### Standard Tools (Discovery Only)
108
109Standard OCI tools can **discover** ATProto signature artifacts but cannot **verify** them (different signature format):
110
111```bash
112# Discover signatures with ORAS
113oras discover atcr.io/alice/myapp:latest \
114 --artifact-type application/vnd.atproto.signature.v1+json
115
116# Fetch signature metadata
117oras pull atcr.io/alice/myapp@sha256:sig789...
118
119# View with Cosign (discovery only)
120cosign tree atcr.io/alice/myapp:latest
121```
122
123**Note:** Cosign/Notary cannot verify ATProto signatures directly because they use a different signature format and trust model. Use integration plugins or the `atcr-verify` CLI tool instead.
124
125## Integration Options
126
127ATCR supports multiple integration approaches depending on your use case:
128
129### 1. **Plugins (Recommended for Kubernetes)** ⭐
130
131Build plugins for existing policy/verification engines:
132
133**Ratify Verifier Plugin:**
134- Integrates with OPA Gatekeeper
135- Verifies ATProto signatures using Ratify's plugin interface
136- Policy-based enforcement for Kubernetes
137
138**OPA Gatekeeper External Provider:**
139- HTTP service that verifies ATProto signatures
140- Rego policies call external provider
141- Flexible and easy to deploy
142
143**Containerd 2.0 Bindir Plugin:**
144- Verifies signatures at containerd level
145- Works with any CRI-compatible runtime
146- No Kubernetes required
147
148**See:** [docs/SIGNATURE_INTEGRATION.md](./SIGNATURE_INTEGRATION.md) for complete plugin implementation examples
149
150### 2. **CLI Tool (atcr-verify)**
151
152Standalone CLI tool for signature verification:
153
154```bash
155# Install
156go install github.com/atcr-io/atcr/cmd/atcr-verify@latest
157
158# Verify image
159atcr-verify atcr.io/alice/myapp:latest --policy trust-policy.yaml
160
161# Use in CI/CD
162atcr-verify $IMAGE --quiet && kubectl apply -f deployment.yaml
163```
164
165**Features:**
166- Trust policy management (which DIDs to trust)
167- Multiple output formats (text, JSON, SARIF)
168- Offline verification with cached DID documents
169- Library usage for custom integrations
170
171**See:** [docs/ATCR_VERIFY_CLI.md](./ATCR_VERIFY_CLI.md) for complete CLI specification
172
173### 3. **External Services**
174
175Deploy verification as a service:
176
177**GitHub Actions:**
178```yaml
179- name: Verify image signature
180 uses: atcr-io/atcr-verify-action@v1
181 with:
182 image: atcr.io/alice/myapp:${{ github.sha }}
183 policy: .atcr/trust-policy.yaml
184```
185
186**GitLab CI, Jenkins, CircleCI:**
187- Use `atcr-verify` CLI in pipeline
188- Fail build if verification fails
189- Enforce signature requirements before deployment
190
191### 4. **X.509 Certificates (Hold-as-CA)** ⚠️
192
193Optional approach where hold services issue X.509 certificates based on ATProto signatures:
194
195**Use cases:**
196- Enterprise environments requiring PKI compliance
197- Tools that only support X.509 (legacy systems)
198- Notation integration (P-256 certificates)
199
200**Trade-offs:**
201- ❌ Introduces centralization (hold acts as CA)
202- ❌ Trust shifts from DIDs to hold operator
203- ❌ Requires hold service infrastructure
204
205**See:** [docs/HOLD_AS_CA.md](./HOLD_AS_CA.md) for complete architecture and security considerations
206
207## Integration Strategy Decision Matrix
208
209Choose the right integration approach:
210
211| Use Case | Recommended Approach | Priority |
212|----------|---------------------|----------|
213| **Kubernetes admission control** | Ratify plugin or Gatekeeper provider | HIGH |
214| **CI/CD verification** | atcr-verify CLI or GitHub Actions | HIGH |
215| **Docker/containerd** | Containerd bindir plugin | MEDIUM |
216| **Policy enforcement** | OPA Gatekeeper + external provider | HIGH |
217| **Manual verification** | Shell scripts or atcr-verify CLI | LOW |
218| **Enterprise PKI compliance** | Hold-as-CA (X.509 certificates) | OPTIONAL |
219| **Legacy tool support** | Hold-as-CA or external bridge service | OPTIONAL |
220
221**See:** [docs/INTEGRATION_STRATEGY.md](./INTEGRATION_STRATEGY.md) for complete integration planning guide including:
222- Architecture layers and data flow
223- Tool compatibility matrix (16+ tools)
224- Implementation roadmap (4 phases)
225- When to use each approach
226
227## Trust Policies
228
229Define which signatures you trust:
230
231```yaml
232# trust-policy.yaml
233version: 1.0
234
235trustedDIDs:
236 did:plc:alice123:
237 name: "Alice (DevOps Lead)"
238 validFrom: "2024-01-01T00:00:00Z"
239 expiresAt: null
240
241 did:plc:bob456:
242 name: "Bob (Security Team)"
243 validFrom: "2024-06-01T00:00:00Z"
244 expiresAt: "2025-12-31T23:59:59Z"
245
246policies:
247 - name: production-images
248 scope: "atcr.io/*/prod-*"
249 require:
250 signature: true
251 trustedDIDs:
252 - did:plc:alice123
253 - did:plc:bob456
254 minSignatures: 1
255 action: enforce # reject if policy fails
256
257 - name: dev-images
258 scope: "atcr.io/*/dev-*"
259 require:
260 signature: false
261 action: audit # log but don't reject
262```
263
264**Use with:**
265- `atcr-verify` CLI: `atcr-verify IMAGE --policy trust-policy.yaml`
266- Kubernetes webhooks: ConfigMap with policy
267- CI/CD pipelines: Fail build if policy not met
268
269## Security Considerations
270
271### What ATProto Signatures Prove
272
273✅ **Identity:** Manifest signed by specific DID (e.g., `did:plc:alice123`)
274✅ **Integrity:** Manifest content hasn't been tampered with
275✅ **Timestamp:** When the manifest was signed
276✅ **Authenticity:** Signature created with private key for that DID
277
278### What They Don't Prove
279
280❌ **Vulnerability-free:** Signature doesn't mean image is safe
281❌ **Authorization:** DID ownership doesn't imply permission to deploy
282❌ **Key security:** Private key could be compromised
283❌ **PDS trustworthiness:** Malicious PDS could create fake records
284
285### Trust Dependencies
286
287When verifying signatures, you're trusting:
2881. **DID resolution** (PLC directory, did:web) - public key is correct for DID
2892. **PDS integrity** - PDS serves correct records and doesn't forge signatures
2903. **Cryptographic primitives** - ECDSA K-256 remains secure
2914. **Your trust policy** - DIDs you've chosen to trust are legitimate
292
293### Best Practices
294
295**1. Use Trust Policies**
296Don't blindly trust all signatures - define which DIDs you trust:
297```yaml
298trustedDIDs:
299 - did:plc:your-org-team
300 - did:plc:your-ci-system
301```
302
303**2. Monitor Signature Coverage**
304Track which images have signatures:
305```bash
306atcr-verify --check-coverage namespace/production
307```
308
309**3. Enforce in Production**
310Use Kubernetes admission control to block unsigned images:
311```yaml
312# Ratify + Gatekeeper or custom webhook
313enforceSignatures: true
314failurePolicy: Fail
315```
316
317**4. Verify in CI/CD**
318Never deploy unsigned images:
319```yaml
320# GitHub Actions
321- name: Verify signature
322 run: atcr-verify $IMAGE || exit 1
323```
324
325**5. Plan for Compromised Keys**
326- Rotate DID keys periodically
327- Monitor DID documents for unexpected key changes
328- Have incident response plan for key compromise
329
330## Implementation Status
331
332### ✅ Available Now
333
334- **ATProto signatures**: All manifests automatically signed by PDS
335- **ORAS artifacts**: Signature metadata stored as OCI artifacts
336- **OCI Referrers API**: Discovery via standard OCI endpoints
337- **Shell scripts**: Manual verification examples
338- **Documentation**: Complete integration guides
339
340### 🔄 In Development
341
342- **atcr-verify CLI**: Standalone verification tool
343- **Ratify plugin**: Kubernetes integration
344- **Gatekeeper provider**: OPA policy enforcement
345- **GitHub Actions**: CI/CD integration
346
347### 📋 Planned
348
349- **Containerd plugin**: Runtime-level verification
350- **Hold-as-CA**: X.509 certificate generation (optional)
351- **Web UI**: Signature viewer in AppView
352- **Offline bundles**: Air-gapped verification
353
354## Comparison with Other Signing Solutions
355
356| Feature | ATCR (ATProto) | Cosign (Sigstore) | Notation (Notary v2) |
357|---------|---------------|-------------------|---------------------|
358| **Signing** | Automatic (PDS) | Manual or keyless | Manual |
359| **Keys** | K-256 (secp256k1) | P-256 or RSA | P-256, P-384, P-521 |
360| **Trust** | DID-based | OIDC + Fulcio CA | X.509 PKI |
361| **Storage** | ATProto PDS | OCI registry | OCI registry |
362| **Centralization** | Decentralized | Centralized (Fulcio) | Configurable |
363| **Transparency Log** | ATProto firehose | Rekor | Configurable |
364| **Verification** | Custom tools/plugins | Cosign CLI | Notation CLI |
365| **Kubernetes** | Plugins (Ratify) | Policy Controller | Policy Controller |
366
367**ATCR advantages:**
368- ✅ Decentralized trust (no CA required)
369- ✅ Automatic signing (no extra tools)
370- ✅ DID-based identity (portable, self-sovereign)
371- ✅ Transparent via ATProto firehose
372
373**ATCR trade-offs:**
374- ⚠️ Requires custom verification tools/plugins
375- ⚠️ K-256 not supported by Notation (needs Hold-as-CA)
376- ⚠️ Smaller ecosystem than Cosign/Notation
377
378## Why Not Use Cosign Directly?
379
380**Question:** Why not just integrate with Cosign's keyless signing (OIDC + Fulcio)?
381
382**Answer:** ATProto and Cosign use incompatible authentication models:
383
384| Requirement | Cosign Keyless | ATProto |
385|-------------|---------------|---------|
386| **Identity protocol** | OIDC | ATProto OAuth + DPoP |
387| **Token format** | JWT from OIDC provider | DPoP-bound access token |
388| **CA** | Fulcio (Sigstore CA) | None (DID-based PKI) |
389| **Infrastructure** | Fulcio + Rekor + TUF | PDS + DID resolver |
390
391**To make Cosign work, we'd need to:**
3921. Deploy Fulcio (certificate authority)
3932. Deploy Rekor (transparency log)
3943. Deploy TUF (metadata distribution)
3954. Build OIDC provider bridge for ATProto OAuth
3965. Maintain all this infrastructure
397
398**Instead:** We leverage ATProto's existing signatures and build lightweight plugins/tools for verification. This is simpler, more decentralized, and aligns with ATCR's design philosophy.
399
400**For tools that need X.509 certificates:** See [Hold-as-CA](./HOLD_AS_CA.md) for an optional centralized approach.
401
402## Getting Started
403
404### Verify Your First Image
405
406```bash
407# 1. Check if image has ATProto signature
408oras discover atcr.io/alice/myapp:latest \
409 --artifact-type application/vnd.atproto.signature.v1+json
410
411# 2. Pull signature metadata
412oras pull atcr.io/alice/myapp@sha256:sig789...
413
414# 3. Verify with shell script
415./examples/verification/atcr-verify.sh atcr.io/alice/myapp:latest
416
417# 4. Use atcr-verify CLI (when available)
418atcr-verify atcr.io/alice/myapp:latest --policy trust-policy.yaml
419```
420
421### Deploy Kubernetes Verification
422
423```bash
424# 1. Choose an approach
425# Option A: Ratify plugin (recommended)
426# Option B: Gatekeeper external provider
427# Option C: Custom admission webhook
428
429# 2. Follow integration guide
430# See docs/SIGNATURE_INTEGRATION.md for step-by-step
431
432# 3. Enable for namespace
433kubectl label namespace production atcr-verify=enabled
434
435# 4. Test with sample pod
436kubectl run test --image=atcr.io/alice/myapp:latest -n production
437```
438
439### Integrate with CI/CD
440
441```bash
442# GitHub Actions
443- name: Verify signature
444 run: |
445 curl -LO https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify
446 chmod +x atcr-verify
447 ./atcr-verify ${{ env.IMAGE }} --policy .atcr/trust-policy.yaml
448
449# GitLab CI
450verify_image:
451 script:
452 - wget https://github.com/atcr-io/atcr/releases/latest/download/atcr-verify
453 - chmod +x atcr-verify
454 - ./atcr-verify $IMAGE --policy .atcr/trust-policy.yaml
455```
456
457## Documentation
458
459### Core Documentation
460
461- **[ATProto Signatures](./ATPROTO_SIGNATURES.md)** - Technical deep-dive into signature format and verification
462- **[Signature Integration](./SIGNATURE_INTEGRATION.md)** - Tool-specific integration guides (Ratify, Gatekeeper, Containerd)
463- **[Integration Strategy](./INTEGRATION_STRATEGY.md)** - High-level overview and decision matrix
464- **[atcr-verify CLI](./ATCR_VERIFY_CLI.md)** - CLI tool specification and usage
465- **[Hold-as-CA](./HOLD_AS_CA.md)** - Optional X.509 certificate approach
466
467### Examples
468
469- **[examples/verification/](../examples/verification/)** - Shell scripts, Kubernetes configs, trust policies
470- **[examples/plugins/](../examples/plugins/)** - Plugin skeletons for Ratify, Gatekeeper, Containerd
471
472### External References
473
474- **ATProto:** https://atproto.com/specs/repository (repository commit signing)
475- **ORAS:** https://oras.land/ (artifact registry)
476- **OCI Referrers API:** https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers
477- **Ratify:** https://ratify.dev/ (verification framework)
478- **OPA Gatekeeper:** https://open-policy-agent.github.io/gatekeeper/
479
480## Support
481
482For questions or issues:
483- GitHub Issues: https://github.com/atcr-io/atcr/issues
484- Documentation: https://docs.atcr.io
485- Security: security@atcr.io
486
487## Summary
488
489**Key Points:**
490
4911. **Automatic signing**: Every ATCR image is automatically signed via ATProto's native signature system
4922. **No additional tools**: Signing happens transparently when you push images
4933. **Decentralized trust**: DID-based signatures, no central CA required
4944. **Standard discovery**: ORAS artifacts and OCI Referrers API for signature metadata
4955. **Custom verification**: Use plugins, CLI tools, or shell scripts (not Cosign directly)
4966. **Multiple integrations**: Kubernetes (Ratify, Gatekeeper), CI/CD (atcr-verify), containerd
4977. **Optional X.509**: Hold-as-CA for enterprise PKI compliance (centralized)
498
499**Next Steps:**
500
5011. Read [examples/verification/README.md](../examples/verification/README.md) for practical examples
5022. Choose integration approach from [INTEGRATION_STRATEGY.md](./INTEGRATION_STRATEGY.md)
5033. Implement plugin or deploy CLI tool from [SIGNATURE_INTEGRATION.md](./SIGNATURE_INTEGRATION.md)
5044. Define trust policy for your organization
5055. Deploy to test environment first, then production