==============
== morph.sh ==
==============
Einfach mal was mit Holz machen.

Project Log: verschlüsseltes Datenarchiv in der "Cloud"

de sysadmin

Wie viele Menschen habe ich eine externe Festplatte zuhause, die mein “digitaler Keller” ist - sie ist voll mit alten Daten, die ich selten bis nie brauche, aber langfristig aufheben will. Alte Fotos, Musik, Dateien aus der Schulzeit - Dinge, bei denen ich mich in 20 Jahren sehr darüber freuen werde, sie aufgehoben zu haben :)

Eine einzelne Festplatte ist aber natürlich kein sicherer Ort für solche wichtigen Daten. Festplatten gehen gerne einfach mal so kaputt - genauso gut kann aber das Haus abbrennen, jemand sie klauen, oder oder oder - daher wollte ich ein besseres Datenarchiv an einem anderen Ort schaffen. Alles auf eine weitere Festplatte zu kopieren und diese bei einer Vertrauensperson oder in einem Schließfach o.ä. zu hinterlegen wäre eine einfache Lösung, die aber auch Probleme mit sich bringt und vor allem an einen physischen Ort gebunden ist. Daher wollte ich das ganze auf einem Speicherdienst in der sogenannten Cloud realisieren. Ein Produkt, das sich für mich bewährt hat, ist die Hetzner Storagebox, da sie relativ günstig ist (ich zahle 3,81€ monatlich für 1TB Speicher) und den Zugriff per SSH, SFTP, FTPS, SMB, WebDAV und weiterem erlaubt. All diese Zugriffswege kann man aber auch einzeln abschalten, was aus Sicherheitsgründen die erste Amtshandlung nach dem Anlegen einer Storagebox sein sollte. Diese Art der Speicherung ist sehr angenehm, weil ich mich um keinen Server o.ä. selbst kümmern muss.

Sicherheitsbedenken

Jetzt stellt sich die Frage: wie kriege ich all diese sehr intimen Daten ins Internet, ohne sie der Gefahr auszusetzen, von bösen bösen Hacker*innen wegschnabuliert zu werden? Es gibt zu bedenken:

  • Der Zugriff auf das Dateisystem muss so stark wie möglich eingeschränkt sein
  • Die Dateien müssen verschlüsselt sein (falls jemand doch in den Account eindringt, Hetzner gehackt wird, ein Mitarbeiter dort rumschnüffelt…)
  • Metadaten wie Datei- und Verzeichnisnamen und -strukturen oder Dateigrößen dürfen nicht sichtbar sein, da diese Rückschlüsse auf die Daten zulassen

Die einfache Lösung, um all das zu erreichen, wäre es, ALLE Daten in ein riesengroßes Zip-Archiv zu packen, dieses zu verschlüsseln und hochzuladen. Das hat aber wieder den Nachteil, dass ich jedes mal die gesamte Datei durch die Gegend kopieren muss, wenn ich etwas draus lesen oder hinzufügen will. Es muss also etwas schlaueres her, dass Daten verschlüsselt und in unauffällige kleine Scheibchen zerteilt irgendwo hinlegen kann, aber trotzdem den Zugriff auf einzelne Dateien erlaubt.

Borgbackup to the rescue! + Vorbereitung

Borgbackup ist eine beliebte Backupsoftware, die ich für mein Datenarchiv missbrauchen kann. Es ist (natürlich) open source, kann alles verschlüsseln und erfüllt auch sonst alles, was ich will. Klar will ich keine klassischen Backups machen, so wie es bspw. in der Serveradministration gebraucht wird, aber an sich sind die Anforderungen gar nicht so unähnlich. Backup-Spezialitäten wie das Generationenprinzip, die Borg beherrscht, brauche ich nicht, aber die muss ich ja auch nicht verwenden.

Zuerst klicke ich mir die Storagebox bei Hetzner. Die Zugangsdaten kann ich direkt dort abrufen und die erlaubten Protokolle wie gewünscht einstellen. Und wie in der Hetzner-Doku beschrieben hinterlege ich einen eigens dafür angelegten SSH-Key.

