A service of Daily Data, Inc.
Contact Form

User Tools

Site Tools


unix:freebsd:system_builds:airgap:sneakernet_implementation

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
unix:freebsd:system_builds:airgap:sneakernet_implementation [2026/01/20 01:45] – [Support] rodolicounix: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 (target) |
 | 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
   * ''GELI'' kernel module (for target server encryption)   * ''GELI'' kernel module (for target server encryption)
Line 86: Line 89:
   * ''transport'' — Transport drive settings (label, encryption key, mountpoint)   * ''transport'' — Transport drive settings (label, encryption key, mountpoint)
   * ''datasets'' — Dataset replication mappings   * ''datasets'' — Dataset replication mappings
 +  * ''source.cleanupScriptSchedule'' — Month-based scheduling for maintenance scripts
 +  * ''source.oneShotCleanup'' — One-time maintenance scripts directory
 +  * ''target.maintenanceMode'' — Flag files that pause replication
 +  * ''target.report.targetDrive'' — Optional report drive settings
  
 Example minimal configuration snippet: Example minimal configuration snippet:
Line 92: Line 99:
   hostname: backup-primary   hostname: backup-primary
   poolname: tank   poolname: tank
 +  cleanUpScriptsDir: /usr/local/opt/zfs_utils/sneakernet/cleanupScripts
 +  cleanupScriptSchedule:
 +    cleanSnaps: [1,2,3,4,5,6,7,8,9,10,11,12]
 +    scrubZFS: [2,5,8,11]
 +  oneShotCleanup: /usr/local/opt/zfs_utils/sneakernet/oneShotCleanup
      
 target: target:
   hostname: airgap-backup   hostname: airgap-backup
   poolname: backup   poolname: backup
 +  maintenanceMode:
 +    flags:
 +      local: /tmp/maintenance
 +      transport: flags/maint.flag
 +  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/maxDelta
   - 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 ''shutdownAfterReplication'' enabled)   - Power off system (if ''shutdownAfterReplication'' enabled)
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 | +  At the source, remove the populated drive and install the in-transit drive for the next cycle. 
-| 2 | At Source (ready| In Transit to Source | At Target (ready) | Operator: Collect Drive B from target | +  - Transport the populated drive to the target site. 
-| 3 | In Transit to Target | At Source (ready) | At Target | Operator: Deliver Drive A to target | +  At the target, remove the current target drive (last cycle's drive)
-| 4 | At Target | At Source (ready) | In Transit to Source | Operator: Collect Drive C from target |+  - Install the populated drive into the target, replacing the drive you removed. 
 +  - Verify the target recognizes the newly installed drive. 
 +  - 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 /dev/ada0 +gpart add -t freebsd-ufs -l sneakernet /dev/ada0 
-gpart add -t freebsd-ufs -l sneakernet_B /dev/ada1 +gpart add -t freebsd-ufs -l sneakernet /dev/ada1 
-gpart add -t freebsd-ufs -l sneakernet_C /dev/ada2+gpart add -t freebsd-ufs -l sneakernet /dev/ada2
  
 # 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
 </code> </code>
  
Line 268: Line 294:
  
 Options: Options:
-  -n, --dryrun          Run in dry-run mode (no writes, shows what would happen) +  -n, --dryrun              Run in dry-run mode (no writes, shows what would happen) 
-  -v, --verbosity       Increase verbosity level (repeat for more detail+  -v, --verbosity LEVEL     Set verbosity level (0-5) 
-  -V, --version         Display version number +  -d, --debug LEVEL         Debug breakpoint level (integer
-  -h, --help            Display this help message+  -V, --version             Display version number 
 +  -h, --help                Display this help message
  
 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
 </code> </code>
  
Line 300: Line 327:
 **Script Requirements:** **Script Requirements:**
   * Must be valid Perl code   * Must be valid Perl code
-  * Return empty array for success, array of error strings for failures+  * Return **two strings**: ''($resultsString, $errorsString)'' 
 +    * ''$resultsString'' is optional informational output (newline-delimited) 
 +    * ''$errorsString'' is empty on success, or newline-delimited errors
   * Encrypted with transport symmetric key   * Encrypted with transport symmetric key
   * Stored in configured ''cleanUpScriptsDir'' on transport   * Stored in configured ''cleanUpScriptsDir'' on transport
 +  * Optional one-shot scripts can be transferred once and then deleted at source
 +  * See ''cleanupScripts/helloWorld'' for the authoritative template
  
-**Example maintenance script:**+**Example maintenance script (based on ''cleanupScripts/helloWorld''):**
 <code perl> <code perl>
 #!/usr/bin/env perl #!/usr/bin/env 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 'backup'+my @errorMessages = ()
-my $cutoff_days 90;+my $caller caller()# Check if called from another script and, if not, prints updates to STDOUT 
 +my $verbosityLevel ($caller && defined $ZFS_Utils::verboseLoggingLevel) ? $ZFS_Utils::verboseLoggingLevel : 5;
  
-# 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 
-    chomp $snap; +push @result, "hello"; 
-    # Parse timestamp from snapshot name and check age +push @result, "world" if $verbosityLevel > 2;
-    # Remove if older than cutoff +
-    # (implementation details omitted for brevity) +
-}+
  
-# Return errors array (empty = success+# Add test error message (remove for production) 
-return @errors;+push @errorMessages, "This is a test error message"; 
 + 
 +# Return two strings: results and errors 
 +return ( 
 +  join("\n", @result. "\n", 
 +  @errorMessages ? join("\n", @errorMessages) : "" 
 +);
 </code> </code>
 +
 +**Month-based scheduling (monthly updates assumed):**
 +
 +Configure the scripts that should be transferred on the current month:
 +<code yaml>
 +source:
 +  cleanupScriptSchedule:
 +    zpoolStats: [1,2,3,4,5,6,7,8,9,10,11,12]
 +    cleanSnaps: [1,2,3,4,5,6,7,8,9,10,11,12]
 +    scrubZFS: [2,5,8,11]
 +    trimZFS: [3,6,9,12]
 +    runSmart: [1,7]
 +</code>
 +
 +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:/secure/transport.key   -pass file:/secure/transport.key
 </code> </code>
 +
 +===== Size Tracking and Validation =====
 +
 +Before replication, the source pre-calculates stream sizes and compares them to historical averages
 +stored in the source history file. If a dataset exceeds its ''maxDelta'' threshold, replication is
 +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 /tmp/zfs_utils.log+tail -f /tmp/zfs_utils.log # location overwritten by sneakernet.conf.yaml
  
 # Check sneakernet log file (if configured) # Check sneakernet log file (if configured)
Line 432: Line 491:
  
   * Main log: Configured via ''logFile'' in YAML (default: ''sneakernet.log'')   * Main log: Configured via ''logFile'' in YAML (default: ''sneakernet.log'')
-  * ZFS_Utils log: ''/tmp/zfs_utils.log''+  * ZFS_Utils log: ''/tmp/zfs_utils.log'' unless defined in sneakernet.conf.yaml
   * Status file: Configured via ''statusFile'' (tracks last replicated snapshots)   * Status file: Configured via ''statusFile'' (tracks last replicated snapshots)
   * 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, isMounted() integration +  * **v1.5.3** (2026-02-05) - Added CLI debug option to set config debug level 
-  * **v1.3.1** (2026-01-18) - CamelCase configuration keysinitialization refactoring +  * **v1.5.2** (2026-02-05) - Capture and report cleanup script errors on target; documentation updates 
-  * **v1.3.0** (2026-01-18) - Enhanced logging with caller tracking +  * **v1.5.1** (2026-02-04) - Always log cleanup script output (even when empty
-  * **v1.2.x** - Serial.txt mechanism, cleanup scriptsrandom IVsencryption enhancements +  * **v1.5.0** (2026-01-29) - Maintenance mode flag to pause replication 
-  * **v1.1.x** - Snapshot filtering, improved logging+  * **v1.4.x** (2026-01-22 to 2026-01-28) - Month-based cleanup schedulingone-shot cleanup, size estimation/validation, improved reporting and diagnostics 
 +  * **v1.3.x** (2026-01-18 to 2026-01-21) - Configuration/logging improvements, GELI refactor, report drive notifications, modular cleanup stats 
 +  * **v1.2.x** (2026-01-11 to 2026-01-17) - Serial.txt mechanism, cleanup script supportmodular configimproved security and error handling 
 +  * **v1.1.x** (2025-12-17 to 2025-12-21) - Snapshot filtering, rollback capability, config validation, logging improvements 
 +  * **v1.0.1** (2025-12-15) - Added verbose logging control
   * **v1.0** (2025-12-15) - Initial release   * **v1.0** (2025-12-15) - Initial release
 +  * **v0.1** (2025-12-10) - Development version
  
 See ''CHANGELOG.md'' in the repository for complete revision history. See ''CHANGELOG.md'' in the repository for complete revision history.
Line 449: Line 513:
 ===== References ===== ===== References =====
  
-  * [[unix:freebsd:system_builds:airgap:concepts|Air Gap Server Concepts]] — Theoretical background and best practices+  * [[airgap:concepts|Air Gap Server Concepts]] — Theoretical background and best practices
   * [[https://docs.freebsd.org/en/books/handbook/disks/#disks-encrypting-geli|FreeBSD GELI Documentation]]   * [[https://docs.freebsd.org/en/books/handbook/disks/#disks-encrypting-geli|FreeBSD GELI Documentation]]
   * [[https://docs.freebsd.org/en/books/handbook/zfs/|FreeBSD ZFS Handbook]]   * [[https://docs.freebsd.org/en/books/handbook/zfs/|FreeBSD ZFS Handbook]]
Line 457: Line 521:
  
 **Repository:** ''http://svn.dailydata.net/svn/zfs_utils/trunk''\\ **Repository:** ''http://svn.dailydata.net/svn/zfs_utils/trunk''\\
-**Checkout:** ''svn export http://svn.dailydata.net/svn/zfs_utils/trunk zfs_utils''\\ 
 **Author:** R. W. Rodolico\\ **Author:** R. W. Rodolico\\
 **License:** BSD 2-Clause (FreeBSD License)\\ **License:** BSD 2-Clause (FreeBSD License)\\
-**Company:** Daily Data Inc. (https://dailydata.net)+**Company:** Daily Data Inc. 
 + 
 +For bug reports, feature requests, or questions, contact the repository maintainer via web form at https://dailydata.net/contact-us/
 + 
 +===== Disclaimer =====
  
-For bug reportsfeature requests, or questions, contact the repository maintainer by contact form https://dailydata.net/contact-us/+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.1768895152.txt.gz · Last modified: by rodolico