From d3be0b0e92e0d6f5328f64116c09db7a3d38972f Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 10 Feb 2026 10:44:23 -0800 Subject: [PATCH 1/4] Add how-to guide for restoring 1Password backup from borgmatic Verified end-to-end: extracted .age + .key.enc from borg archive, decrypted age key with openssl, decrypted .1pux with age, confirmed valid 31MB zip containing vault data. Added cross-links from disaster-recovery, 1password, borgmatic, backups, and how-to index. Co-Authored-By: Claude Opus 4.6 --- .../doc-restore-1password-backup.doc.md | 1 + docs/how-to/how-to.md | 1 + docs/how-to/restore-1password-backup.md | 112 ++++++++++++++++++ .../reference/operations/disaster-recovery.md | 13 +- docs/reference/services/1password.md | 6 + docs/reference/services/borgmatic.md | 1 + docs/reference/storage/backups.md | 3 +- 7 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 docs/changelog.d/doc-restore-1password-backup.doc.md create mode 100644 docs/how-to/restore-1password-backup.md diff --git a/docs/changelog.d/doc-restore-1password-backup.doc.md b/docs/changelog.d/doc-restore-1password-backup.doc.md new file mode 100644 index 0000000..2c66288 --- /dev/null +++ b/docs/changelog.d/doc-restore-1password-backup.doc.md @@ -0,0 +1 @@ +Add how-to guide for restoring 1Password backup from borgmatic, with cross-links from disaster recovery, borgmatic, 1password, and backup policy docs diff --git a/docs/how-to/how-to.md b/docs/how-to/how-to.md index 8959626..f31f738 100644 --- a/docs/how-to/how-to.md +++ b/docs/how-to/how-to.md @@ -42,6 +42,7 @@ Task-oriented instructions for common BlumeOps operations. These guides assume y |-------|-------------| | [[restart-indri]] | Safely shut down and restart indri | | [[manage-flyio-proxy]] | Deploy, shutoff, and troubleshoot the public proxy | +| [[restore-1password-backup]] | Recover 1Password credentials from borgmatic backup | | [[troubleshooting]] | Diagnose and fix common issues | ## Plans diff --git a/docs/how-to/restore-1password-backup.md b/docs/how-to/restore-1password-backup.md new file mode 100644 index 0000000..11f1a62 --- /dev/null +++ b/docs/how-to/restore-1password-backup.md @@ -0,0 +1,112 @@ +--- +title: Restore 1Password Backup +tags: + - how-to + - operations + - backup +--- + +# Restore 1Password Backup + +How to recover a 1Password `.1pux` export from a [[borgmatic]] backup on [[sifaka]]. + +## Prerequisites + +- SSH access to [[indri]] +- `age` installed (`brew install age`) +- `openssl` installed (ships with macOS) +- Your **1Password Emergency Kit** (safety deposit box) — contains the master password and secret key + +## When to Use This + +Use this procedure when you've lost access to 1Password and need to recover credentials from the encrypted backup created by `mise run op-backup`. + +## Procedure + +### 1. Extract From Borgmatic + +List recent archives to find one containing the backup: + +```bash +ssh indri 'borgmatic list --last 5' +``` + +Extract the 1Password backup files from the chosen archive: + +```bash +ssh indri 'cd /tmp && mkdir -p op-restore && cd op-restore && \ + BORG_PASSCOMMAND="cat /Users/erichblume/.borg/config.yaml" \ + /opt/homebrew/bin/borg extract \ + "/Volumes/backups/borg/::" \ + Users/erichblume/Documents/1password-backup/' +``` + +Verify the files were extracted: + +```bash +ssh indri 'ls -lh /tmp/op-restore/Users/erichblume/Documents/1password-backup/' +``` + +You should see a `.age` file (~30-45 MB) and a `.key.enc` file (~200 bytes). + +### 2. Copy Files to Your Workstation + +```bash +mkdir -p /tmp/op-restore +scp "indri:/tmp/op-restore/Users/erichblume/Documents/1password-backup/1password-export-*.age" \ + "indri:/tmp/op-restore/Users/erichblume/Documents/1password-backup/1password-export-*.key.enc" \ + /tmp/op-restore/ +``` + +### 3. Decrypt the Age Private Key + +The private key is encrypted with `openssl aes-256-cbc`. The passphrase is `{master_password}:{secret_key}` from your Emergency Kit. + +```bash +cd /tmp/op-restore +openssl enc -d -aes-256-cbc -pbkdf2 \ + -in 1password-export-*.key.enc \ + -out key.txt +``` + +Enter the passphrase when prompted: `{master_password}:{secret_key}` (colon-separated, no spaces around the colon). + +### 4. Decrypt the Export + +```bash +age -d -i key.txt < 1password-export-*.age > export.1pux +``` + +### 5. Verify + +The `.1pux` file is a zip archive. Verify it looks correct: + +```bash +file export.1pux # Should say "Zip archive data" +ls -lh export.1pux # Should be ~30-45 MB +unzip -l export.1pux | head -20 # Should list files/ entries +``` + +### 6. Import Into 1Password + +Open 1Password and use **File > Import** to restore from the `.1pux` file. + +### 7. Clean Up + +Remove all temporary files — the decrypted export and key contain secrets: + +```bash +rm -rf /tmp/op-restore +ssh indri 'rm -rf /tmp/op-restore' +``` + +## If You Don't Have the Borg Passphrase + +The borg repo passphrase is stored in `/Users/erichblume/.borg/config.yaml` on [[indri]]. If indri is unavailable but [[sifaka]] is accessible, the borg repo at `/Volumes/backups/borg/` uses `repokey` encryption — the key is stored in the repo itself, so you only need the passphrase (not a separate keyfile). + +## Related + +- [[borgmatic]] - Backup system +- [[1password]] - Credential management +- [[backups]] - Backup policy and schedule +- [[disaster-recovery]] - Overall disaster recovery diff --git a/docs/reference/operations/disaster-recovery.md b/docs/reference/operations/disaster-recovery.md index 79d2864..a521aa1 100644 --- a/docs/reference/operations/disaster-recovery.md +++ b/docs/reference/operations/disaster-recovery.md @@ -6,14 +6,17 @@ tags: # Disaster Recovery -TBD. Current state: +Recovery procedures for BlumeOps infrastructure. -- [[borgmatic]] provides daily backups to [[sifaka|Sifaka]] -- Infrastructure can be rebootstrapped using the blumeops repo -- Detailed DR procedures not yet documented +## Procedures + +| Scenario | Guide | +|----------|-------| +| Lost 1Password access | [[restore-1password-backup]] | +| Indri reboot/power loss | [[restart-indri]] | ## Components - [[borgmatic]] - Backup restoration -- [[1password]] - Credential recovery +- [[1password]] - Credential recovery (backed up via `mise run op-backup`) - [[forgejo]] - Source of truth for infrastructure code diff --git a/docs/reference/services/1password.md b/docs/reference/services/1password.md index 90faecc..46f95da 100644 --- a/docs/reference/services/1password.md +++ b/docs/reference/services/1password.md @@ -34,7 +34,13 @@ The `blumeops` vault contains all infrastructure credentials. Services reference 1Password items via `ExternalSecret` manifests. +## Disaster Recovery Backup + +The `mise run op-backup` task encrypts a `.1pux` vault export and transfers it to [[indri]] for inclusion in [[borgmatic]] backups. See [[restore-1password-backup]] for the full recovery procedure. + ## Related - [[argocd]] - Uses secrets for git access - [[postgresql]] - Database credentials +- [[restore-1password-backup]] - Recovery from backup +- [[borgmatic]] - Backup system diff --git a/docs/reference/services/borgmatic.md b/docs/reference/services/borgmatic.md index 52f2b11..a543ab9 100644 --- a/docs/reference/services/borgmatic.md +++ b/docs/reference/services/borgmatic.md @@ -57,3 +57,4 @@ Dashboard: "Borgmatic Backups" in [[grafana]] - [[backups|Backups]] - Full backup policy - [[sifaka|Sifaka]] - Backup target - [[postgresql]] - Database backups +- [[restore-1password-backup]] - Recover 1Password from backup diff --git a/docs/reference/storage/backups.md b/docs/reference/storage/backups.md index 88e36f0..f8b15b7 100644 --- a/docs/reference/storage/backups.md +++ b/docs/reference/storage/backups.md @@ -24,7 +24,7 @@ Daily automated backups from [[indri]] to [[sifaka|Sifaka]] NAS. | `~/code/personal/zk` | Zettelkasten notes | Critical | | `/opt/homebrew/var/forgejo` | Git repositories | Critical | | `~/.config/borgmatic` | Backup config | High | -| `~/Documents` | Personal documents | High | +| `~/Documents` | Personal documents (includes [[1password]] encrypted export) | High | ### Databases @@ -72,3 +72,4 @@ Dashboard: "Borgmatic Backups" in [[grafana]] - [[borgmatic]] - Backup system details - [[sifaka|Sifaka]] - Backup storage - [[postgresql]] - Database backups +- [[restore-1password-backup]] - Recover 1Password from backup -- 2.50.1 (Apple Git-155) From 357b6f2db82e37d99c8e35fcf1c703c2b81b70ae Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 10 Feb 2026 10:46:38 -0800 Subject: [PATCH 2/4] =?UTF-8?q?Fix=20'safety=20deposit=20box'=20=E2=86=92?= =?UTF-8?q?=20'fire=20safety=20box'=20in=20DR=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- docs/how-to/restore-1password-backup.md | 2 +- mise-tasks/op-backup | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/how-to/restore-1password-backup.md b/docs/how-to/restore-1password-backup.md index 11f1a62..6125c9e 100644 --- a/docs/how-to/restore-1password-backup.md +++ b/docs/how-to/restore-1password-backup.md @@ -15,7 +15,7 @@ How to recover a 1Password `.1pux` export from a [[borgmatic]] backup on [[sifak - SSH access to [[indri]] - `age` installed (`brew install age`) - `openssl` installed (ships with macOS) -- Your **1Password Emergency Kit** (safety deposit box) — contains the master password and secret key +- Your **1Password Emergency Kit** (fire safety box) — contains the master password and secret key ## When to Use This diff --git a/mise-tasks/op-backup b/mise-tasks/op-backup index 48b8a9a..68c46ae 100755 --- a/mise-tasks/op-backup +++ b/mise-tasks/op-backup @@ -19,7 +19,7 @@ If no path is given, prompts you to export from the 1Password desktop app first. DISASTER RECOVERY: 1. Restore borgmatic archive to get the .age and .key.enc files - 2. Retrieve Emergency Kit from safety deposit box + 2. Retrieve Emergency Kit from fire safety box 3. openssl enc -d -aes-256-cbc -pbkdf2 < backup.key.enc > key.txt (passphrase: {master_password}:{secret_key}) 4. age -d -i key.txt < backup.age > export.1pux -- 2.50.1 (Apple Git-155) From 5d2d95fe42f86d5473f9f0e564f942ca90aaa39b Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 10 Feb 2026 10:48:55 -0800 Subject: [PATCH 3/4] Rewrite restore guide to not assume indri/sifaka are available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The disaster scenario is house fire + 1Password cloud down — indri and sifaka may both be gone. Reframed to require only a borg repo copy and the Emergency Kit, with indri access as an optional shortcut. Co-Authored-By: Claude Opus 4.6 --- docs/how-to/restore-1password-backup.md | 54 ++++++++++--------------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/docs/how-to/restore-1password-backup.md b/docs/how-to/restore-1password-backup.md index 6125c9e..97ac4cc 100644 --- a/docs/how-to/restore-1password-backup.md +++ b/docs/how-to/restore-1password-backup.md @@ -8,14 +8,14 @@ tags: # Restore 1Password Backup -How to recover a 1Password `.1pux` export from a [[borgmatic]] backup on [[sifaka]]. +How to recover a 1Password `.1pux` export from a [[borgmatic]] backup. This procedure assumes the worst case — [[indri]] and [[sifaka]] may both be gone. All you need is a copy of the borg repository and your Emergency Kit. ## Prerequisites -- SSH access to [[indri]] -- `age` installed (`brew install age`) -- `openssl` installed (ships with macOS) +- A copy of the borg backup repository (from [[sifaka]], or an off-site copy — TBD) +- `borg`, `age`, and `openssl` installed on any machine - Your **1Password Emergency Kit** (fire safety box) — contains the master password and secret key +- The borg repo passphrase (printed on the Emergency Kit, or from `/Users/erichblume/.borg/config.yaml` if [[indri]] is accessible) ## When to Use This @@ -23,15 +23,19 @@ Use this procedure when you've lost access to 1Password and need to recover cred ## Procedure -### 1. Extract From Borgmatic +### 1. Extract From Borg Repository -List recent archives to find one containing the backup: +If you have direct access to the borg repository (e.g. mounted from [[sifaka]] or restored from off-site), extract directly: ```bash -ssh indri 'borgmatic list --last 5' +mkdir -p /tmp/op-restore && cd /tmp/op-restore +BORG_PASSPHRASE="" borg list /path/to/borg/repo --last 5 +BORG_PASSPHRASE="" borg extract \ + "/path/to/borg/repo::" \ + Users/erichblume/Documents/1password-backup/ ``` -Extract the 1Password backup files from the chosen archive: +If [[indri]] is available, you can use borgmatic instead: ```bash ssh indri 'cd /tmp && mkdir -p op-restore && cd op-restore && \ @@ -41,29 +45,14 @@ ssh indri 'cd /tmp && mkdir -p op-restore && cd op-restore && \ Users/erichblume/Documents/1password-backup/' ``` -Verify the files were extracted: +Verify you have a `.age` file (~30-45 MB) and a `.key.enc` file (~200 bytes). -```bash -ssh indri 'ls -lh /tmp/op-restore/Users/erichblume/Documents/1password-backup/' -``` - -You should see a `.age` file (~30-45 MB) and a `.key.enc` file (~200 bytes). - -### 2. Copy Files to Your Workstation - -```bash -mkdir -p /tmp/op-restore -scp "indri:/tmp/op-restore/Users/erichblume/Documents/1password-backup/1password-export-*.age" \ - "indri:/tmp/op-restore/Users/erichblume/Documents/1password-backup/1password-export-*.key.enc" \ - /tmp/op-restore/ -``` - -### 3. Decrypt the Age Private Key +### 2. Decrypt the Age Private Key The private key is encrypted with `openssl aes-256-cbc`. The passphrase is `{master_password}:{secret_key}` from your Emergency Kit. ```bash -cd /tmp/op-restore +cd /tmp/op-restore/Users/erichblume/Documents/1password-backup openssl enc -d -aes-256-cbc -pbkdf2 \ -in 1password-export-*.key.enc \ -out key.txt @@ -71,13 +60,13 @@ openssl enc -d -aes-256-cbc -pbkdf2 \ Enter the passphrase when prompted: `{master_password}:{secret_key}` (colon-separated, no spaces around the colon). -### 4. Decrypt the Export +### 3. Decrypt the Export ```bash age -d -i key.txt < 1password-export-*.age > export.1pux ``` -### 5. Verify +### 4. Verify The `.1pux` file is a zip archive. Verify it looks correct: @@ -87,22 +76,21 @@ ls -lh export.1pux # Should be ~30-45 MB unzip -l export.1pux | head -20 # Should list files/ entries ``` -### 6. Import Into 1Password +### 5. Import Into 1Password Open 1Password and use **File > Import** to restore from the `.1pux` file. -### 7. Clean Up +### 6. Clean Up Remove all temporary files — the decrypted export and key contain secrets: ```bash rm -rf /tmp/op-restore -ssh indri 'rm -rf /tmp/op-restore' ``` -## If You Don't Have the Borg Passphrase +## Notes on the Borg Passphrase -The borg repo passphrase is stored in `/Users/erichblume/.borg/config.yaml` on [[indri]]. If indri is unavailable but [[sifaka]] is accessible, the borg repo at `/Volumes/backups/borg/` uses `repokey` encryption — the key is stored in the repo itself, so you only need the passphrase (not a separate keyfile). +The borg repo uses `repokey` encryption — the key is stored in the repo itself, so you only need the passphrase (not a separate keyfile). The passphrase should be recorded on your Emergency Kit. If not, it lives in `/Users/erichblume/.borg/config.yaml` on [[indri]] (which may not be available in a disaster scenario). ## Related -- 2.50.1 (Apple Git-155) From 5a0002cc8f79c55f8eb32f632dc2fd15ddb131cb Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 10 Feb 2026 10:54:27 -0800 Subject: [PATCH 4/4] =?UTF-8?q?Update=20borg=20passphrase=20note=20?= =?UTF-8?q?=E2=80=94=20now=20recorded=20on=20Emergency=20Kit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- docs/how-to/restore-1password-backup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/restore-1password-backup.md b/docs/how-to/restore-1password-backup.md index 97ac4cc..d1508b0 100644 --- a/docs/how-to/restore-1password-backup.md +++ b/docs/how-to/restore-1password-backup.md @@ -90,7 +90,7 @@ rm -rf /tmp/op-restore ## Notes on the Borg Passphrase -The borg repo uses `repokey` encryption — the key is stored in the repo itself, so you only need the passphrase (not a separate keyfile). The passphrase should be recorded on your Emergency Kit. If not, it lives in `/Users/erichblume/.borg/config.yaml` on [[indri]] (which may not be available in a disaster scenario). +The borg repo uses `repokey` encryption — the key is stored in the repo itself, so you only need the passphrase (not a separate keyfile). The passphrase is recorded on your Emergency Kit alongside the 1Password credentials. ## Related -- 2.50.1 (Apple Git-155)