Danach schreibe ich in meine SSH-Config (~.ssh/config) einen Block für die Storagebox rein. Das ist ein reines Komfortfeature, mit dem OpenSSH alle passenden SSH-Settings immer zur Hand hat, damit ich sie nicht jedes mal manuell mitgeben muss:

Host archive u123456
	Hostname u123456.your-storagebox.de
	User u123456
	Port 23
	IdentityFile ~/.ssh/examplekey

Jetzt muss ich immer nur noch bspw. ssh archive tippen, wenn ich eine Verbindung zur Box aufbauen will, und alle Einstellungen werden automatisch angewendet. Und das funktioniert auch in Borg, rsync und allen möglichen anderen Programmen, die ich hier verwenden will.

Als letzten Teil der Vorbereitung lege ich ein neues Borg-Repository auf der Storagebox an. Das geht mit dem Befehl borg init --encryption=repokey ssh://archive/./offsite-archive. Die --encryption-Option macht, dass Borg den Key, mit dem die Daten verschlüsselt werden, selbst anlegt und im Archiv speichert; ich muss ihn bei jeder Verwendung mit einer Passphrase entschlüsseln. Der klassische Weg, den Key nur auf dem eigenen Rechner zu speichern, ist auch möglich, ich finde das so aber etwas einfacher zu handlen und es ist trotzdem ausreichend sicher (wenn die Passphrase taugt, natürlich - meine ist lang und besteht aus Zufallszeichen, also passt das).

Up, up and away!

