====== Air Gap Server: Concepts and Best Practices ======
**Purpose:** Secure long-term backup storage isolated from network threats\\
**Key Requirements:** Full disk encryption, physical security, validated data transfer\\
**Target Environment:** FreeBSD with ZFS and GELI encryption\\
**Status:** Powered off when not actively receiving updates
===== Overview =====
An **Air Gap Server** is a server that operates without network connectivity to protect critical backup data from remote attacks. A modified approach allows temporary network access for system updates while maintaining security boundaries.
The primary purpose is to store long-term backups with significantly reduced attack surface. Physical isolation combined with encryption provides defense-in-depth against:
* Remote network attacks (ransomware, unauthorized access)
* Physical theft or unauthorized access
* Compromised source systems
**Critical:** If the server must be stored in an unsecured location, full disk encryption is **mandatory**, not optional.
===== Core Security Principles =====
* **Physical Isolation** — Geographic separation from primary servers with controlled access
* **Defense in Depth** — Multiple security layers protect data at rest and in transit
* **Data Validation** — Verify integrity of all data transfers and scripts
* **Automated Reporting** — Track all operations for audit and monitoring
* **Powered Off by Default** — Server only active during updates or maintenance
===== Implementation Guidelines =====
==== Physical Security and Access Control ====
**Ideal Configuration:**
* Store in secure facility requiring authenticated access (e.g., Network Operations Center)
* Geographic separation from primary production servers
* Documented access procedures and audit logs
**Fallback for Insecure Locations:**
When secure facilities are unavailable:
* **Mandatory:** Full disk encryption (''GELI'' or equivalent)
* **Mandatory:** Documented key management procedures
* **Recommended:** Physical locks, tamper-evident seals
* **Recommended:** Motion detection or access logging
Store encryption keys in a different physical location than the server. Consider splitting keys across multiple secure locations.
==== Encryption Strategy ====
This implementation uses FreeBSD with ''GELI'' disk encryption backing a ''ZFS'' filesystem.
**At Rest Protection:**
* Full disk encryption using ''GELI'' (minimum requirement)
* All data pools encrypted with strong passphrases or key files
* Keys never stored on the server itself
**Split-Key Architecture:**
For enhanced security, consider using split-key encryption where the final encryption key is derived from combining two separate key components. This enhances security by allowing the actual GELI key to be stored securely off-site, as it cannot be reconstructed without both components:
* **Two-Operator Model:** Each key component held by different operators
* Requires both operators present to unlock encrypted data
* Maximum security: no single person can access data alone
* Higher operational overhead
* **Operator + Automated Model:** One key with operator, one on server
* Operator key: Physically carried by trusted operator
* Server key: Stored on automated script (never on target server)
* Keys combined via XOR or similar operation at decrypt time
* Balances security with automation needs
**In Transit Protection:**
* Transport media (external drives) fully encrypted
* Delta data encrypted before writing to transport media
* Encryption keys validated at both source and destination
**Example GELI Setup:**
# Generate a random key file (4096 bits = 512 bytes)
openssl rand 512 > /secure/path/geli.key
chmod 400 /secure/path/geli.key
# Initialize GELI encryption on disk using the key file
geli init -s 4096 -K /secure/path/geli.key /dev/ada0
# Attach encrypted device
geli attach -k /secure/path/geli.key /dev/ada0
# Create ZFS pool on encrypted device
zpool create backup /dev/ada0.eli
Key size of 4096 bits provides strong encryption. The key file should be stored securely and backed up to a separate location. Use ''-P'' flag to add passphrase protection in addition to key file.
==== Data Transfer Validation ====
**Transport Media Requirements:**
* Large capacity drives (match expected delta sizes)
* Encrypted filesystem (''GELI'', ''LUKS'', or BitLocker) or Encryption of individual files in transit
* Labeled with GPT labels for automated mounting
**Delta Monitoring:**
Monitor transfer sizes to detect anomalies:
* Establish baseline delta sizes for normal operations
* Alert on deltas exceeding 150-200% of baseline
* **Large deltas may indicate ransomware on source system**
**Data Integrity Verification:**
# Generate checksum on source
zfs send pool/dataset@snapshot | tee >(sha256) > /mnt/transport/delta.zfs
# Verify checksum on air gap server
sha256 /mnt/transport/delta.zfs
**Data Validation:**
* All data encrypted with symmetric key at source
* Decryption failure automatically rejects the data
* Failed decryption indicates corruption or tampering
* Process terminates on any decryption failure
==== Script Validation and Maintenance ====
Air gap servers require special consideration for maintenance since they lack network access for updates.
**Validated Script Execution:**
Scripts may be deployed to perform maintenance tasks:
* ''ZFS'' scrubs and pool health checks
* Snapshot cleanup and rotation
* SMART disk monitoring
* System updates (if temporarily networked)
**Script Deployment Process:**
- Scripts stored on source server and version controlled
- Scripts encrypted with symmetric key before transfer
- Air gap server must successfully decrypt before execution
- Decryption failure prevents script execution and terminates process
- Scripts run automatically during replication operations
**Example Script Encryption/Decryption:**
# On source server: encrypt script
openssl enc -aes-256-cbc -salt -in cleanup_script.sh \
-out cleanup_script.sh.enc -pass file:/secure/transport.key
# On air gap server: decrypt and execute
openssl enc -aes-256-cbc -d -in cleanup_script.sh.enc \
-out cleanup_script.sh -pass file:/secure/transport.key && \
sh cleanup_script.sh || { echo "Decryption failed - aborting"; exit 1; }
**Security through decryption:** Scripts that cannot be decrypted with the correct symmetric key are rejected. Any decryption failure terminates the entire process to prevent execution of potentially tampered scripts.
==== Reporting and Audit Trail ====
**Reporting Challenges:**
* Air gap servers cannot send email reports
* No network access for remote monitoring
* Reports must be physically retrieved
**Solution — Report Drive:**
* Dedicated removable media for reports (USB drive, small HDD)
* Reports written to transport drive after each operation
* Administrator retrieves and processes reports manually
**Report Contents:**
* Timestamp of operation
* Data volumes transferred (size, snapshot names)
* Success/failure status of each operation
* Disk health (SMART status, ZFS pool health)
* Script execution results
* Any errors or warnings
**Example Report Structure:**
=== Air Gap Backup Report ===
Date: 2026-01-18 03:00:00
Operation: Incremental Backup
Source: production.example.com
Target: airgap-backup01
Datasets Processed:
- pool/data: 45.2 GB transferred
Latest: pool/data@2026-01-18_02:00:00
- pool/databases: 12.8 GB transferred
Latest: pool/databases@2026-01-18_02:00:00
Pool Health: ONLINE
Disk Status: All disks PASSED SMART checks
Maintenance Scripts Executed:
- snapshot_cleanup.sh: SUCCESS (removed 3 old snapshots)
- zfs_scrub.sh: SUCCESS (no errors found)
System Shutdown: 2026-01-18 03:45:00
Next Expected Update: 2026-01-25
==== Power Management ====
**Default State: Powered Off**
The air gap server should remain powered off except during:
* Scheduled data imports
* Manual maintenance operations
* Security audits
**Benefits of Power-Off Strategy:**
* Encrypted drives are locked (keys in memory are cleared)
* Eliminates risk of remote exploitation during off time
* Reduces hardware wear and power consumption
* Limits window of opportunity for physical attacks
**Automated Shutdown:**
Final script in maintenance chain should power off the system:
#!/bin/sh
# Final maintenance script - shutdown system
# Verify all operations completed successfully
if [ -f /var/run/backup_complete ]; then
# Write final report
echo "Backup completed successfully at $(date)" >> /mnt/report/status.log
# Sync all filesystem buffers
sync
# Unmount transport media
umount /mnt/transport
umount /mnt/report
# Power off system
shutdown -p now
else
echo "ERROR: Backup did not complete. Manual intervention required." >> /mnt/report/error.log
# Do NOT shutdown - leave powered on for troubleshooting
fi
**Do not** configure automatic shutdown if backups fail. A powered-on system indicates problems requiring manual investigation.
===== Example Workflow =====
A typical weekly backup cycle:
**Day 1 (Monday) — Source Server:**
- Automated script takes ZFS snapshots of all datasets
- Calculates incremental changes since last backup
- Encrypts delta data to transport drive with symmetric key
- Encrypts maintenance scripts with same symmetric key
- Operator notified that transport drive is ready
**Day 2 (Tuesday) — Physical Transport:**
- Operator removes transport drive from source server
- Drive physically transported to air gap location
- Transport logged in access control system
**Day 3 (Wednesday) — Air Gap Server:**
- Operator inserts transport drive and powers on server
- Server boots, mounts transport drive
- Automated script begins:
* Attempts to decrypt delta files with symmetric key
* Validates delta sizes against baseline
* Imports ZFS datasets (decryption happens during import)
* Attempts to decrypt and run maintenance scripts
* Any decryption failure terminates the entire process
* Generates report to report drive
* Powers off system (only if all operations succeed)
- Operator retrieves report drive for later review
**Day 4 (Thursday) — Report Processing:**
- Operator reviews reports from air gap server
- Verifies all backups completed successfully
- Archives reports for audit trail
- Updates monitoring dashboard
**Day 8 (Next Monday):**
- Process repeats with fresh delta data
===== Pre-Implementation Checklist =====
[ ] Physical Security
[ ] Secure location identified and documented
[ ] Access procedures established
[ ] Key storage locations determined
[ ] Hardware
[ ] Air gap server procured and tested
[ ] Transport drives procured (minimum 2 for rotation)
[ ] Report drive procured
[ ] All drives labeled appropriately
[ ] Encryption
[ ] GELI encryption configured and tested
[ ] Encryption keys generated and stored securely
[ ] Key recovery procedures documented
[ ] Transport drives encrypted
[ ] Software
[ ] FreeBSD installed and hardened
[ ] ZFS pools created and tested
[ ] Replication scripts developed and tested
[ ] Maintenance scripts developed and tested
[ ] Symmetric transport keys generated and deployed
[ ] Procedures
[ ] Backup schedule documented
[ ] Transport procedures documented
[ ] Report review procedures documented
[ ] Key rotation schedule established
[ ] Disaster recovery plan created
[ ] Testing
[ ] Full backup cycle tested end-to-end
[ ] Recovery procedures tested
[ ] Failure scenarios tested
[ ] Report generation verified
[ ] Automated shutdown verified
===== Security Considerations =====
**Threat Model:**
This design protects against:
* ✓ Remote network attacks (ransomware, unauthorized access)
* ✓ Compromised source systems
* ✓ Physical theft (with encryption)
* ✓ Unauthorized physical access (with encryption)
This design does NOT fully protect against:
* ✗ Sophisticated attackers with physical access and unlimited time
* ✗ Compromised encryption keys
* ✗ Attacks on the transport process itself
* ✗ Insider threats with authorized access
**Best Practices:**
* Rotate encryption keys annually
* Test recovery procedures quarterly
* Review audit logs monthly
* Update maintenance scripts as needed
* Keep offline backups of critical configuration
===== Troubleshooting =====
**Common Issues:**
^ Problem ^ Symptom ^ Solution ^
| Transport drive not mounting | Server unable to find ''/dev/gpt/label'' | Verify GPT label, check dmesg for device detection |
| Decryption fails | OpenSSL reports bad decrypt error | Verify correct symmetric key in use, check file integrity, investigate potential tampering or corruption |
| Large delta size | Delta exceeds baseline by 200%+ | **Do not import** — investigate source system for compromise or legitimate growth |
| Server won't shutdown | Remains powered on after backup | Check ''/var/run/backup_complete'' flag, review error logs on report drive |
| ZFS pool won't import | Import command fails | Verify encryption key, check pool status with ''zpool import -F'' |
===== References =====
* [[https://docs.freebsd.org/en/books/handbook/disks/#disks-encrypting-geli|FreeBSD GELI Encryption Documentation]]
* [[https://docs.freebsd.org/en/books/handbook/zfs/|FreeBSD ZFS Administration Guide]]
* [[https://www.openssl.org/docs/|OpenSSL Documentation]] — For symmetric encryption operations
* [[https://www.nist.gov/publications/guide-storage-encryption-technologies-end-user-devices|NIST Storage Encryption Guide]]
===== Related Documentation =====
* [[unix:freebsd:system_builds:airgap:sneakernet_implementation|Sneakernet Implementation Guide]] — Real-world deployment example
* [[key_management_procedures|Encryption Key Management]] — Key generation, storage, and rotation
* [[incident_response_airgap|Air Gap Incident Response Plan]] — What to do if compromise suspected
* [[disaster_recovery_procedures|Disaster Recovery Procedures]] — Restoring from air gap backups