|
8 | 8 | <img src="https://img.shields.io/badge/python-%3E%3D3.11-3776AB.svg?logo=python&logoColor=white" alt="Python"> |
9 | 9 | <img src="https://img.shields.io/badge/platform-Debian%2FUbuntu-A81D33.svg?logo=debian&logoColor=white" alt="Platform"> |
10 | 10 | <img src="https://img.shields.io/badge/packaging-.deb-orange.svg" alt="Packaging"> |
11 | | - <img src="https://img.shields.io/badge/status-v0.8.1-brightgreen.svg" alt="Status"> |
12 | | - <img src="https://img.shields.io/badge/coverage-%E2%89%A580%25-brightgreen.svg" alt="Coverage"> |
| 11 | + <img src="https://img.shields.io/badge/status-v0.9.0-brightgreen.svg" alt="Status"> |
| 12 | + <img src="https://img.shields.io/badge/coverage-%E2%89%A590%25-brightgreen.svg" alt="Coverage"> |
13 | 13 | </p> |
14 | 14 |
|
15 | 15 | --- |
@@ -74,10 +74,10 @@ Download the latest `.deb` files from [GitHub Releases](https://github.com/Rwx-G |
74 | 74 |
|
75 | 75 | ```bash |
76 | 76 | # Offline machine |
77 | | -sudo dpkg -i buncker_0.8.1_all.deb |
| 77 | +sudo dpkg -i buncker_0.9.0_all.deb |
78 | 78 |
|
79 | 79 | # Online machine |
80 | | -sudo dpkg -i buncker-fetch_0.8.1_all.deb |
| 80 | +sudo dpkg -i buncker-fetch_0.9.0_all.deb |
81 | 81 | ``` |
82 | 82 |
|
83 | 83 | If dependencies are missing, fix them with: |
@@ -140,13 +140,18 @@ without manual re-entry. |
140 | 140 |
|
141 | 141 | The operator works directly on the buncker server. Transfers go through USB. |
142 | 142 |
|
143 | | -**1. Analyze a Dockerfile and generate a transfer request** |
| 143 | +**1. Prepare a transfer request from a Dockerfile** |
144 | 144 |
|
145 | 145 | ```bash |
146 | | -buncker analyze ./Dockerfile --build-arg NODE_VERSION=20 |
147 | | -buncker generate-manifest --output /media/usb/ |
| 146 | +buncker prepare ./Dockerfile --build-arg NODE_VERSION=20 --output /media/usb/ |
| 147 | +# Combines analyze + generate-manifest in one step |
148 | 148 | ``` |
149 | 149 |
|
| 150 | +This analyzes the Dockerfile, identifies missing layers, and writes the |
| 151 | +encrypted transfer request to the USB drive in a single command. |
| 152 | +You can also run `buncker analyze` and `buncker generate-manifest` separately |
| 153 | +if you need to inspect the analysis before generating the request. |
| 154 | + |
150 | 155 | **2. Online machine - pair and fetch** |
151 | 156 |
|
152 | 157 | ```bash |
@@ -328,8 +333,9 @@ references as in Approach 1. |
328 | 333 | | `buncker generate-manifest` | Generate an encrypted transfer request | |
329 | 334 | | `buncker import [file.tar.enc]` | Import an encrypted transfer response (auto-scans `transfer_path` if omitted, `--cleanup` deletes file after success) | |
330 | 335 | | `buncker status` | Show registry status (blob count, store size) | |
| 336 | +| `buncker verify` | Re-hash all blobs and detect silent corruption (bit-rot) | |
331 | 337 | | `buncker gc --report` | List inactive blobs eligible for garbage collection | |
332 | | -| `buncker gc --execute` | Delete reported inactive blobs | |
| 338 | +| `buncker gc --execute` | Delete reported inactive blobs (requires `--yes` or interactive confirmation) | |
333 | 339 | | `buncker rotate-keys` | Generate a new mnemonic and deprecate old keys | |
334 | 340 | | `buncker export-ca` | Print CA certificate to stdout (TLS mode only) | |
335 | 341 | | `buncker api-setup` | Generate API tokens and activate TLS for LAN access | |
@@ -369,6 +375,7 @@ references as in Approach 1. |
369 | 375 | | `--output <path>` | Output directory for `fetch` response | |
370 | 376 | | `--parallelism N` | Parallel downloads for `fetch` (default: 4) | |
371 | 377 | | `--older-than Nd` | Cache clean threshold (default: `30d`) | |
| 378 | +| `--deb <path>` | Include a `.deb` update file in the `fetch` response | |
372 | 379 |
|
373 | 380 | ## Maintenance |
374 | 381 |
|
@@ -423,6 +430,72 @@ sudo tail -f /var/log/buncker/buncker.log |
423 | 430 | sudo journalctl -u buncker -f |
424 | 431 | ``` |
425 | 432 |
|
| 433 | +## Security Hardening |
| 434 | + |
| 435 | +### Mnemonic storage (`/etc/buncker/env`) |
| 436 | + |
| 437 | +`buncker setup` encrypts the mnemonic with a PBKDF2-derived key from |
| 438 | +`/etc/machine-id` and stores the ciphertext as `BUNCKER_MNEMONIC_ENC=<base64>` |
| 439 | +in `/etc/buncker/env` (mode 0600, owned by root). The daemon decrypts it |
| 440 | +automatically on startup. This prevents direct exposure if the file is |
| 441 | +read by an attacker without access to the machine-id. |
| 442 | + |
| 443 | +On sensitive deployments, consider additional protections: |
| 444 | + |
| 445 | +- **LUKS encryption** - place the buncker data directory on a LUKS |
| 446 | + encrypted partition for full at-rest protection |
| 447 | +- **TPM-backed encryption** - use `systemd-creds` or `clevis` to seal |
| 448 | + `/etc/buncker/env` to the machine's TPM, so it can only be decrypted |
| 449 | + on that specific host |
| 450 | +- **Manual entry** - remove `/etc/buncker/env` and enter the mnemonic via |
| 451 | + stdin on each daemon start (set `BUNCKER_MNEMONIC` env or pipe it). |
| 452 | + This provides the strongest protection but requires manual intervention |
| 453 | + on every restart |
| 454 | + |
| 455 | +### Backup and recovery |
| 456 | + |
| 457 | +Buncker state consists of the blob store and configuration files. To back up: |
| 458 | + |
| 459 | +```bash |
| 460 | +# Back up store and config |
| 461 | +rsync -a /var/lib/buncker/ /backup/buncker-store/ |
| 462 | +rsync -a /etc/buncker/ /backup/buncker-config/ |
| 463 | +``` |
| 464 | + |
| 465 | +To restore, copy the files back and restart the daemon. |
| 466 | + |
| 467 | +**Mnemonic recovery**: if the mnemonic is lost and `/etc/buncker/env` is |
| 468 | +unavailable, the only option is `buncker rotate-keys` to generate a new |
| 469 | +mnemonic. There is no way to extract the original mnemonic from the config. |
| 470 | +After rotation, re-pair the online machine with `buncker-fetch pair`. |
| 471 | + |
| 472 | +### OCI endpoints (`/v2/*`) are unauthenticated |
| 473 | + |
| 474 | +The OCI Distribution API endpoints (`/v2/`, `/v2/<name>/manifests/`, |
| 475 | +`/v2/<name>/blobs/`) are always unauthenticated, even when API auth is |
| 476 | +enabled. This is by design - Docker clients need direct access to pull |
| 477 | +images without Bearer token configuration. |
| 478 | + |
| 479 | +**Implications:** |
| 480 | + |
| 481 | +- Any machine on the offline LAN can pull images from buncker |
| 482 | +- Image content is not confidential in most air-gapped scenarios (the |
| 483 | + threat model protects integrity and provenance, not secrecy) |
| 484 | +- If you need to restrict OCI access, use network-level controls |
| 485 | + (firewall rules, VLAN segmentation) to limit which hosts can reach |
| 486 | + port 5000 |
| 487 | + |
| 488 | +### Admin API protection |
| 489 | + |
| 490 | +When API auth is enabled (`buncker api-setup`): |
| 491 | + |
| 492 | +- TLS is mandatory (the daemon refuses to start without it) |
| 493 | +- Admin endpoints require the admin token (analyze, import, GC execute) |
| 494 | +- Read-only endpoints accept either token (status, logs, health, GC report) |
| 495 | +- Token values are never logged (only `auth_level` appears in audit trail) |
| 496 | +- All admin API calls are logged with `client_ip`, `auth_level`, and |
| 497 | + `user_agent` for forensic review |
| 498 | + |
426 | 499 | ## Troubleshooting |
427 | 500 |
|
428 | 501 | | Problem | Cause | Solution | |
@@ -465,14 +538,21 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for full development setup and guidelines |
465 | 538 |
|
466 | 539 | | Feature | Description | Status | |
467 | 540 | |---------|-------------|--------| |
468 | | -| Import cleanup flag | `--cleanup` flag on `buncker import` to delete .tar.enc after successful import | Done | |
469 | | -| Streamlined `api-setup` | Auto-export ca.pem to `/etc/buncker/ca.pem` and display cert fingerprint during setup | Done | |
470 | | -| Disk space in `status` | Show store disk usage and available space in `buncker status` and `/admin/status` | Done | |
471 | | -| Health-check endpoint | `/admin/health` returning store integrity, cert expiry, and disk space | Planned | |
472 | | -| Store integrity check | `buncker verify` command to re-hash all blobs and detect silent corruption (bit-rot) | Planned | |
473 | | -| GC impact report | `gc --report` shows which images become non-pullable if candidates are deleted | Planned | |
474 | | -| Fetch rate limiting | Auto-pace blob downloads based on registry `RateLimit-*` headers | Planned | |
475 | | -| Manifest auto-refresh | buncker-fetch re-downloads manifests on every fetch and warns if upstream digest changed | Planned | |
| 541 | +| API auth & LAN clients | Bearer tokens (admin + readonly), TLS, endpoint access control, audit trail | Done | |
| 542 | +| Remote operations | curl-based analyze, generate-manifest download, PUT streaming import with resume | Done | |
| 543 | +| Health-check endpoint | `/admin/health` returning store integrity, cert expiry, and disk space | Done | |
| 544 | +| Store integrity check | `buncker verify` command to re-hash all blobs and detect silent corruption (bit-rot) | Done | |
| 545 | +| GC impact report | `gc --report` shows which images become non-pullable if candidates are deleted | Done | |
| 546 | +| GC execute confirmation | `gc --execute` requires `--yes` flag or interactive confirmation to prevent accidents | Done | |
| 547 | +| Fetch rate limiting | Auto-pace blob downloads based on registry `RateLimit-*` headers | Done | |
| 548 | +| Manifest auto-refresh | buncker-fetch re-downloads manifests on every fetch and warns if upstream digest changed | Done | |
| 549 | +| Resolver ARG edge cases | Support for `${VAR:-default}` and `${VAR:+replacement}` syntax, complex `--platform` patterns | Done | |
| 550 | +| Security hardening docs | Document `/etc/buncker/env` encryption recommendations and `/v2/*` unauthenticated access risks | Done | |
| 551 | +| Quick start with `prepare` | Feature `buncker prepare` in main README workflow instead of separate analyze + generate-manifest | Done | |
| 552 | +| Docker Compose support | `buncker analyze --compose docker-compose.yml` to extract all images from multi-service projects | Planned | |
| 553 | +| .deb GPG signature verification | Verify GPG signature on `.deb` updates included in transfer responses before installation | Planned | |
| 554 | +| Log rotation | Built-in log rotation policy or logrotate config for `/var/log/buncker/` | Planned | |
| 555 | +| buncker-fetch on Windows | PyInstaller binary or WSL2 documentation for online-side Windows operators | Planned | |
476 | 556 |
|
477 | 557 | ## License |
478 | 558 |
|
|
0 commit comments