Jetzt kann ich anfangen, Daten ins Archiv zu schieben. Mit ncdu lasse ich mir anzeigen, welche Verzeichnisse ich habe und wie groß die sind - um das ganze erstmal auszuprobieren, fange ich mit den kleinsten Verzeichnissen an und arbeite mich hoch:

  105,8 GiB [############                      ] /Bilder
   77,8 GiB [#########                         ] /ISOs
   44,0 GiB [#####                             ] /recovery
   29,0 GiB [###                               ] /Roms
    9,4 GiB [#                                 ] /Installer
[...]

Borg arbeitet mit sogenannten “Archives” (zugegebenermaßen etwas verwirrend, dass meine Storagebox auch “archive” heißt…), von denen in einem Repository beliebig viele existieren können. Archives kann man auch als “Backupstände” verstehen; sie beziehen sich aufeinander, d.h. wenn ich nacheinander zwei Archives anlege mit exakt dem gleichen Inhalt, werden die Daten nur beim ersten Mal übertragen und beim zweiten Archive merkt Borg, dass es die Daten schon hat, und referenziert diese nur. Das kann ich beliebig oft tun und kann dann aus all diesen Archiven meine Daten abrufen, aber trotzdem belegen sie nur einmal Speicherplatz. Für meinen Einsatzzweck ist das sehr praktisch, denn ich kann für jede Upload-Rutsche (sagen wir, ich lade ‘Bilder’, ‘Musik’ und ‘Installer’ in getrennten Befehlen nacheinander hoch) ein Archive anlegen, welches dann erstmal nur den jeweiligen Ordner enthält. Ganz zum Schluss erstelle ich noch ein finales Archive mit allen Ordnern, in das ich reinschaue, wenn ich etwas suche (die Struktur ist dort also genau wie auf der Originalfestplatte), aber trotzdem dauert das nicht lange, weil Borg alle Daten schon hat.

Wenn ich jetzt ein Archive anlege und mit ihm ein Verzeichnis hochlade, sieht das so aus:

$ borg create --progress --verbose ssh://archive/./offsite-archive::init-archive-$(date +%s) ./Games/
Enter passphrase for key ssh://archive/./offsite-archive: 
Creating archive at "ssh://archive/./offsite-archive::init-archive-1677085507"

Das Archive heißt “init-archive-” und dahinter die aktuelle Uhrzeit im Unix-Format, damit ich es später wiedererkennen und löschen kann, wenn ich das “finale Archiv” mit allen Daten erstellt habe. So lade ich alle Daten nacheinander hoch, was bei mir zuhause ein paar Tage dauert.

Getting there

Nachdem alle Daten einmal durch die dünne Leitung gewandert sind, nutze ich find, um alle Verzeichnisse zu nehmen und einen langen borg create-Befehl zusammenzubasteln, in dem alles enthalten ist, was ich vorher schon hochgeladen habe. Erwartungsgemäß läuft dieser relativ schnell durch, weil Borg nur feststellen muss, dass alle Daten schon da sind, und dann ein finales Archiv erstellt.

$ find . -maxdepth 1 -type d -exec borg create --progress --verbose ssh://archive/./offsite-archive::complete-archive-$(date +%s) {} +

Nachdem das durch ist, lasse ich mir anzeigen, welche Archive wir jetzt haben:

$ borg list ssh://archive/./offsite-archive
Enter passphrase for key ssh://archive/./offsite-archive: 
init-archive-1677070165              Wed, 2023-02-22 13:49:29 [6ff4647d61124b5cd009a0e42951107f54a4b5e1a46749e19822a21a1559b2b7]
init-archive-1677070207              Wed, 2023-02-22 13:50:12 [cc26a95ea0a92e91a277da4baf79d01cc3095ad9e5d7e9c3d7019ee861ac8ab9]
init-archive-1677070413              Wed, 2023-02-22 13:53:37 [0bbad5cbe0da5e65b1c456ca554fae945dee998fb283e328bc7314f84dfa0f9c]
init-archive-1677070490              Wed, 2023-02-22 13:54:53 [03f13b6282b3d3c8ac0a91f2e3f7b113853acd74a08f5f929a4dc94b1a089abc]
init-archive-1677070526              Wed, 2023-02-22 13:55:30 [3eff514858d66bca0425d350b0a2dae823c4bff146b95c14072f5616cc79725f]
init-archive-1677070703              Wed, 2023-02-22 13:58:34 [9abec3cdab1ca57485d2d32e38e58d48952fcbea112c2cde57a7f0206ac248b0]
init-archive-1677071097              Wed, 2023-02-22 14:05:06 [f0ae32bfd6e5e974d3e873c8ba77f47bcc2ce977699030d2592cd7ff7fa5da82]
init-archive-1677074654              Wed, 2023-02-22 15:04:23 [758cf780bdde960b6fbc1962b32c0ea44df5585a8980bfcf0ef4535699551355]
init-archive-1677078122              Wed, 2023-02-22 16:02:08 [eab74aafb130a5b1f98ce583a6f9397770cff9c66d9179710f9260d44118ee06]
init-archive-1677085507              Wed, 2023-02-22 18:05:11 [21c75de5c23a4f4ecb112359a26bca333934fd05fb4b4da7add00e086b18f549]
init-archive-1677135847              Thu, 2023-02-23 08:04:25 [1c9188ebb09bf0243264d01b8ea16267e283820a7cfb101b7099f47dd21fa781]
init-archive-1677135925              Thu, 2023-02-23 08:05:34 [baa90aa3782a1c1e724c28e40bb078d6e387ef764bc3188016c0952af97de4a5]
init-archive-1677194311              Fri, 2023-02-24 00:19:00 [efc6a3781405e1c1abfd578db85eab5df85d419ce93163415cb60eead8f0ba48]
init-archive-1677247972              Fri, 2023-02-24 15:13:05 [83d91d32313ae4dffa2e172783fe19e6d3be276e0931550d04e0e809cda9f139]
init-archive-1677274277              Fri, 2023-02-24 22:31:33 [81c52fbb2cbf8503532dc3d55bf3fc49e01f5e1a9feb44587d661008d52aa7e5]
init-archive-1677316271              Sat, 2023-02-25 10:11:43 [04f45aef42094b7ba675c558c01e735f9c4ef3179eb3764e95616b1eee744228]
init-archive-1677672813              Wed, 2023-03-01 13:13:47 [ec6c30ebfa3c3f0195c0d8bb00f04485da6ed2ff786f394ef3b63d090472064e]
complete-archive-1677690935          Wed, 2023-03-01 18:15:44 [5ae59750ae2ed9af2b6d964114ea2918fb6baa41f8af60ac5480b7509e1e0206]

Das ganze verbraucht jetzt ca. 991GB Platz auf der Storagebox.

u123456 /home > du -sh
991G	.

Mit borg prune können wir alle init-archive-Archive abräumen, wir brauchen ja nur noch das finale:

$ borg prune --verbose --list --keep-within 1d  ssh://archive/./offsite-archive
Enter passphrase for key ssh://archive/./offsite-archive: 
Keeping archive (rule: within #1):       complete-archive-1677690935          Wed, 2023-03-01 18:15:44 [5ae59750ae2ed9af2b6d964114ea2918fb6baa41f8af60ac5480b7509e1e0206]
Keeping archive (rule: within #2):       init-archive-1677672813              Wed, 2023-03-01 13:13:47 [ec6c30ebfa3c3f0195c0d8bb00f04485da6ed2ff786f394ef3b63d090472064e]
Pruning archive (1/27):                  init-archive-1677597979.checkpoint   Tue, 2023-02-28 16:26:31 [26fee74b6e3c693bf8997fbc5c595d3322454fc6968bd5e7cd3f8d644777b498]
Pruning archive (2/27):                  init-archive-1677316271              Sat, 2023-02-25 10:11:43 [04f45aef42094b7ba675c558c01e735f9c4ef3179eb3764e95616b1eee744228]
Pruning archive (3/27):                  init-archive-1677274277              Fri, 2023-02-24 22:31:33 [81c52fbb2cbf8503532dc3d55bf3fc49e01f5e1a9feb44587d661008d52aa7e5]
Pruning archive (4/27):                  init-archive-1677247972              Fri, 2023-02-24 15:13:05 [83d91d32313ae4dffa2e172783fe19e6d3be276e0931550d04e0e809cda9f139]
Pruning archive (5/27):                  init-archive-1677234485.checkpoint   Fri, 2023-02-24 11:28:15 [0a770784a95d1352f7f1adf57ad5914de7c7402efc11e3fd833199d4792f5ed8]
Pruning archive (6/27):                  init-archive-1677194311              Fri, 2023-02-24 00:19:00 [efc6a3781405e1c1abfd578db85eab5df85d419ce93163415cb60eead8f0ba48]
Pruning archive (7/27):                  init-archive-1677187998.checkpoint   Thu, 2023-02-23 22:33:51 [f6a0e1a549d028a733bc9343af4f8def1a34058207bfdfaff2d28878ae172752]
Pruning archive (8/27):                  init-archive-1677135925              Thu, 2023-02-23 08:05:34 [baa90aa3782a1c1e724c28e40bb078d6e387ef764bc3188016c0952af97de4a5]
Pruning archive (9/27):                  init-archive-1677135847              Thu, 2023-02-23 08:04:25 [1c9188ebb09bf0243264d01b8ea16267e283820a7cfb101b7099f47dd21fa781]
Pruning archive (10/27):                 init-archive-1677085507              Wed, 2023-02-22 18:05:11 [21c75de5c23a4f4ecb112359a26bca333934fd05fb4b4da7add00e086b18f549]
Pruning archive (11/27):                 init-archive-1677078122              Wed, 2023-02-22 16:02:08 [eab74aafb130a5b1f98ce583a6f9397770cff9c66d9179710f9260d44118ee06]
Pruning archive (12/27):                 init-archive-1677076644.checkpoint   Wed, 2023-02-22 15:37:33 [d26466e86bdc129a43feddc032382510ca129d2b8ee8d0f256f8188746e2478b]
Pruning archive (13/27):                 init-archive-1677074654              Wed, 2023-02-22 15:04:23 [758cf780bdde960b6fbc1962b32c0ea44df5585a8980bfcf0ef4535699551355]
Pruning archive (14/27):                 init-archive-1677071097              Wed, 2023-02-22 14:05:06 [f0ae32bfd6e5e974d3e873c8ba77f47bcc2ce977699030d2592cd7ff7fa5da82]
Pruning archive (15/27):                 init-archive-1677070703              Wed, 2023-02-22 13:58:34 [9abec3cdab1ca57485d2d32e38e58d48952fcbea112c2cde57a7f0206ac248b0]
Pruning archive (16/27):                 init-archive-1677070526              Wed, 2023-02-22 13:55:30 [3eff514858d66bca0425d350b0a2dae823c4bff146b95c14072f5616cc79725f]
Pruning archive (17/27):                 init-archive-1677070490              Wed, 2023-02-22 13:54:53 [03f13b6282b3d3c8ac0a91f2e3f7b113853acd74a08f5f929a4dc94b1a089abc]
Pruning archive (18/27):                 init-archive-1677070413              Wed, 2023-02-22 13:53:37 [0bbad5cbe0da5e65b1c456ca554fae945dee998fb283e328bc7314f84dfa0f9c]
Pruning archive (19/27):                 init-archive-1677070207              Wed, 2023-02-22 13:50:12 [cc26a95ea0a92e91a277da4baf79d01cc3095ad9e5d7e9c3d7019ee861ac8ab9]
Pruning archive (20/27):                 init-archive-1677070165              Wed, 2023-02-22 13:49:29 [6ff4647d61124b5cd009a0e42951107f54a4b5e1a46749e19822a21a1559b2b7]
Pruning archive (21/27):                 1677069659-test                      Wed, 2023-02-22 13:41:02 [0d291249744318a24f10df122dbf57887ded8612ee82fc453609853e1581a148]
Pruning archive (22/27):                 1677069640-test                      Wed, 2023-02-22 13:40:44 [bc33aa691e114982854ec534adcf7bfd19333e83e101304f4f3be030ab0fc438]
Pruning archive (23/27):                 1677069602-test                      Wed, 2023-02-22 13:40:05 [aa05d0b1dec91b037225786145dc57a8b080798daf1004ede65ca9e1e57bf3a8]
Pruning archive (24/27):                 1677069577-test                      Wed, 2023-02-22 13:39:41 [730a70290dcd7858d2414a9c90b9b4e8ab0906416d01dd75575c241d3c385311]
Pruning archive (25/27):                 1677017743-test                      Tue, 2023-02-21 23:15:47 [06451b93a95151c1f99c2c38bcf6114daf9a68d1bc35a21b6a7d31a2bb0c84a0]
Pruning archive (26/27):                 1677017728-test                      Tue, 2023-02-21 23:15:32 [3e2d814e4101a88fc894f2864d5abb2bc64c0fa9216fc94822326e6706fd7242]
Pruning archive (27/27):                 1677017677-test                      Tue, 2023-02-21 23:14:53 [0a49ea81a04b2eceebc32600fd8844dd3dfc063bde21f3420881d4ced658b5ed]

Jetzt ist nur noch das neueste Archive übrig. Zum Abschluss kommt noch der Befehl borg compact zum Einsatz, der den Speicherplatz von inzwischen gelöschten Archiven tatsächlich freiräumt. An sich sollte das nicht nötig sein, in diesem Fall habe ich aber zwischendurch beschlossen, eine riesige Datei auf meiner Festplatte doch nicht hochzuladen, weil ich sie nicht mehr brauchte. Somit war sie nur in einem der gelöschten Archive vorhanden, aber nicht im finalen.

$ borg compact ssh://archive/./offsite-archive
u123456 /home > du -sh
787G	.

Und fertig! :) Habt einen schönen Tag.