unix:freebsd:system_builds:airgap:sneakernet_implementation
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| unix:freebsd:system_builds:airgap:sneakernet_implementation [2026/01/20 01:42] – [Support] rodolico | unix:freebsd:system_builds:airgap:sneakernet_implementation [2026/02/06 00:37] (current) – rodolico | ||
|---|---|---|---|
| Line 17: | Line 17: | ||
| * Multi-layer encryption (GELI + symmetric transport) | * Multi-layer encryption (GELI + symmetric transport) | ||
| * Split-key architecture preventing single-point compromise | * Split-key architecture preventing single-point compromise | ||
| + | * Maintenance mode flag to pause replication | ||
| + | * Monthly cleanup script scheduling (built-in) | ||
| + | * Size tracking and max-delta validation before transfer | ||
| * Automated maintenance script execution | * Automated maintenance script execution | ||
| * Comprehensive reporting and audit trails | * Comprehensive reporting and audit trails | ||
| Line 26: | Line 29: | ||
| ^ Requirement ^ Implementation ^ | ^ Requirement ^ Implementation ^ | ||
| - | | Replication Schedule | Monthly updates from in-house backup server to air gap server | | + | | Replication Schedule | Monthly updates from in-house backup server to air gap server |
| | Transport Media | 3× 1.9TB SSD drives in rotation | | | Transport Media | 3× 1.9TB SSD drives in rotation | | ||
| | Drive Rotation | One at source, one at target, one in transit — minimizes site visits | | | Drive Rotation | One at source, one at target, one in transit — minimizes site visits | | ||
| Line 54: | Line 57: | ||
| ==== Prerequisites ==== | ==== Prerequisites ==== | ||
| - | * FreeBSD 13.0 or later | + | * FreeBSD 13.0 or later (or Linux with ZFS) |
| * ZFS filesystem | * ZFS filesystem | ||
| - | * Perl 5.28 or later | + | * Perl 5.10 or later |
| * OpenSSL | * OpenSSL | ||
| * '' | * '' | ||
| Line 86: | Line 89: | ||
| * '' | * '' | ||
| * '' | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| Example minimal configuration snippet: | Example minimal configuration snippet: | ||
| Line 92: | Line 99: | ||
| hostname: backup-primary | hostname: backup-primary | ||
| poolname: tank | poolname: tank | ||
| + | cleanUpScriptsDir: | ||
| + | cleanupScriptSchedule: | ||
| + | cleanSnaps: [1, | ||
| + | scrubZFS: [2,5,8,11] | ||
| + | oneShotCleanup: | ||
| | | ||
| target: | target: | ||
| hostname: airgap-backup | hostname: airgap-backup | ||
| poolname: backup | poolname: backup | ||
| + | maintenanceMode: | ||
| + | flags: | ||
| + | local: / | ||
| + | transport: flags/ | ||
| + | report: | ||
| + | targetDrive: | ||
| + | label: report | ||
| + | fstype: msdos | ||
| + | mountPoint: /mnt/report | ||
| | | ||
| transport: | transport: | ||
| Line 120: | Line 141: | ||
| - Verify transport drive processed by target (check serial.txt) | - Verify transport drive processed by target (check serial.txt) | ||
| - Securely erase previous data from transport drive | - Securely erase previous data from transport drive | ||
| + | - Pre-calculate replication sizes and validate against history/ | ||
| - Calculate incremental ZFS replication stream | - Calculate incremental ZFS replication stream | ||
| - Encrypt and write replication data to transport drive | - Encrypt and write replication data to transport drive | ||
| - Record latest snapshots sent (update status file) | - Record latest snapshots sent (update status file) | ||
| + | - Select cleanup scripts scheduled for the current month | ||
| - Encrypt and write maintenance scripts to transport drive | - Encrypt and write maintenance scripts to transport drive | ||
| + | - Copy one-shot cleanup scripts and delete from source | ||
| - Create serial.txt timestamp marker | - Create serial.txt timestamp marker | ||
| - Unmount transport drive | - Unmount transport drive | ||
| Line 137: | Line 161: | ||
| The target server performs the following operations automatically: | The target server performs the following operations automatically: | ||
| + | - Check maintenance mode flag(s) and pause if configured | ||
| - Mount transport drive | - Mount transport drive | ||
| - Verify serial.txt exists (indicates unprocessed data) | - Verify serial.txt exists (indicates unprocessed data) | ||
| Line 146: | Line 171: | ||
| - Decrypt and import replication streams from transport | - Decrypt and import replication streams from transport | ||
| - Remove serial.txt (marks data as processed) | - Remove serial.txt (marks data as processed) | ||
| - | - Collect system statistics (pool health, disk status, capacity) | ||
| - Decrypt and execute maintenance scripts | - Decrypt and execute maintenance scripts | ||
| - | - Generate detailed report and write to report drive | + | - Generate detailed report and write to report drive (if configured) |
| - Unmount all media | - Unmount all media | ||
| - Power off system (if '' | - Power off system (if '' | ||
| Line 167: | Line 191: | ||
| **Normal Operation Cycle:** | **Normal Operation Cycle:** | ||
| - | ^ Month ^ Drive A ^ Drive B ^ Drive C ^ Action Required ^ | + | - Receive confirmation that the source drive is populated and ready. |
| - | | 1 | At Source (ready) | At Target | In Transit to Target | Operator: Deliver Drive C to target | + | |
| - | | 2 | At Source | + | - Transport the populated drive to the target |
| - | | 3 | In Transit to Target | At Source (ready) | At Target | Operator: Deliver Drive A to target | + | |
| - | | 4 | At Target | At Source (ready) | In Transit | + | - Install the populated drive into the target, replacing the drive you removed. |
| + | - Verify the target | ||
| + | - Return the removed target drive to the source on the next cycle. | ||
| **Benefits: | **Benefits: | ||
| Line 184: | Line 210: | ||
| <code bash> | <code bash> | ||
| # Label drives for easy identification | # Label drives for easy identification | ||
| - | gpart add -t freebsd-ufs -l sneakernet_A | + | gpart add -t freebsd-ufs -l sneakernet |
| - | gpart add -t freebsd-ufs -l sneakernet_B | + | gpart add -t freebsd-ufs -l sneakernet |
| - | gpart add -t freebsd-ufs -l sneakernet_C | + | gpart add -t freebsd-ufs -l sneakernet |
| # Create filesystems | # Create filesystems | ||
| - | newfs -U /dev/gpt/sneakernet_A | + | newfs -U /dev/gpt/sneakernet |
| - | newfs -U /dev/gpt/sneakernet_B | + | newfs -U /dev/gpt/sneakernet |
| - | newfs -U /dev/gpt/sneakernet_C | + | newfs -U /dev/gpt/sneakernet |
| </ | </ | ||
| Line 268: | Line 294: | ||
| Options: | Options: | ||
| - | -n, --dryrun | + | -n, --dryrun |
| - | -v, --verbosity | + | -v, --verbosity |
| - | -V, --version | + | -d, --debug LEVEL Debug breakpoint level (integer) |
| - | -h, --help | + | -V, --version |
| + | -h, --help | ||
| Verbosity Levels: | Verbosity Levels: | ||
| Line 288: | Line 315: | ||
| # Run with detailed logging | # Run with detailed logging | ||
| - | sneakernet -vv | + | sneakernet -v 2 |
| # Maximum verbosity for troubleshooting | # Maximum verbosity for troubleshooting | ||
| - | sneakernet -vvvvv | + | sneakernet -v 5 |
| </ | </ | ||
| Line 300: | Line 327: | ||
| **Script Requirements: | **Script Requirements: | ||
| * Must be valid Perl code | * Must be valid Perl code | ||
| - | * Return empty array for success, | + | * Return |
| + | * '' | ||
| + | * '' | ||
| * Encrypted with transport symmetric key | * Encrypted with transport symmetric key | ||
| * Stored in configured '' | * Stored in configured '' | ||
| + | * Optional one-shot scripts can be transferred once and then deleted at source | ||
| + | * See '' | ||
| - | **Example maintenance script:** | + | **Example maintenance script |
| <code perl> | <code perl> | ||
| # | # | ||
| - | # cleanup_old_snapshots.pl | + | # helloWorld-style template |
| - | # Remove snapshots older than 90 days | + | |
| use strict; | use strict; | ||
| use warnings; | use warnings; | ||
| - | my @errors; | + | my @result; |
| - | my $pool = ' | + | my @errorMessages = (); |
| - | my $cutoff_days | + | my $caller |
| + | my $verbosityLevel | ||
| - | # Get list of snapshots | ||
| - | my @snapshots = `zfs list -t snapshot -o name -s creation -H $pool`; | ||
| - | foreach my $snap (@snapshots) { | + | # Add messages to result array |
| - | | + | push @result, " |
| - | # Parse timestamp from snapshot name and check age | + | push @result, " |
| - | # Remove if older than cutoff | + | |
| - | # (implementation details omitted for brevity) | + | |
| - | } | + | |
| - | # Return errors | + | # Add test error message (remove for production) |
| - | return | + | push @errorMessages, |
| + | |||
| + | # Return | ||
| + | return | ||
| + | join(" | ||
| + | @errorMessages ? join(" | ||
| + | ); | ||
| </ | </ | ||
| + | |||
| + | **Month-based scheduling (monthly updates assumed):** | ||
| + | |||
| + | Configure the scripts that should be transferred on the current month: | ||
| + | <code yaml> | ||
| + | source: | ||
| + | cleanupScriptSchedule: | ||
| + | zpoolStats: [1, | ||
| + | cleanSnaps: [1, | ||
| + | scrubZFS: [2,5,8,11] | ||
| + | trimZFS: [3,6,9,12] | ||
| + | runSmart: [1,7] | ||
| + | </ | ||
| + | |||
| + | Scripts not listed are not copied. This aligns with monthly updates to the air gap target. | ||
| **Deploy maintenance script:** | **Deploy maintenance script:** | ||
| Line 338: | Line 385: | ||
| -pass file:/ | -pass file:/ | ||
| </ | </ | ||
| + | |||
| + | ===== Size Tracking and Validation ===== | ||
| + | |||
| + | Before replication, | ||
| + | stored in the source history file. If a dataset exceeds its '' | ||
| + | aborted to prevent unexpected large transfers (e.g., ransomware). The transfer is also aborted if | ||
| + | the estimated total size exceeds transport capacity. | ||
| ===== Monitoring and Reports ===== | ===== Monitoring and Reports ===== | ||
| + | |||
| + | Reports send a brief summary, followed by the logs generated. The degree of detail in the logs are | ||
| + | controlled by the verbosity level, so can vary based on this setting. Most mainteannce scripts will | ||
| + | change the amount of output based on the verbosity level also. | ||
| + | |||
| + | **Note**: While it is assumed the output of the reports is e-mail for the source machine and a file | ||
| + | written to disk on the target, both options are available in both modes, and are not exclusive. | ||
| + | Source can send e-mail **and** write to a disk file, for example. | ||
| ==== Source Server Reporting ==== | ==== Source Server Reporting ==== | ||
| Line 349: | Line 411: | ||
| * Snapshot names and sizes | * Snapshot names and sizes | ||
| * Total data transferred | * Total data transferred | ||
| - | * Disk space utilization | ||
| * Any errors or warnings | * Any errors or warnings | ||
| Line 378: | Line 439: | ||
| * Timestamp of operation | * Timestamp of operation | ||
| * Datasets imported | * Datasets imported | ||
| - | * Pool health status | ||
| - | * Disk SMART status | ||
| * Maintenance script results | * Maintenance script results | ||
| * Any errors or warnings | * Any errors or warnings | ||
| Line 423: | Line 482: | ||
| # Check ZFS_Utils log file | # Check ZFS_Utils log file | ||
| - | tail -f / | + | tail -f / |
| # Check sneakernet log file (if configured) | # Check sneakernet log file (if configured) | ||
| Line 432: | Line 491: | ||
| * Main log: Configured via '' | * Main log: Configured via '' | ||
| - | * ZFS_Utils log: ''/ | + | * ZFS_Utils log: ''/ |
| * Status file: Configured via '' | * Status file: Configured via '' | ||
| * State file: Target only, records pre-update snapshot state | * State file: Target only, records pre-update snapshot state | ||
| Line 438: | Line 497: | ||
| ===== Version History ===== | ===== Version History ===== | ||
| - | * **v1.3.2** (2026-01-18) - Report drive notification, | + | * **v1.5.3** (2026-02-05) - Added CLI debug option to set config debug level |
| - | * **v1.3.1** (2026-01-18) - CamelCase configuration keys, initialization refactoring | + | * **v1.5.2** (2026-02-05) - Capture and report cleanup script errors on target; documentation updates |
| - | * **v1.3.0** (2026-01-18) - Enhanced | + | * **v1.5.1** |
| - | * **v1.2.x** - Serial.txt mechanism, cleanup | + | * **v1.5.0** (2026-01-29) - Maintenance mode flag to pause replication |
| - | * **v1.1.x** - Snapshot filtering, | + | * **v1.4.x** (2026-01-22 to 2026-01-28) - Month-based cleanup scheduling, one-shot cleanup, size estimation/ |
| + | * **v1.3.x** (2026-01-18 | ||
| + | * **v1.2.x** | ||
| + | * **v1.1.x** | ||
| + | * **v1.0.1** (2025-12-15) - Added verbose | ||
| * **v1.0** (2025-12-15) - Initial release | * **v1.0** (2025-12-15) - Initial release | ||
| + | * **v0.1** (2025-12-10) - Development version | ||
| See '' | See '' | ||
| Line 449: | Line 513: | ||
| ===== References ===== | ===== References ===== | ||
| - | * [[unix: | + | * [[airgap: |
| * [[https:// | * [[https:// | ||
| * [[https:// | * [[https:// | ||
| Line 457: | Line 521: | ||
| **Repository: | **Repository: | ||
| - | **Author:** R. W. Rodolico | + | **Author:** R. W. Rodolico\\ |
| **License: | **License: | ||
| - | **Company: | + | **Company: |
| + | |||
| + | For bug reports, feature requests, or questions, contact the repository maintainer via web form at https:// | ||
| + | |||
| + | ===== Disclaimer ===== | ||
| - | For bug reports, feature requests, or questions, contact | + | This document was edited for clarity and formatting by an AI agent (GitHub Copilot), and the content was reviewed for accuracy afterward. |
unix/freebsd/system_builds/airgap/sneakernet_implementation.1768894935.txt.gz · Last modified: by rodolico
