password-rotation #3
12 changed files with 124 additions and 43 deletions
doc
infrastructure/backup
src
main
cljc/dda/c4k_nextcloud
resources/backup
test
|
@ -9,16 +9,12 @@
|
|||
|
||||
## Manual backup
|
||||
|
||||
1. Scale Cloud deployment down:
|
||||
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=0`
|
||||
1. Scale backup-restore deployment up:
|
||||
`kubectl -n nextcloud scale deployment backup-restore --replicas=1`
|
||||
1. exec into pod and execute restore pod
|
||||
2. exec into pod and execute restore pod
|
||||
`kubectl -n nextcloud exec -it backup-restore -- backup.bb`
|
||||
1. Scale backup-restore deployment down:
|
||||
3. Scale backup-restore deployment down:
|
||||
`kubectl -n nextcloud scale deployment backup-restore --replicas=0`
|
||||
1. Scale Cloud deployment up:
|
||||
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=1`
|
||||
|
||||
## Manual restore
|
||||
|
||||
|
@ -32,3 +28,40 @@
|
|||
`kubectl -n nextcloud scale deployment backup-restore --replicas=0`
|
||||
5. Scale Cloud deployment up:
|
||||
`kubectl -n nextcloud scale deployment cloud-deployment --replicas=1`
|
||||
|
||||
## Change Password
|
||||
|
||||
1. Apply restic-new-password to secret & backup deployment
|
||||
```
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: backup-restore
|
||||
spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: backup-app
|
||||
env:
|
||||
- name: RESTIC_NEW_PASSWORD_FILE
|
||||
value: /var/run/secrets/backup-secrets/restic-new-password
|
||||
---
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: backup-secret
|
||||
data:
|
||||
restic-password: old
|
||||
restic-new-password: new
|
||||
```
|
||||
2. Scale backup-restore deployment up:
|
||||
`kubectl -n nextcloud scale deployment backup-restore --replicas=1`
|
||||
3. exec into pod and execute restore pod
|
||||
`kubectl -n nextcloud exec -it backup-restore -- change-password.bb`
|
||||
4. Scale backup-restore deployment down:
|
||||
`kubectl -n nextcloud scale deployment backup-restore --replicas=0`
|
||||
5. Replace restic-password with restic-new-password in secret
|
||||
```
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: backup-secret
|
||||
data:
|
||||
restic-password: new
|
||||
```
|
||||
|
|
BIN
doc/tryItOut.png
BIN
doc/tryItOut.png
Binary file not shown.
Before ![]() (image error) Size: 63 KiB After ![]() (image error) Size: 146 KiB ![]() ![]() |
26
infrastructure/backup/image/resources/change-password.bb
Executable file
26
infrastructure/backup/image/resources/change-password.bb
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bb
|
||||
(require
|
||||
'[babashka.fs :as fs])
|
||||
(-> "/usr/local/bin/config.clj" fs/file load-file)
|
||||
|
||||
(require
|
||||
'[dda.backup.core :as bc]
|
||||
'[dda.backup.restic :as rc]
|
||||
'[config :as cf])
|
||||
|
||||
(def file-pw-change-config (merge cf/file-config {:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
|
||||
(def db-pw-change-config (merge cf/db-config {:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
|
||||
(def db-role-pw-change-config (merge cf/db-role-config {:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
|
||||
|
||||
(defn prepare!
|
||||
[]
|
||||
(bc/create-aws-credentials! cf/aws-config))
|
||||
|
||||
(defn change-password!
|
||||
[]
|
||||
(rc/change-password! file-pw-change-config)
|
||||
(rc/change-password! db-pw-change-config)
|
||||
(rc/change-password! db-role-pw-change-config))
|
||||
|
||||
(prepare!)
|
||||
(change-password!)
|
|
@ -11,6 +11,7 @@
|
|||
(in/install! "backup.bb")
|
||||
(in/install! "restore.bb")
|
||||
(in/install! "list-snapshots.bb")
|
||||
(in/install! "change-password.bb")
|
||||
(in/install! "start-maintenance.sh")
|
||||
(in/install! "end-maintenance.sh")
|
||||
(in/install! "restore.bb")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM c4k-cloud-backup:latest
|
||||
|
||||
ADD resources /tmp/
|
||||
RUN RESTIC_PASSWORD_FILE=/tmp/file_password RESTIC_REPOSITORY=restic-repo POSTGRES_SERVICE=dummy POSTGRES_PORT=dummy POSTGRES_DB=dummy POSTGRES_USER=dummy POSTGRES_PASSWORD=dummy AWS_ACCESS_KEY_ID=dummy AWS_SECRET_ACCESS_KEY=dummy /tmp/test.bb
|
||||
RUN RESTIC_PASSWORD_FILE=/tmp/file_password RESTIC_NEW_PASSWORD_FILE=/tmp/new_file_password RESTIC_REPOSITORY=restic-repo POSTGRES_SERVICE=dummy POSTGRES_PORT=dummy POSTGRES_DB=dummy POSTGRES_USER=dummy POSTGRES_PASSWORD=dummy AWS_ACCESS_KEY_ID=dummy AWS_SECRET_ACCESS_KEY=dummy /tmp/test.bb
|
||||
|
|
1
infrastructure/backup/test/resources/new_file_password
Normal file
1
infrastructure/backup/test/resources/new_file_password
Normal file
|
@ -0,0 +1 @@
|
|||
newPassword
|
|
@ -4,12 +4,15 @@
|
|||
(-> "/usr/local/bin/config.clj" fs/file load-file)
|
||||
|
||||
(require '[babashka.tasks :as tasks]
|
||||
'[dda.backup.core :as bc]
|
||||
'[dda.backup.restic :as rc]
|
||||
'[dda.backup.postgresql :as pg]
|
||||
'[dda.backup.backup :as bak]
|
||||
'[dda.backup.restore :as rs]
|
||||
'[config :as cf])
|
||||
|
||||
(def file-pw-change-config (merge cf/file-config {:new-password-file (bc/env-or-file "RESTIC_NEW_PASSWORD_FILE")}))
|
||||
|
||||
(defn prepare!
|
||||
[]
|
||||
(tasks/shell "mkdir" "-p" "/var/backups/")
|
||||
|
@ -42,8 +45,14 @@
|
|||
(rs/restore-db! (merge cf/db-config cf/dry-run))
|
||||
(rs/restore-file! (merge cf/file-restore-config cf/dry-run)))
|
||||
|
||||
(defn change-password!
|
||||
[]
|
||||
(println "change-password!")
|
||||
(rc/change-password! file-pw-change-config))
|
||||
|
||||
(prepare!)
|
||||
(restic-repo-init!)
|
||||
(restic-backup!)
|
||||
(list-snapshots!)
|
||||
(restic-restore!)
|
||||
(change-password!)
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
(ns dda.c4k-nextcloud.backup
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
#?(:clj [orchestra.core :refer [defn-spec]]
|
||||
:cljs [orchestra.core :refer-macros [defn-spec]])
|
||||
[dda.c4k-common.yaml :as yaml]
|
||||
[dda.c4k-common.base64 :as b64]
|
||||
[dda.c4k-common.common :as cm]
|
||||
[dda.c4k-common.predicate :as cp]
|
||||
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])))
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
#?(:clj [orchestra.core :refer [defn-spec]]
|
||||
:cljs [orchestra.core :refer-macros [defn-spec]])
|
||||
[dda.c4k-common.yaml :as yaml]
|
||||
[dda.c4k-common.base64 :as b64]
|
||||
[dda.c4k-common.common :as cm]
|
||||
[dda.c4k-common.predicate :as cp]
|
||||
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])))
|
||||
|
||||
(s/def ::aws-access-key-id cp/bash-env-string?)
|
||||
(s/def ::aws-secret-access-key cp/bash-env-string?)
|
||||
(s/def ::restic-password cp/bash-env-string?)
|
||||
(s/def ::restic-new-password cp/bash-env-string?)
|
||||
(s/def ::restic-repository cp/bash-env-string?)
|
||||
|
||||
(s/def ::config (s/keys :req-un [::restic-repository]))
|
||||
|
||||
(s/def ::auth (s/keys :req-un [::restic-password ::aws-access-key-id ::aws-secret-access-key]))
|
||||
|
||||
(s/def ::auth (s/keys :req-un [::restic-password ::aws-access-key-id ::aws-secret-access-key]
|
||||
:opt-un [::restic-new-password]))
|
||||
|
||||
#?(:cljs
|
||||
(defmethod yaml/load-resource :backup [resource-name]
|
||||
|
@ -32,20 +33,20 @@
|
|||
|
||||
(defn-spec generate-cron map?
|
||||
[]
|
||||
(yaml/from-string (yaml/load-resource "backup/cron.yaml")))
|
||||
(yaml/from-string (yaml/load-resource "backup/cron.yaml")))
|
||||
|
||||
(defn-spec generate-backup-restore-deployment map?
|
||||
[my-conf ::config]
|
||||
(let [backup-restore-yaml (yaml/load-as-edn "backup/backup-restore-deployment.yaml")]
|
||||
(if (and (contains? my-conf :local-integration-test) (= true (:local-integration-test my-conf)))
|
||||
(cm/replace-named-value backup-restore-yaml "CERTIFICATE_FILE" "/var/run/secrets/localstack-secrets/ca.crt")
|
||||
backup-restore-yaml)))
|
||||
[conf ::config]
|
||||
(yaml/load-as-edn "backup/backup-restore-deployment.yaml"))
|
||||
|
||||
(defn-spec generate-secret map?
|
||||
[my-auth ::auth]
|
||||
(let [{:keys [aws-access-key-id aws-secret-access-key restic-password]} my-auth]
|
||||
(->
|
||||
(yaml/load-as-edn "backup/secret.yaml")
|
||||
(cm/replace-key-value :aws-access-key-id (b64/encode aws-access-key-id))
|
||||
(cm/replace-key-value :aws-secret-access-key (b64/encode aws-secret-access-key))
|
||||
(cm/replace-key-value :restic-password (b64/encode restic-password)))))
|
||||
[auth ::auth]
|
||||
(let [{:keys [aws-access-key-id aws-secret-access-key
|
||||
restic-password restic-new-password]} auth]
|
||||
(as-> (yaml/load-as-edn "backup/secret.yaml") res
|
||||
(cm/replace-key-value res :aws-access-key-id (b64/encode aws-access-key-id))
|
||||
(cm/replace-key-value res :aws-secret-access-key (b64/encode aws-secret-access-key))
|
||||
(cm/replace-key-value res :restic-password (b64/encode restic-password))
|
||||
(if (contains? auth :restic-new-password)
|
||||
(assoc-in res [:data :restic-new-password] (b64/encode restic-new-password))
|
||||
res))))
|
||||
|
|
|
@ -57,8 +57,8 @@ spec:
|
|||
key: restic-repository
|
||||
- name: RESTIC_PASSWORD_FILE
|
||||
value: /var/run/secrets/backup-secrets/restic-password
|
||||
- name: CERTIFICATE_FILE
|
||||
value: ""
|
||||
- name: RESTIC_NEW_PASSWORD_FILE
|
||||
value: /var/run/secrets/backup-secrets/restic-new-password
|
||||
volumeMounts:
|
||||
- name: cloud-data-volume
|
||||
mountPath: /var/backups
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: rotation-credential-secret
|
||||
namespace: nextcloud
|
||||
type: Opaque
|
||||
data:
|
||||
rotation-credential: "dGVzdAo="
|
|
@ -15,8 +15,25 @@
|
|||
:metadata {:name "backup-secret", :namespace "nextcloud"}
|
||||
:type "Opaque"
|
||||
:data
|
||||
{:aws-access-key-id "YXdzLWlk", :aws-secret-access-key "YXdzLXNlY3JldA==", :restic-password "cmVzdGljLXB3"}}
|
||||
(cut/generate-secret {:aws-access-key-id "aws-id" :aws-secret-access-key "aws-secret" :restic-password "restic-pw"}))))
|
||||
{:aws-access-key-id "YXdzLWlk",
|
||||
:aws-secret-access-key "YXdzLXNlY3JldA==",
|
||||
:restic-password "cmVzdGljLXB3"}}
|
||||
(cut/generate-secret {:aws-access-key-id "aws-id"
|
||||
:aws-secret-access-key "aws-secret"
|
||||
:restic-password "restic-pw"})))
|
||||
(is (= {:apiVersion "v1"
|
||||
:kind "Secret"
|
||||
:metadata {:name "backup-secret", :namespace "nextcloud"}
|
||||
:type "Opaque"
|
||||
:data
|
||||
{:aws-access-key-id "YXdzLWlk",
|
||||
:aws-secret-access-key "YXdzLXNlY3JldA==",
|
||||
:restic-password "cmVzdGljLXB3"
|
||||
:restic-new-password "bmV3LXJlc3RpYy1wdw=="}}
|
||||
(cut/generate-secret {:aws-access-key-id "aws-id"
|
||||
:aws-secret-access-key "aws-secret"
|
||||
:restic-password "restic-pw"
|
||||
:restic-new-password "new-restic-pw"}))))
|
||||
|
||||
(deftest should-generate-config
|
||||
(is (= {:apiVersion "v1"
|
||||
|
|
|
@ -5,6 +5,7 @@ nextcloud-admin-password: "cloudpassword"
|
|||
aws-access-key-id: "aws-id"
|
||||
aws-secret-access-key: "aws-secret"
|
||||
restic-password: "restic-password"
|
||||
restic-new-password: "restic-new-password"
|
||||
mon-auth:
|
||||
grafana-cloud-user: "user"
|
||||
grafana-cloud-password: "password"
|
Loading…
Add table
Reference in a new issue