From 3f6af244f69803f45136256d77c56cecd07da4ba Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Mon, 19 Jan 2026 17:38:48 -0800 Subject: [PATCH 1/4] Fix borgmatic borg path and add k8s-pg ACL grant - Add local_path option to borgmatic config for borg binary - Add ACL grant for tag:homelab -> tag:k8s on port 5432 Co-Authored-By: Claude Opus 4.5 --- ansible/roles/borgmatic/defaults/main.yml | 3 +++ ansible/roles/borgmatic/templates/config.yaml.j2 | 3 +++ pulumi/policy.hujson | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/ansible/roles/borgmatic/defaults/main.yml b/ansible/roles/borgmatic/defaults/main.yml index a62e5de..0189321 100644 --- a/ansible/roles/borgmatic/defaults/main.yml +++ b/ansible/roles/borgmatic/defaults/main.yml @@ -3,6 +3,9 @@ borgmatic_config: /Users/erichblume/.config/borgmatic/config.yaml borgmatic_config_dir: /Users/erichblume/.config/borgmatic borgmatic_log_dir: /Users/erichblume/Library/Logs +# Full path to borg binary since LaunchAgent doesn't have homebrew in PATH +borgmatic_local_path: /opt/homebrew/bin/borg + # Schedule: runs daily at 2:00 AM borgmatic_schedule_hour: 2 borgmatic_schedule_minute: 0 diff --git a/ansible/roles/borgmatic/templates/config.yaml.j2 b/ansible/roles/borgmatic/templates/config.yaml.j2 index 6bfb835..2e2bf0f 100644 --- a/ansible/roles/borgmatic/templates/config.yaml.j2 +++ b/ansible/roles/borgmatic/templates/config.yaml.j2 @@ -1,5 +1,8 @@ # {{ ansible_managed }} +# Path to borg binary (LaunchAgent doesn't have homebrew in PATH) +local_path: {{ borgmatic_local_path }} + source_directories: {% for dir in borgmatic_source_directories %} - {{ dir }} diff --git a/pulumi/policy.hujson b/pulumi/policy.hujson index c575037..142326b 100644 --- a/pulumi/policy.hujson +++ b/pulumi/policy.hujson @@ -74,6 +74,12 @@ "dst": ["tag:homelab"], "ip": ["tcp:3001", "tcp:2200"], }, + // Homelab can reach k8s PostgreSQL for borgmatic backups + { + "src": ["tag:homelab"], + "dst": ["tag:k8s"], + "ip": ["tcp:5432"], + }, ], // ============== SSH Access ============== -- 2.50.1 (Apple Git-155) From 420aaf56964c4e781d132d260ec3627c92a203b7 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Mon, 19 Jan 2026 17:39:27 -0800 Subject: [PATCH 2/4] Add borgmatic user to k8s-pg via CloudNativePG - Create secret-borgmatic.yaml.tpl for 1Password integration - Add borgmatic managed role with pg_read_all_data privilege - Update README with borgmatic user documentation Co-Authored-By: Claude Opus 4.5 --- argocd/manifests/databases/README.md | 16 ++++++++++------ argocd/manifests/databases/blumeops-pg.yaml | 8 ++++++++ .../databases/secret-borgmatic.yaml.tpl | 13 +++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 argocd/manifests/databases/secret-borgmatic.yaml.tpl diff --git a/argocd/manifests/databases/README.md b/argocd/manifests/databases/README.md index 7696217..c82f4d1 100644 --- a/argocd/manifests/databases/README.md +++ b/argocd/manifests/databases/README.md @@ -14,15 +14,16 @@ Single-instance PostgreSQL cluster for blumeops services. ### Users/Roles -| User | Role | Purpose | Password Source | -|----------|-------------|----------------------------------|------------------------------------| -| postgres | superuser | CNPG internal (avoid using) | `blumeops-pg-superuser` secret | -| miniflux | app owner | Owns miniflux database | `blumeops-pg-app` secret | -| eblume | superuser | Admin access (matches brew pg) | `blumeops-pg-eblume` secret (manual) | +| User | Role | Purpose | Password Source | +|-----------|----------------|----------------------------------|---------------------------------------| +| postgres | superuser | CNPG internal (avoid using) | `blumeops-pg-superuser` secret | +| miniflux | app owner | Owns miniflux database | `blumeops-pg-app` secret | +| eblume | superuser | Admin access (matches brew pg) | `blumeops-pg-eblume` secret (manual) | +| borgmatic | pg_read_all_data | Backup access for borgmatic | `blumeops-pg-borgmatic` secret (manual) | ### Manual Secret Setup -Before deploying, create the eblume password secret: +Before deploying, create the password secrets: ```bash # Create namespace first @@ -30,6 +31,9 @@ kubectl create namespace databases # Apply eblume password from 1Password op inject -i argocd/manifests/databases/secret-eblume.yaml.tpl | kubectl apply -f - + +# Apply borgmatic password from 1Password +op inject -i argocd/manifests/databases/secret-borgmatic.yaml.tpl | kubectl apply -f - ``` The `miniflux` user password is auto-generated by CloudNativePG and stored in `blumeops-pg-app`. diff --git a/argocd/manifests/databases/blumeops-pg.yaml b/argocd/manifests/databases/blumeops-pg.yaml index 93d30a2..3834c43 100644 --- a/argocd/manifests/databases/blumeops-pg.yaml +++ b/argocd/manifests/databases/blumeops-pg.yaml @@ -29,6 +29,14 @@ spec: createrole: true passwordSecret: name: blumeops-pg-eblume + # borgmatic read-only user for backups + - name: borgmatic + login: true + superuser: false + inRoles: + - pg_read_all_data + passwordSecret: + name: blumeops-pg-borgmatic # Resource limits for minikube environment resources: diff --git a/argocd/manifests/databases/secret-borgmatic.yaml.tpl b/argocd/manifests/databases/secret-borgmatic.yaml.tpl new file mode 100644 index 0000000..5aff760 --- /dev/null +++ b/argocd/manifests/databases/secret-borgmatic.yaml.tpl @@ -0,0 +1,13 @@ +# Template for borgmatic backup user password +# Apply with: op inject -i secret-borgmatic.yaml.tpl | kubectl apply -f - +# +# Uses the same borgmatic password from 1Password as the brew PostgreSQL setup +apiVersion: v1 +kind: Secret +metadata: + name: blumeops-pg-borgmatic + namespace: databases +type: kubernetes.io/basic-auth +stringData: + username: borgmatic + password: {{ op://vg6xf6vvfmoh5hqjjhlhbeoaie/mw2bv5we7woicjza7hc6s44yvy/password }} -- 2.50.1 (Apple Git-155) From ec1198f5f450c057a0421d99fbbd796477257ea1 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Mon, 19 Jan 2026 17:46:47 -0800 Subject: [PATCH 3/4] Fix apps selfHeal and borgmatic secret field name - Disable selfHeal on apps app to allow manual revision changes during dev - Fix secret-borgmatic.yaml.tpl to use db-password field Co-Authored-By: Claude Opus 4.5 --- argocd/apps/apps.yaml | 5 ++--- argocd/manifests/databases/secret-borgmatic.yaml.tpl | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/argocd/apps/apps.yaml b/argocd/apps/apps.yaml index 787ab7d..ec0d5ac 100644 --- a/argocd/apps/apps.yaml +++ b/argocd/apps/apps.yaml @@ -17,8 +17,7 @@ spec: syncPolicy: automated: prune: true - selfHeal: true + # selfHeal disabled: allows manual revision changes on child apps during development + # Sync apps app manually when adding/removing Application manifests syncOptions: - CreateNamespace=true - # Auto-sync enabled: new/changed Application manifests appear automatically - # but child apps still require manual sync (they have manual sync policy) diff --git a/argocd/manifests/databases/secret-borgmatic.yaml.tpl b/argocd/manifests/databases/secret-borgmatic.yaml.tpl index 5aff760..6a1c52a 100644 --- a/argocd/manifests/databases/secret-borgmatic.yaml.tpl +++ b/argocd/manifests/databases/secret-borgmatic.yaml.tpl @@ -10,4 +10,4 @@ metadata: type: kubernetes.io/basic-auth stringData: username: borgmatic - password: {{ op://vg6xf6vvfmoh5hqjjhlhbeoaie/mw2bv5we7woicjza7hc6s44yvy/password }} + password: {{ op://vg6xf6vvfmoh5hqjjhlhbeoaie/mw2bv5we7woicjza7hc6s44yvy/db-password }} -- 2.50.1 (Apple Git-155) From be688bd10d964d97ae5d88675230e9a1ee3d3d88 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Mon, 19 Jan 2026 17:51:52 -0800 Subject: [PATCH 4/4] Configure borgmatic to backup k8s-pg PostgreSQL - Add k8s-pg database entry to borgmatic config - Add k8s-pg entry to pgpass for borgmatic access Co-Authored-By: Claude Opus 4.5 --- ansible/roles/borgmatic/defaults/main.yml | 6 ++++++ ansible/roles/postgresql/tasks/main.yml | 1 + 2 files changed, 7 insertions(+) diff --git a/ansible/roles/borgmatic/defaults/main.yml b/ansible/roles/borgmatic/defaults/main.yml index 0189321..8fae283 100644 --- a/ansible/roles/borgmatic/defaults/main.yml +++ b/ansible/roles/borgmatic/defaults/main.yml @@ -45,7 +45,13 @@ borgmatic_keep_yearly: 1000 # pg_dump_command must be full path since LaunchAgent doesn't have homebrew in PATH borgmatic_pg_dump_command: /opt/homebrew/opt/postgresql@18/bin/pg_dump borgmatic_postgresql_databases: + # Brew PostgreSQL on indri (current production) - name: miniflux hostname: localhost port: 5432 username: borgmatic + # k8s PostgreSQL (CloudNativePG) - backup both during migration + - name: miniflux + hostname: k8s-pg.tail8d86e.ts.net + port: 5432 + username: borgmatic diff --git a/ansible/roles/postgresql/tasks/main.yml b/ansible/roles/postgresql/tasks/main.yml index 851a01e..c79ffd5 100644 --- a/ansible/roles/postgresql/tasks/main.yml +++ b/ansible/roles/postgresql/tasks/main.yml @@ -184,6 +184,7 @@ content: | # Managed by ansible - only read-only roles localhost:{{ postgresql_port }}:*:borgmatic:{{ postgresql_user_passwords['borgmatic'] }} + k8s-pg.tail8d86e.ts.net:5432:*:borgmatic:{{ postgresql_user_passwords['borgmatic'] }} dest: ~/.pgpass mode: '0600' no_log: true -- 2.50.1 (Apple Git-155)