finished change-password
This commit is contained in:
parent
a4deb8143b
commit
b415956a35
14 changed files with 216 additions and 405 deletions
|
@ -5,6 +5,7 @@ ADD resources /tmp/
|
||||||
RUN /tmp/install.sh
|
RUN /tmp/install.sh
|
||||||
ADD local/ /usr/local/lib/dda-backup
|
ADD local/ /usr/local/lib/dda-backup
|
||||||
RUN init-bb.bb
|
RUN init-bb.bb
|
||||||
#ADD resources2 /tmp/
|
# ADD resources2 /tmp/
|
||||||
#RUN install -m 0700 -o root -g root /tmp/test.bb /usr/local/bin/
|
# RUN install -m 0700 -o root -g root /tmp/test.bb /usr/local/bin/
|
||||||
#RUN test.bb
|
# RUN install -m 0700 -o root -g root /tmp/check.bb /usr/local/bin/
|
||||||
|
# RUN test.bb
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
(require '[dda.backup.cred-rot :as cr])
|
(require '[dda.backup.cred-rot :as cr])
|
||||||
|
|
||||||
(def restic-repo {:password-file "/restic-pwd"
|
(def restic-repo {:password-file "/restic-pwd"
|
||||||
:restic-repository "/restic-repo"})
|
:restic-repository "/restic-repo"
|
||||||
|
:debug true})
|
||||||
|
|
||||||
(def file-config (merge restic-repo {:backup-path "files"
|
(def file-config (merge restic-repo {:backup-path "files"
|
||||||
:files ["/test-backup"]
|
:files ["/test-backup"]
|
||||||
|
@ -12,7 +13,7 @@
|
||||||
(def cred-config (merge file-config
|
(def cred-config (merge file-config
|
||||||
{:restic-repository "/restic-repo/files"
|
{:restic-repository "/restic-repo/files"
|
||||||
:new-password-config {:new-password-file "/new-pw"
|
:new-password-config {:new-password-file "/new-pw"
|
||||||
:valid-from "2024-12-12 00:00:00"}}))
|
:valid-from "2024-12-17 00:00:00"}}))
|
||||||
|
|
||||||
|
|
||||||
(def dry-run {:dry-run true :debug true})
|
(def dry-run {:dry-run true :debug true})
|
||||||
|
|
23
infrastructure/backup/image/resources2/check.bb
Executable file
23
infrastructure/backup/image/resources2/check.bb
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env bb
|
||||||
|
|
||||||
|
(require '[dda.backup.restic :as rc])
|
||||||
|
|
||||||
|
(def restic-repo {:password-file "/restic-pwd"
|
||||||
|
:restic-repository "/restic-repo"
|
||||||
|
:debug true})
|
||||||
|
|
||||||
|
(def file-config (merge restic-repo {:backup-path "files"
|
||||||
|
:files ["/test-backup"]
|
||||||
|
:restore-target-directory "/test-restore"}))
|
||||||
|
|
||||||
|
(def cred-config (merge file-config {:new-password-file "new-pw"}))
|
||||||
|
|
||||||
|
|
||||||
|
(def dry-run {:dry-run true :debug true})
|
||||||
|
|
||||||
|
(defn restic-repo-check
|
||||||
|
[]
|
||||||
|
(println "restic-repo-check")
|
||||||
|
(println (rc/check file-config)))
|
||||||
|
|
||||||
|
(restic-repo-check)
|
|
@ -1,82 +1,57 @@
|
||||||
#!/usr/bin/env bb
|
#!/usr/bin/env bb
|
||||||
|
|
||||||
(require '[babashka.tasks :as tasks]
|
(require '[babashka.tasks :as tasks]
|
||||||
'[dda.backup.core :as bc]
|
|
||||||
'[dda.backup.cred-rot :as cr]
|
|
||||||
'[dda.backup.restic :as rc]
|
'[dda.backup.restic :as rc]
|
||||||
'[dda.backup.postgresql :as pg]
|
|
||||||
'[dda.backup.backup :as bak]
|
'[dda.backup.backup :as bak]
|
||||||
'[dda.backup.restore :as rs])
|
'[dda.backup.restore :as rs])
|
||||||
|
|
||||||
(def restic-repo {:password-file "restic-pwd"
|
(def restic-repo {:password-file "/restic-pwd"
|
||||||
:restic-repository "/restic-repo"})
|
:new-password-file "/new-restic-pwd"
|
||||||
|
:restic-repository "/restic-repo"
|
||||||
|
:debug true})
|
||||||
|
|
||||||
(def file-config (merge restic-repo {:backup-path "files"
|
(def file-config (merge restic-repo {:backup-path "files"
|
||||||
:files ["/test-backup"]
|
:files ["/test-backup"]
|
||||||
:restore-target-directory "/test-restore"}))
|
:restore-target-directory "/test-restore"}))
|
||||||
|
|
||||||
|
|
||||||
(def db-config (merge restic-repo {:backup-path "db"
|
|
||||||
:pg-db "mydb"
|
|
||||||
:pg-user "user"
|
|
||||||
:pg-password "password"}))
|
|
||||||
|
|
||||||
(def cred-config (merge file-config
|
|
||||||
{:restic-repository "/restic-repo/files"
|
|
||||||
:new-password-config {:new-password-file "new-pw"
|
|
||||||
:valid-from "2024-12-12 00:00:00"}}))
|
|
||||||
|
|
||||||
|
|
||||||
(def dry-run {:dry-run true :debug true})
|
(def dry-run {:dry-run true :debug true})
|
||||||
|
|
||||||
(defn prepare!
|
(defn prepare!
|
||||||
[]
|
[]
|
||||||
(spit "/tmp/file_password" "file-password")
|
(spit "/tmp/file_password" "file-password")
|
||||||
|
|
||||||
(spit "/restic-pwd" "ThePassword")
|
(spit "/restic-pwd" "oldPassword")
|
||||||
(spit "/new-pw" "newPassword")
|
(spit "/new-restic-pwd" "newPassword")
|
||||||
|
|
||||||
(tasks/shell "mkdir" "-p" "/test-backup")
|
(tasks/shell "mkdir" "-p" "/test-backup")
|
||||||
(spit "/test-backup/file" "I was here")
|
(spit "/test-backup/file" "I was here")
|
||||||
(tasks/shell "mkdir" "-p" "/test-restore")
|
(tasks/shell "mkdir" "-p" "/test-restore"))
|
||||||
(pg/create-pg-pass! db-config))
|
|
||||||
|
|
||||||
(defn check-env-or-file
|
|
||||||
[]
|
|
||||||
(println "check-env-or-file")
|
|
||||||
(println (bc/env-or-file "FILE_PASSWORD"))
|
|
||||||
(println (bc/env-or-file "ENV_PASSWORD")))
|
|
||||||
|
|
||||||
(defn restic-repo-init!
|
(defn restic-repo-init!
|
||||||
[]
|
[]
|
||||||
(println "restic-repo-init!")
|
(println "restic-repo-init!")
|
||||||
(rc/init! file-config)
|
(rc/init! file-config))
|
||||||
(rc/init! (merge db-config dry-run)))
|
|
||||||
|
|
||||||
(defn restic-backup!
|
(defn restic-backup!
|
||||||
[]
|
[]
|
||||||
(println "restic-backup!")
|
(println "restic-backup!")
|
||||||
(bak/backup-file! file-config)
|
(bak/backup-file! file-config))
|
||||||
(bak/backup-db! (merge db-config dry-run)))
|
|
||||||
|
|
||||||
(defn list-snapshots!
|
(defn list-snapshots!
|
||||||
[]
|
[]
|
||||||
(println "list-snapshots!")
|
(println "list-snapshots!")
|
||||||
(rc/list-snapshots! file-config)
|
(rc/list-snapshots! file-config))
|
||||||
(rc/list-snapshots! (merge db-config dry-run)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn restic-restore!
|
(defn restic-restore!
|
||||||
[]
|
[]
|
||||||
(println "restic-restore!")
|
(println "restic-restore!")
|
||||||
(rs/restore-file! file-config)
|
(rs/restore-file! file-config))
|
||||||
(pg/drop-create-db! (merge db-config dry-run))
|
|
||||||
(rs/restore-db! (merge db-config dry-run)))
|
|
||||||
|
|
||||||
(defn change-password!
|
(defn change-password!
|
||||||
[]
|
[]
|
||||||
(println "change-password!")
|
(println "change-password!")
|
||||||
(cr/change-password! cred-config))
|
(rc/change-password! file-config))
|
||||||
|
|
||||||
|
|
||||||
(prepare!)
|
(prepare!)
|
||||||
|
|
|
@ -2,39 +2,33 @@
|
||||||
|
|
||||||
(require '[babashka.tasks :as tasks]
|
(require '[babashka.tasks :as tasks]
|
||||||
'[dda.backup.core :as bc]
|
'[dda.backup.core :as bc]
|
||||||
'[dda.backup.cred-rot :as cr]
|
|
||||||
'[dda.backup.restic :as rc]
|
'[dda.backup.restic :as rc]
|
||||||
'[dda.backup.postgresql :as pg]
|
'[dda.backup.postgresql :as pg]
|
||||||
'[dda.backup.backup :as bak]
|
'[dda.backup.backup :as bak]
|
||||||
'[dda.backup.restore :as rs])
|
'[dda.backup.restore :as rs])
|
||||||
|
|
||||||
(def restic-repo {:password-file "restic-pwd"
|
(def restic-repo {:password-file "/restic-pwd"
|
||||||
:restic-repository "/restic-repo"})
|
:new-password-file "/new-restic-pwd"
|
||||||
|
:restic-repository "/restic-repo"
|
||||||
|
:debug true})
|
||||||
|
|
||||||
(def file-config (merge restic-repo {:backup-path "files"
|
(def file-config (merge restic-repo {:backup-path "files"
|
||||||
:files ["/test-backup"]
|
:files ["/test-backup"]
|
||||||
:restore-target-directory "/test-restore"}))
|
:restore-target-directory "/test-restore"}))
|
||||||
|
|
||||||
|
|
||||||
(def db-config (merge restic-repo {:backup-path "db"
|
(def db-config (merge restic-repo {:backup-path "db"
|
||||||
:pg-db "mydb"
|
:pg-db "mydb"
|
||||||
:pg-user "user"
|
:pg-user "user"
|
||||||
:pg-password "password"}))
|
:pg-password "password"}))
|
||||||
|
|
||||||
(def cred-config (merge file-config
|
|
||||||
{:restic-repository "/restic-repo/files"
|
|
||||||
:new-password-config {:new-password-file "new-pw"
|
|
||||||
:valid-from "2024-12-12 00:00:00"}}))
|
|
||||||
|
|
||||||
|
|
||||||
(def dry-run {:dry-run true :debug true})
|
(def dry-run {:dry-run true :debug true})
|
||||||
|
|
||||||
(defn prepare!
|
(defn prepare!
|
||||||
[]
|
[]
|
||||||
(spit "/tmp/file_password" "file-password")
|
(spit "/tmp/file_password" "file-password")
|
||||||
|
|
||||||
(spit "/restic-pwd" "ThePassword")
|
(spit "/restic-pwd" "oldPassword")
|
||||||
(spit "/new-pw" "newPassword")
|
(spit "/new-restic-pwd" "newPassword")
|
||||||
|
|
||||||
(tasks/shell "mkdir" "-p" "/test-backup")
|
(tasks/shell "mkdir" "-p" "/test-backup")
|
||||||
(spit "/test-backup/file" "I was here")
|
(spit "/test-backup/file" "I was here")
|
||||||
|
@ -43,41 +37,40 @@
|
||||||
|
|
||||||
(defn check-env-or-file
|
(defn check-env-or-file
|
||||||
[]
|
[]
|
||||||
(println "check-env-or-file")
|
(println "\ncheck-env-or-file")
|
||||||
(println (bc/env-or-file "FILE_PASSWORD"))
|
(println (bc/env-or-file "FILE_PASSWORD"))
|
||||||
(println (bc/env-or-file "ENV_PASSWORD")))
|
(println (bc/env-or-file "ENV_PASSWORD")))
|
||||||
|
|
||||||
(defn restic-repo-init!
|
(defn restic-repo-init!
|
||||||
[]
|
[]
|
||||||
(println "restic-repo-init!")
|
(println "\nrestic-repo-init!")
|
||||||
(rc/init! file-config)
|
(rc/init! file-config)
|
||||||
(rc/init! (merge db-config dry-run)))
|
(rc/init! (merge db-config dry-run)))
|
||||||
|
|
||||||
(defn restic-backup!
|
(defn restic-backup!
|
||||||
[]
|
[]
|
||||||
(println "restic-backup!")
|
(println "\nrestic-backup!")
|
||||||
(bak/backup-file! file-config)
|
(bak/backup-file! file-config)
|
||||||
(bak/backup-db! (merge db-config dry-run)))
|
(bak/backup-db! (merge db-config dry-run)))
|
||||||
|
|
||||||
(defn list-snapshots!
|
(defn list-snapshots!
|
||||||
[]
|
[]
|
||||||
(println "list-snapshots!")
|
(println "\nlist-snapshots!")
|
||||||
(rc/list-snapshots! file-config)
|
(rc/list-snapshots! file-config)
|
||||||
(rc/list-snapshots! (merge db-config dry-run)))
|
(rc/list-snapshots! (merge db-config dry-run)))
|
||||||
|
|
||||||
|
|
||||||
(defn restic-restore!
|
(defn restic-restore!
|
||||||
[]
|
[]
|
||||||
(println "restic-restore!")
|
(println "\nrestic-restore!")
|
||||||
(rs/restore-file! file-config)
|
(rs/restore-file! file-config)
|
||||||
(pg/drop-create-db! (merge db-config dry-run))
|
(pg/drop-create-db! (merge db-config dry-run))
|
||||||
(rs/restore-db! (merge db-config dry-run)))
|
(rs/restore-db! (merge db-config dry-run)))
|
||||||
|
|
||||||
(defn change-password!
|
(defn change-password!
|
||||||
[]
|
[]
|
||||||
(println "change-password!")
|
(println "\nchange-password!")
|
||||||
(cr/change-password! cred-config))
|
(rc/change-password! file-config))
|
||||||
|
|
||||||
|
|
||||||
(prepare!)
|
(prepare!)
|
||||||
(check-env-or-file)
|
(check-env-or-file)
|
||||||
|
@ -86,3 +79,6 @@
|
||||||
(list-snapshots!)
|
(list-snapshots!)
|
||||||
(restic-restore!)
|
(restic-restore!)
|
||||||
(change-password!)
|
(change-password!)
|
||||||
|
(restic-backup!)
|
||||||
|
(list-snapshots!)
|
||||||
|
(restic-restore!)
|
||||||
|
|
|
@ -26,25 +26,31 @@
|
||||||
(s/merge ::pg/pg-config
|
(s/merge ::pg/pg-config
|
||||||
::restic/restic-config))
|
::restic/restic-config))
|
||||||
|
|
||||||
|
(defn- config-w-defaults
|
||||||
|
[config]
|
||||||
|
(if (restic/use-new-password? config)
|
||||||
|
(merge default config {:password-file (:new-password-file config)})
|
||||||
|
(merge default config)))
|
||||||
|
|
||||||
(defn-spec backup-file! nil?
|
(defn-spec backup-file! nil?
|
||||||
[config ::backup-file-config]
|
[config ::backup-file-config]
|
||||||
(let [config-w-defaults (merge default config)]
|
(let [config-2-use (config-w-defaults config)]
|
||||||
(restic/unlock! config-w-defaults)
|
(restic/unlock! config-2-use)
|
||||||
(i/execute!
|
(i/execute!
|
||||||
(domain/backup-files-command config-w-defaults)
|
(domain/backup-files-command config-2-use)
|
||||||
config-w-defaults)
|
config-2-use)
|
||||||
(restic/forget! config-w-defaults)))
|
(restic/forget! config-2-use)))
|
||||||
|
|
||||||
(defn-spec backup-db-roles! nil?
|
(defn-spec backup-db-roles! nil?
|
||||||
[config ::pg-role-dump-config]
|
[config ::pg-role-dump-config]
|
||||||
(let [config-w-defaults (merge default config)]
|
(let [config-2-use (config-w-defaults config)]
|
||||||
(restic/unlock! config-w-defaults)
|
(restic/unlock! config-2-use)
|
||||||
(i/execute! (domain/backup-role-command config-w-defaults) config-w-defaults)
|
(i/execute! (domain/backup-role-command config-2-use) config-2-use)
|
||||||
(restic/forget! config-w-defaults)))
|
(restic/forget! config-2-use)))
|
||||||
|
|
||||||
(defn-spec backup-db! nil?
|
(defn-spec backup-db! nil?
|
||||||
[config ::pg-db-dump-config]
|
[config ::pg-db-dump-config]
|
||||||
(let [config-w-defaults (merge default config)]
|
(let [config-2-use (config-w-defaults config)]
|
||||||
(restic/unlock! config-w-defaults)
|
(restic/unlock! config-2-use)
|
||||||
(i/execute! (domain/backup-db-command config-w-defaults) config-w-defaults)
|
(i/execute! (domain/backup-db-command config-2-use) config-2-use)
|
||||||
(restic/forget! config-w-defaults)))
|
(restic/forget! config-2-use)))
|
|
@ -1,72 +0,0 @@
|
||||||
(ns dda.backup.cred-rot
|
|
||||||
(:require
|
|
||||||
[orchestra.core :refer [defn-spec]]
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[dda.backup.cred-rot.domain :as domain]
|
|
||||||
[dda.backup.infrastructure :as i]
|
|
||||||
[cljc.java-time.instant :as inst]
|
|
||||||
[cljc.java-time.local-date :as ld]))
|
|
||||||
|
|
||||||
(s/def ::replace-until domain/timestamp?)
|
|
||||||
(s/def ::new-password-file string?)
|
|
||||||
(s/def ::new-password-config (s/keys :req-un [::new-password-file ::replace-until]))
|
|
||||||
|
|
||||||
(s/def ::cred-rot
|
|
||||||
(s/keys :req-un []
|
|
||||||
:opt-un [::new-password-config]))
|
|
||||||
|
|
||||||
; Refer to "docs/CredentialRotation.md" for specifics
|
|
||||||
(defn-spec list-passwords! string?
|
|
||||||
[config ::cred-rot]
|
|
||||||
(i/execute-out! (domain/list-passwords-command config) config))
|
|
||||||
|
|
||||||
(defn-spec change-password-step! ::domain/set-password-action
|
|
||||||
[config ::cred-rot]
|
|
||||||
(when-some [new-password-config (:new-password-config config)]
|
|
||||||
(let [initial-passwords-list (domain/parse-response (list-passwords! config))
|
|
||||||
action (domain/set-new-password-action
|
|
||||||
(ld/now)
|
|
||||||
initial-passwords-list
|
|
||||||
config)]
|
|
||||||
(cond
|
|
||||||
(= action :wait-for-new-pwd)
|
|
||||||
(println "nothing to do.")
|
|
||||||
(= action :change-pwd)
|
|
||||||
(i/execute! (domain/change-password-command config) config)
|
|
||||||
(= action :new-pwd-change-finished)
|
|
||||||
(println "pw-change sucessfull")
|
|
||||||
(= action :no-pwd-change-needed)
|
|
||||||
(println "nothing to do.")
|
|
||||||
:else
|
|
||||||
(throw (Exception. (str action)))
|
|
||||||
)
|
|
||||||
(println initial-passwords-list)
|
|
||||||
(println action)
|
|
||||||
(println (list-passwords! config))
|
|
||||||
action
|
|
||||||
)))
|
|
||||||
|
|
||||||
(defn-spec change-password! nil?
|
|
||||||
[config ::cred-rot]
|
|
||||||
(while (let [action (change-password-step! config) ]
|
|
||||||
(and (not= :no-pwd-change-needed action)
|
|
||||||
(not= :wait-for-new-pwd action)))
|
|
||||||
(println "call step")
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
(defn-spec set-new-password-old! nil?
|
|
||||||
[config ::cred-rot]
|
|
||||||
(let [{:keys [new-password-file replace-until]} (:new-password-config config)
|
|
||||||
replace-until-date (ld/parse "2024-10-19 13:16:54" domain/timestamp-formatter)]
|
|
||||||
(if (not (nil? new-password-file))
|
|
||||||
(let [parsed-passwords (domain/parse-response (list-passwords! config))]
|
|
||||||
(println (str "add-new-password: relace until " replace-until))
|
|
||||||
(cond
|
|
||||||
(> 0 (compare
|
|
||||||
(:created (last parsed-passwords))
|
|
||||||
replace-until-date))
|
|
||||||
(do (println "add-new-password: set new pw")
|
|
||||||
(i/execute! (domain/add-password-command config) config))
|
|
||||||
:else (println (str "else " (inst/now)))))
|
|
||||||
(println "add-new-password: there was no new pw configured"))))
|
|
|
@ -1,111 +0,0 @@
|
||||||
(ns dda.backup.cred-rot.domain
|
|
||||||
(:require
|
|
||||||
[orchestra.core :refer [defn-spec]]
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[clojure.string :as str]
|
|
||||||
[dda.backup.core.domain :as cd]
|
|
||||||
[dda.backup.restic.domain :as rd]
|
|
||||||
[cheshire.core :as cc]
|
|
||||||
[cljc.java-time.local-date :as ld]
|
|
||||||
[cljc.java-time.format.date-time-formatter :as df]))
|
|
||||||
|
|
||||||
(s/def ::new-password-file string?)
|
|
||||||
(s/def ::config (s/keys :req-un [::rd/restic-repository
|
|
||||||
::rd/password-file]
|
|
||||||
:opt-un [::rd/certificate-file
|
|
||||||
::new-password-file]))
|
|
||||||
|
|
||||||
(def lowercase-numeric #"[a-z0-9]+")
|
|
||||||
(def alphanumeric #"[a-zA-Z0-9]+")
|
|
||||||
; true | false
|
|
||||||
(s/def ::current boolean?)
|
|
||||||
; 521e0760
|
|
||||||
(s/def ::id (s/and string? #(re-matches lowercase-numeric %)))
|
|
||||||
; root
|
|
||||||
(s/def ::userName #(re-matches alphanumeric %))
|
|
||||||
; backup-restore-65bd9b6ff5-z69sn
|
|
||||||
(s/def ::hostName (fn [in] (every? #(re-matches lowercase-numeric %) (str/split in #"-"))))
|
|
||||||
; "2024-10-18 13:08:16"
|
|
||||||
(def timestamp-formatter (df/of-pattern "yyyy-MM-dd HH:mm:ss"))
|
|
||||||
(defn timestamp-string? [in]
|
|
||||||
(try
|
|
||||||
(ld/parse in timestamp-formatter)
|
|
||||||
true
|
|
||||||
(catch Exception _ false)))
|
|
||||||
(def timestamp? any?)
|
|
||||||
|
|
||||||
(s/def ::created timestamp?)
|
|
||||||
|
|
||||||
(s/def ::entry (s/keys :opt-un []
|
|
||||||
:req-un [::current ::id ::userName ::hostName ::created]))
|
|
||||||
(s/def ::response (s/coll-of ::entry))
|
|
||||||
|
|
||||||
(s/def ::set-password-action #{:error-parse-password :error-undefined
|
|
||||||
:wait-for-new-pwd :change-pwd :pwd-change-finished :no-pwd-change-needed})
|
|
||||||
|
|
||||||
(s/def ::valid-from timestamp-string?)
|
|
||||||
(s/def ::new-password-file string?)
|
|
||||||
(s/def ::new-password-config (s/keys :req-un [::new-password-file ::valid-from]))
|
|
||||||
|
|
||||||
(s/def ::cred-rot
|
|
||||||
(s/keys :req-un []
|
|
||||||
:opt-un [::new-password-config]))
|
|
||||||
|
|
||||||
; Refer to "docs/CredentialRotation.md" for specifics
|
|
||||||
(defn-spec base-command ::cd/command
|
|
||||||
[config ::config
|
|
||||||
command ::cd/command]
|
|
||||||
(let [{:keys [restic-repository password-file
|
|
||||||
certificate-file new-password-file]} config]
|
|
||||||
(into
|
|
||||||
[]
|
|
||||||
(concat ["restic" "-r" restic-repository]
|
|
||||||
(cond
|
|
||||||
(some? certificate-file)
|
|
||||||
["--cacert" certificate-file]
|
|
||||||
(some? password-file)
|
|
||||||
["--password-file" password-file]
|
|
||||||
:else
|
|
||||||
[])
|
|
||||||
command))))
|
|
||||||
|
|
||||||
(defn-spec list-passwords-command ::cd/command
|
|
||||||
[config ::config]
|
|
||||||
(base-command config ["key" "list" "--json"]))
|
|
||||||
|
|
||||||
(defn-spec change-password-command ::cd/command
|
|
||||||
[config ::config]
|
|
||||||
(let [{:keys [new-password-file]} (:new-password-config config)]
|
|
||||||
[(base-command config ["--new-password-file" new-password-file "key" "passwd"])]))
|
|
||||||
|
|
||||||
(defn-spec parse-response ::response
|
|
||||||
[response string?]
|
|
||||||
(->> (cc/parse-string response true)
|
|
||||||
(map #(merge % {:created (ld/parse (:created %) timestamp-formatter)}))
|
|
||||||
(sort-by :created)
|
|
||||||
))
|
|
||||||
|
|
||||||
(defn-spec set-new-password-action ::set-password-action
|
|
||||||
[current-date timestamp?
|
|
||||||
parsed-response ::response
|
|
||||||
config ::cred-rot]
|
|
||||||
(if-let [new-password-config (:new-password-config config)]
|
|
||||||
(let [valid-from (:valid-from new-password-config)
|
|
||||||
valid-from-date (ld/parse valid-from timestamp-formatter)]
|
|
||||||
(cond
|
|
||||||
(> 1 (count parsed-response))
|
|
||||||
:error-parse-password
|
|
||||||
(> 0 (compare current-date valid-from-date))
|
|
||||||
:wait-for-new-pwd
|
|
||||||
(and (<= 0 (compare current-date valid-from-date))
|
|
||||||
(= 1 (count parsed-response))
|
|
||||||
(> 0 (compare (:created (last parsed-response)) valid-from-date)))
|
|
||||||
:change-pwd
|
|
||||||
(and (<= 0 (compare current-date valid-from-date))
|
|
||||||
(= 1 (count parsed-response))
|
|
||||||
(<= 0 (compare (:created (last parsed-response)) valid-from-date))
|
|
||||||
(:current (last parsed-response)))
|
|
||||||
:pwd-change-finished
|
|
||||||
:else
|
|
||||||
:error-undefined))
|
|
||||||
:no-pwd-change-needed))
|
|
|
@ -3,16 +3,6 @@
|
||||||
[babashka.tasks :as t]
|
[babashka.tasks :as t]
|
||||||
[dda.backup.core.domain :as core]))
|
[dda.backup.core.domain :as core]))
|
||||||
|
|
||||||
(defn-spec execute! nil?
|
|
||||||
[commands ::core/commands
|
|
||||||
config ::core/execution]
|
|
||||||
(let [{:keys [dry-run debug]} config]
|
|
||||||
(doseq [c commands]
|
|
||||||
(when debug
|
|
||||||
(println c))
|
|
||||||
(when-not dry-run
|
|
||||||
(apply t/shell c)))))
|
|
||||||
|
|
||||||
(defn-spec execute-out! string?
|
(defn-spec execute-out! string?
|
||||||
[command ::core/command
|
[command ::core/command
|
||||||
config ::core/execution]
|
config ::core/execution]
|
||||||
|
@ -20,4 +10,22 @@
|
||||||
(when debug
|
(when debug
|
||||||
(println command))
|
(println command))
|
||||||
(when-not dry-run
|
(when-not dry-run
|
||||||
(:out (t/shell {:out :string} (clojure.string/join " " command))))))
|
(:out (t/shell {:out :string :err :string} (clojure.string/join " " command))))))
|
||||||
|
|
||||||
|
(defn-spec execute-single! string?
|
||||||
|
[command ::core/command
|
||||||
|
config ::core/execution]
|
||||||
|
(let [{:keys [dry-run debug]} config]
|
||||||
|
(when debug
|
||||||
|
(println command))
|
||||||
|
(when-not dry-run
|
||||||
|
(:out (t/shell {:err :string} (clojure.string/join " " command))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn-spec execute! nil?
|
||||||
|
[commands ::core/commands
|
||||||
|
config ::core/execution]
|
||||||
|
(let [{:keys [dry-run debug]} config]
|
||||||
|
(doseq [c commands]
|
||||||
|
(when-not dry-run
|
||||||
|
(execute-single! c config)))))
|
|
@ -17,34 +17,72 @@
|
||||||
::domain/backup-path]
|
::domain/backup-path]
|
||||||
:opt-un [::domain/certificate-file
|
:opt-un [::domain/certificate-file
|
||||||
::domain/password-file
|
::domain/password-file
|
||||||
|
::domain/new-password-file
|
||||||
::domain/days-to-keep
|
::domain/days-to-keep
|
||||||
::domain/months-to-keep])))
|
::domain/months-to-keep])))
|
||||||
|
|
||||||
(defn-spec initalized? boolean?
|
(s/def ::check-result #{:initialized :wrong-password :not-initialized :error})
|
||||||
|
|
||||||
|
(defn-spec check ::check-result
|
||||||
[restic-config ::restic-config]
|
[restic-config ::restic-config]
|
||||||
(let [config-w-defaults (merge core/default restic-config)]
|
(let [config-w-defaults (merge core/default restic-config)]
|
||||||
(try
|
(try
|
||||||
(i/execute! (domain/check-repo-command config-w-defaults) config-w-defaults)
|
(i/execute! (domain/check-repo-command config-w-defaults) config-w-defaults)
|
||||||
true
|
:initialized
|
||||||
(catch Exception e false))))
|
(catch Exception e
|
||||||
|
(let [data (ex-data e)
|
||||||
|
parsed-error (domain/parse-check-error (get-in data [:proc :err]))]
|
||||||
|
(cond
|
||||||
|
(= parsed-error :not-initialized) :not-initialized
|
||||||
|
(= parsed-error :wrong-password) :wrong-password
|
||||||
|
:default :error))))))
|
||||||
|
|
||||||
|
(defn-spec use-new-password? boolean?
|
||||||
|
"deprecated"
|
||||||
|
[restic-config ::restic-config]
|
||||||
|
(if (contains? restic-config :new-password-file)
|
||||||
|
(= :initialized (check (merge restic-config {:password-file (:new-password-file restic-config)})))
|
||||||
|
false))
|
||||||
|
|
||||||
|
(defn- config-w-defaults
|
||||||
|
[restic-config]
|
||||||
|
(if (use-new-password? restic-config)
|
||||||
|
(merge default restic-config {:password-file (:new-password-file restic-config)})
|
||||||
|
(merge default restic-config)))
|
||||||
|
|
||||||
|
(defn-spec initalized? boolean?
|
||||||
|
"deprecated"
|
||||||
|
[restic-config ::restic-config]
|
||||||
|
(let [config-2-use (config-w-defaults restic-config)]
|
||||||
|
(= :initialized (check config-2-use))))
|
||||||
|
|
||||||
(defn-spec init! nil?
|
(defn-spec init! nil?
|
||||||
[restic-config ::restic-config]
|
[restic-config ::restic-config]
|
||||||
(let [config-w-defaults (merge core/default restic-config)]
|
(let [config-2-use (config-w-defaults restic-config)]
|
||||||
(when (not (initalized? config-w-defaults))
|
(when (= :not-initialized (check config-2-use))
|
||||||
(i/execute! (domain/init-repo-command config-w-defaults) config-w-defaults))))
|
(i/execute! (domain/init-repo-command config-2-use) config-2-use))))
|
||||||
|
|
||||||
(defn-spec unlock! nil?
|
(defn-spec unlock! nil?
|
||||||
[restic-config ::restic-config]
|
[restic-config ::restic-config]
|
||||||
(let [config-w-defaults (merge core/default restic-config)]
|
(let [config-2-use (config-w-defaults restic-config)]
|
||||||
(i/execute! (domain/unlock-repo-command config-w-defaults) config-w-defaults)))
|
(i/execute! (domain/unlock-repo-command config-2-use) config-2-use)))
|
||||||
|
|
||||||
(defn-spec forget! nil?
|
(defn-spec forget! nil?
|
||||||
[restic-config ::restic-config]
|
[restic-config ::restic-config]
|
||||||
(let [config-w-defaults (merge core/default restic-config)]
|
(let [config-2-use (config-w-defaults restic-config)]
|
||||||
(i/execute! (domain/forget-command config-w-defaults) config-w-defaults)))
|
(i/execute! (domain/forget-command config-2-use) config-2-use)))
|
||||||
|
|
||||||
(defn-spec list-snapshots! nil?
|
(defn-spec list-snapshots! nil?
|
||||||
[restic-config ::restic-config]
|
[restic-config ::restic-config]
|
||||||
(let [config-w-defaults (merge core/default restic-config)]
|
(let [config-2-use (config-w-defaults restic-config)]
|
||||||
(i/execute! (domain/list-snapshot-command config-w-defaults) config-w-defaults)))
|
(i/execute! (domain/list-snapshot-command config-2-use) config-2-use)))
|
||||||
|
|
||||||
|
(defn-spec change-password! nil?
|
||||||
|
[restic-config ::restic-config]
|
||||||
|
(when (contains? restic-config :new-password-file)
|
||||||
|
(let [config-2-use (merge core/default restic-config)]
|
||||||
|
(when (= :initialized (check config-2-use))
|
||||||
|
(do
|
||||||
|
(i/execute! (domain/change-password-command config-2-use) config-2-use)
|
||||||
|
(when-not (= :wrong-password (check config-2-use))
|
||||||
|
(throw (Exception. "password-change did not work!"))))))))
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(s/def ::certificate-file string?)
|
(s/def ::certificate-file string?)
|
||||||
(s/def ::password-file string?)
|
(s/def ::password-file string?)
|
||||||
|
(s/def ::new-password-file string?)
|
||||||
(s/def ::restic-repository string?)
|
(s/def ::restic-repository string?)
|
||||||
(s/def ::backup-path string?)
|
(s/def ::backup-path string?)
|
||||||
(s/def ::days-to-keep pos?)
|
(s/def ::days-to-keep pos?)
|
||||||
|
@ -18,8 +19,11 @@
|
||||||
::months-to-keep]
|
::months-to-keep]
|
||||||
:opt-un [::certificate-file
|
:opt-un [::certificate-file
|
||||||
::password-file
|
::password-file
|
||||||
|
::new-password-file
|
||||||
::cd/execution-directory]))
|
::cd/execution-directory]))
|
||||||
|
|
||||||
|
(s/def ::check-error #{:not-initialized :wrong-password :no-password :unknown})
|
||||||
|
|
||||||
(defn-spec repo-command ::cd/command
|
(defn-spec repo-command ::cd/command
|
||||||
[config ::restic-config
|
[config ::restic-config
|
||||||
command ::cd/command]
|
command ::cd/command]
|
||||||
|
@ -60,7 +64,23 @@
|
||||||
(defn-spec forget-command ::cd/commands
|
(defn-spec forget-command ::cd/commands
|
||||||
[config ::restic-config]
|
[config ::restic-config]
|
||||||
(let [{:keys [days-to-keep months-to-keep]} config]
|
(let [{:keys [days-to-keep months-to-keep]} config]
|
||||||
[(repo-command config ["forget" "--group-by" ""
|
[(repo-command config ["forget" "--group-by" "''"
|
||||||
"--keep-last" "1"
|
"--keep-last" "1"
|
||||||
"--keep-daily" (str days-to-keep)
|
"--keep-daily" (str days-to-keep)
|
||||||
"--keep-monthly" (str months-to-keep) "--prune"])]))
|
"--keep-monthly" (str months-to-keep) "--prune"])]))
|
||||||
|
|
||||||
|
(defn-spec change-password-command ::cd/command
|
||||||
|
[config ::restic-config]
|
||||||
|
(if (contains? config :new-password-file)
|
||||||
|
(let [{:keys [new-password-file]} config]
|
||||||
|
[(repo-command config ["--new-password-file" new-password-file
|
||||||
|
"key" "passwd"])])
|
||||||
|
(throw (Exception. "change-password: new password required"))))
|
||||||
|
|
||||||
|
(defn-spec parse-check-error ::check-error
|
||||||
|
[error string?]
|
||||||
|
(cond
|
||||||
|
(clojure.string/includes? error "Fatal: unable to open config file") :not-initialized
|
||||||
|
(clojure.string/includes? error "Fatal: wrong password or no key found") :wrong-password
|
||||||
|
(clojure.string/includes? error "Resolving password failed") :no-password
|
||||||
|
:default :unknown))
|
||||||
|
|
|
@ -20,19 +20,26 @@
|
||||||
(s/merge ::pg/pg-config
|
(s/merge ::pg/pg-config
|
||||||
(s/keys :req-un [::domain/snapshot-id])))
|
(s/keys :req-un [::domain/snapshot-id])))
|
||||||
|
|
||||||
|
(defn- config-w-defaults
|
||||||
|
[config]
|
||||||
|
(if (restic/use-new-password? config)
|
||||||
|
(merge default config {:password-file (:new-password-file config)})
|
||||||
|
(merge default config)))
|
||||||
|
|
||||||
|
|
||||||
(defn-spec restore-file! nil?
|
(defn-spec restore-file! nil?
|
||||||
[config ::restore-file-config]
|
[config ::restore-file-config]
|
||||||
(let [config-w-defaults (merge default config)]
|
(let [config-2-use (config-w-defaults config)]
|
||||||
(restic/unlock! config-w-defaults)
|
(restic/unlock! config-2-use)
|
||||||
(i/execute!
|
(i/execute!
|
||||||
(domain/restore-dir-command config-w-defaults)
|
(domain/restore-dir-command config-2-use)
|
||||||
config-w-defaults)))
|
config-2-use)))
|
||||||
|
|
||||||
(defn-spec restore-db! nil?
|
(defn-spec restore-db! nil?
|
||||||
[config ::restore-db-config]
|
[config ::restore-db-config]
|
||||||
(let [config-w-defaults (merge default config)]
|
(let [config-2-use (config-w-defaults config)]
|
||||||
(restic/unlock! config-w-defaults)
|
(restic/unlock! config-2-use)
|
||||||
(i/execute! (domain/restore-db-command config-w-defaults) config-w-defaults)))
|
(i/execute! (domain/restore-db-command config-2-use) config-2-use)))
|
||||||
|
|
||||||
|
|
||||||
;; function restore-roles() {
|
;; function restore-roles() {
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
(ns dda.backup.cred-rot.domain-test
|
|
||||||
(:require
|
|
||||||
[clojure.test :refer [deftest is]]
|
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[clojure.spec.test.alpha :as st]
|
|
||||||
[cljc.java-time.local-date :as ld]
|
|
||||||
[dda.backup.cred-rot.domain :as cut]))
|
|
||||||
|
|
||||||
(deftest test-spec-id
|
|
||||||
(is (s/valid? ::cut/id "521e0760"))
|
|
||||||
(is (s/valid? ::cut/id "test"))
|
|
||||||
(is (s/valid? ::cut/id "123456"))
|
|
||||||
(is (not (s/valid? ::cut/id "ROOT")))
|
|
||||||
(is (not (s/valid? ::cut/id "Test!"))))
|
|
||||||
|
|
||||||
(deftest test-spec-username
|
|
||||||
(is (s/valid? ::cut/userName "521e0760"))
|
|
||||||
(is (s/valid? ::cut/userName "Testuser"))
|
|
||||||
(is (s/valid? ::cut/userName "root"))
|
|
||||||
(is (s/valid? ::cut/userName "ROOT"))
|
|
||||||
(is (not (s/valid? ::cut/userName "test-user"))))
|
|
||||||
|
|
||||||
(deftest test-spec-hostName
|
|
||||||
(let [valid #(s/valid? ::cut/hostName %)]
|
|
||||||
(is (valid "test-some-combination-2"))
|
|
||||||
(is (valid "backup-restore-65bd9b6ff5-z69sn"))))
|
|
||||||
|
|
||||||
(deftest test-spec-timestamp
|
|
||||||
(let [valid #(s/valid? cut/timestamp-string? %)]
|
|
||||||
(is (valid "2024-10-18 13:08:16"))
|
|
||||||
(is (valid "2032-09-01 12:56:59"))
|
|
||||||
(is (not (valid "2024-13-5 13:08:16")))
|
|
||||||
(is (not (valid "2024-6-42 13:08:16")))
|
|
||||||
(is (not (valid "test")))))
|
|
||||||
|
|
||||||
(deftest test-parse-response
|
|
||||||
(is (=
|
|
||||||
(ld/parse "2024-10-19 13:16:54" cut/timestamp-formatter)
|
|
||||||
(:created
|
|
||||||
(first
|
|
||||||
(cut/parse-response "[
|
|
||||||
{
|
|
||||||
\"current\": false,
|
|
||||||
\"id\": \"521e0760\",
|
|
||||||
\"userName\": \"root\",
|
|
||||||
\"hostName\": \"backup-restore-65bd9b6ff5-z69sn\",
|
|
||||||
\"created\": \"2024-11-18 13:08:16\"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
\"current\": true,
|
|
||||||
\"id\": \"b67161fb\",
|
|
||||||
\"userName\": \"root\",
|
|
||||||
\"hostName\": \"backup-restore-65bd9b6ff5-z69sn\",
|
|
||||||
\"created\": \"2024-10-19 13:16:54\"
|
|
||||||
}
|
|
||||||
]"))))))
|
|
||||||
|
|
||||||
(deftest test-set-new-password-action
|
|
||||||
(is (= :error-parse-password
|
|
||||||
(cut/set-new-password-action
|
|
||||||
(ld/parse "2024-10-19 13:16:54" cut/timestamp-formatter)
|
|
||||||
[]
|
|
||||||
{:new-password-config {:new-password-file "new-pw-file"
|
|
||||||
:valid-from "2024-11-29 12:00:16"}})))
|
|
||||||
(is (= :wait-for-new-pwd
|
|
||||||
(cut/set-new-password-action
|
|
||||||
(ld/parse "2024-10-19 13:16:54" cut/timestamp-formatter)
|
|
||||||
[{:current true
|
|
||||||
:id "a1"
|
|
||||||
:userName "root"
|
|
||||||
:hostName "host"
|
|
||||||
:created (ld/parse "2023-01-01 00:00:00" cut/timestamp-formatter)}]
|
|
||||||
{:new-password-config {:new-password-file "new-pw-file"
|
|
||||||
:valid-from "2024-11-29 12:00:16"}})))
|
|
||||||
(is (= :change-pwd
|
|
||||||
(cut/set-new-password-action
|
|
||||||
(ld/parse "2024-11-29 13:16:54" cut/timestamp-formatter)
|
|
||||||
[{:current true
|
|
||||||
:id "a1"
|
|
||||||
:userName "root"
|
|
||||||
:hostName "host"
|
|
||||||
:created (ld/parse "2023-01-01 00:00:00" cut/timestamp-formatter)}]
|
|
||||||
{:new-password-config {:new-password-file "new-pw-file"
|
|
||||||
:valid-from "2024-11-29 12:00:16"}})))
|
|
||||||
|
|
||||||
(is (= :pwd-change-finished
|
|
||||||
(cut/set-new-password-action
|
|
||||||
(ld/parse "2024-11-29 13:16:55" cut/timestamp-formatter)
|
|
||||||
[{:current true
|
|
||||||
:id "a2"
|
|
||||||
:userName "root"
|
|
||||||
:hostName "host"
|
|
||||||
:created (ld/parse "2024-11-29 13:16:54" cut/timestamp-formatter)}]
|
|
||||||
{:new-password-config {:new-password-file "new-pw-file"
|
|
||||||
:valid-from "2024-11-29 12:00:16"}})))
|
|
||||||
|
|
||||||
(is (= :no-pwd-change-needed
|
|
||||||
(cut/set-new-password-action
|
|
||||||
(ld/parse "2024-11-29 13:16:55" cut/timestamp-formatter)
|
|
||||||
[{:current true
|
|
||||||
:id "a2"
|
|
||||||
:userName "root"
|
|
||||||
:hostName "host"
|
|
||||||
:created (ld/parse "2024-11-29 13:16:54" cut/timestamp-formatter)}]
|
|
||||||
{})))
|
|
||||||
)
|
|
|
@ -64,9 +64,34 @@
|
||||||
|
|
||||||
(deftest should-calculate-forget-command
|
(deftest should-calculate-forget-command
|
||||||
(is (= [["restic" "-r" "repo/dir" "-v" "forget"
|
(is (= [["restic" "-r" "repo/dir" "-v" "forget"
|
||||||
"--group-by" "" "--keep-last" "1"
|
"--group-by" "''" "--keep-last" "1"
|
||||||
"--keep-daily" "39" "--keep-monthly" "3" "--prune"]]
|
"--keep-daily" "39" "--keep-monthly" "3" "--prune"]]
|
||||||
(cut/forget-command {:restic-repository "repo"
|
(cut/forget-command {:restic-repository "repo"
|
||||||
:backup-path "dir"
|
:backup-path "dir"
|
||||||
:days-to-keep 39
|
:days-to-keep 39
|
||||||
:months-to-keep 3}))))
|
:months-to-keep 3}))))
|
||||||
|
|
||||||
|
(deftest should-calculate-change-password-command
|
||||||
|
(is (= [["restic"
|
||||||
|
"-r"
|
||||||
|
"repo/dir"
|
||||||
|
"-v"
|
||||||
|
"--new-password-file"
|
||||||
|
"/new-pwd"
|
||||||
|
"key"
|
||||||
|
"passwd"]]
|
||||||
|
(cut/change-password-command {:restic-repository "repo"
|
||||||
|
:new-password-file "/new-pwd"
|
||||||
|
:backup-path "dir"
|
||||||
|
:days-to-keep 39
|
||||||
|
:months-to-keep 3}))))
|
||||||
|
|
||||||
|
(deftest should-parse-check-error
|
||||||
|
(is (= :not-initialized
|
||||||
|
(cut/parse-check-error "Fatal: unable to open config file: stat /restic-repo/files/config: no such file or directory\nIs there a repository at the following location?\n/restic-repo/files" )
|
||||||
|
))
|
||||||
|
(is (= :wrong-password
|
||||||
|
(cut/parse-check-error "Fatal: wrong password or no key found\n")))
|
||||||
|
(is (= :no-password
|
||||||
|
(cut/parse-check-error "Resolving password failed: Fatal: /restic-pwd does not exist\n")))
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue