backup-scripts/admin.sh

914 lines
28 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
trap nfcunmount EXIT
set -o noglob
SCRIPT="$(readlink -f "${BASH_SOURCE}")"
CONFIGURATION="/home/user/scripts/admin.conf"
if [ "$EUID" -ne 0 ]; then
echo "Ce script nécessite des privilèges administrateur."
echo "Relance avec sudo..."
exec sudo "$0" "$@"
fi
echo "Le script est bien lancé avec sudo/root !"
function show()
{
NC='\033[0m'
if [ -z "$2" ]; then
COLOR=$NC
elif [ "$2" == "ERR" ]; then
COLOR='\033[1;31m'
else
COLOR='\033[0;32m'
fi
printf "${COLOR}$1${NC}\n"
}
function assign()
{
KEYS=$(cat "$1"|sed 's/.*%\([A-Z0-9]*\)%.*/%\1/g'|grep "%"|tr -d '%')
while read -r KEY; do
REALKEY=$(eval echo \$${KEY})
show "Apply key $KEY" 1
sed -i "s#%${KEY}%#${REALKEY}#g" /mnt/usb/rclone/rclone.conf
done < <(echo "${KEYS}")
}
function extract()
{
ALLCONTENT=$(cat "${SCRIPT}"|grep "#$1"|sed "s/^#$1\(.*\)$/\1/")
CONTENT=$(echo "${ALLCONTENT}"|tail -n +2)
CONTENTSIZE=$(echo "${CONTENT}"|wc -c)
FILEINFO=$(echo "${ALLCONTENT}"|head -n1)
FILENAME=$(echo "${FILEINFO}"|cut -d"," -f1)
FILEMOD=$(echo "${FILEINFO}"|cut -d"," -f2)
show "Extract piece $1 (${CONTENTSIZE}o) at ${FILENAME} with ${FILEMOD}"
echo "${CONTENT}" > "${FILENAME}"
chmod ${FILEMOD} "${FILENAME}"
}
function excludepath()
{
EXCLUD=""
while read SRC; do
if [ ! -z "${SRC}" ]; then
EXCLUD="${EXCLUD} --exclude ${SRC}"
fi
done < <(echo "$1"|tr "," "\n")
echo "${EXCLUD}"
}
function nfcunmount()
{
TMPFS=$(mount -t tmpfs|grep "/mnt/usb")
if [ ! -z "${TMPFS}" ]; then
umount /mnt/usb
fi
TMPFS=$(mount -t tmpfs|grep "/mnt/usb")
if [ ! -z "${TMPFS}" ]; then
show "Unable to umount" ERR
fi
}
function nfcmountonly()
{
if [ ! -d /mnt/usb ]; then
mkdir -p /mnt/usb
fi
TMPFS=$(mount -t tmpfs|grep "/mnt/usb")
if [ -z "${TMPFS}" ]; then
mount -t tmpfs tmpfs /mnt/usb
fi
}
function rclonemount()
{
if [ ! -f /mnt/usb/rclone/rclone.conf ]; then
show "NO RCLONE CONFIGURATION FILE" ERR
nfcmountonly
if [ ! -d /mnt/usb/rclone ]; then
show "Create /mnt/usb/rclone" 1
mkdir -p /mnt/usb/rclone
show "Create rclone.conf" 1
extract 5
TOKEN=$(${ZFS} get rclone:token $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
if [[ "${TOKEN}" == "" ]]; then
show "Unable to find connexion information: token"
nfcunmount
exit
fi
if [[ "$2" == "rclone" ]]; then
show "RCLONE mode"
PASSWD1=$(${ZFS} get rclone:password1 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
if [[ "${PASSWD1}" == "" ]]; then
show "Unable to find connexion information: passwd1"
nfcunmount
exit
fi
PASSWD2=$(${ZFS} get rclone:password2 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
if [[ "${PASSWD2}" == "" ]]; then
show "Unable to find connexion information: passwd2"
nfcunmount
exit
fi
REMOTE=$(${ZFS} get sync:dstpath $1 -o value -H)
if [[ "${REMOTE}" == "" ]]; then
show "Unable to find connexion information: dstpath"
nfcunmount
exit
fi
ACTIVE=$(${ZFS} get sync:active $1 -o value -H)
if [[ ! "${ACTIVE}" == "on" ]]; then
show "Sync not active"
nfcunmount
exit
fi
RCLONE_EXCLUDE=$(${ZFS} get sync:exclude $1 -o value -H)
RCLONE_VOLS="/$1"
else
PASSWD1=$(${ZFS} get restic:password1 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
if [[ "${PASSWD1}" == "" ]]; then
show "Unable to find connexion information: passwd1"
nfcunmount
exit
fi
PASSWD2=$(${ZFS} get restic:password2 $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
if [[ "${PASSWD2}" == "" ]]; then
show "Unable to find connexion information: passwd2"
nfcunmount
exit
fi
show "RESTIC mode"
REMOTE=$(${ZFS} get backup:dstpath $1 -o value -H)
if [[ "${REMOTE}" == "" ]]; then
show "Unable to find connexion information: dstpath"
nfcunmount
exit
fi
ACTIVE=$(${ZFS} get backup:active $1 -o value -H)
if [[ ! "${ACTIVE}" == "on" ]]; then
show "Backup not active"
nfcunmount
exit
fi
RESTIC_PASSWORD=$(${ZFS} get restic:password $1 -o value -H|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
if [[ "${RESTIC_PASSWORD}" == "" ]]; then
show "Unable to find connexion information: passwd"
nfcunmount
exit
fi
RESTIC_EXCLUDE=$(${ZFS} get backup:exclude $1 -o value -H)
RESTIC_ALL=$(${ZFS} get backup:retention $1 -o value -H)
RESTIC_MONTHLY=$(echo "${RESTIC_ALL}"|cut -d',' -f1)
RESTIC_WEEKLY=$(echo "${RESTIC_ALL}"|cut -d',' -f2)
RESTIC_DAILY=$(echo "${RESTIC_ALL}"|cut -d',' -f3)
RESTIC_VOLS="/$1"
fi
assign /mnt/usb/rclone/rclone.conf
fi
fi
TOKEN=""
PASSWD1=""
PASSWD2=""
show "List remotes" 1
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf listremotes
show "Connect to Cloud without cyphering" 1
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf lsd pcloud:/
show "Connect to Cloud with cyphering" 1
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf lsd crypt:/
}
function attribute()
{
VAL=""
ATTRIBUTE=$(${ZFS} get $1 $4 -o value -H)
if [[ "${ATTRIBUTE}" == "-" ]]; then
ATTRIBUTE="$5"
show "Init attribute $1 with $5"
${ZFS} set $1=$5 $4
fi
if [[ "$2" == "passwd" ]]; then
ATTRIBUTE_DEC=$(echo -en "${ATTRIBUTE}"|decrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
BEGIN=$(echo "${ATTRIBUTE_DEC}"|head -c 10)
MIDDLE="..."
END=$(echo "${ATTRIBUTE_DEC}"|tail -c 10)
BLOB="${BEGIN}${MIDDLE}${END}"
read -p "$3 [${BLOB}]:" ASK_DEC </dev/tty
if [[ "${ASK_DEC}" == "" ]]; then
ASK=""
else
ASK=$(echo -en "${ASK_DEC}"|encrypt_now "{\"url\": \"${URL}\"}" 2> /dev/null)
fi
ATTRIBUTE_DEC=""
ASK_DEC=""
elif [[ "$2" == "bool" ]]; then
if [[ "${ATTRIBUTE}" == "on" ]]; then
VALUE="off"
else
VALUE="on"
fi
read -p "$3 [${ATTRIBUTE}]/${VALUE}:" ASK </dev/tty
else
read -p "$3 [${ATTRIBUTE}]:" ASK </dev/tty
fi
if [[ "${ASK}" != "${ATTRIBUTE}" ]]; then
if [[ "${ASK}" == "" ]]; then
#${ZFS} set $1=${ATTRIBUTE} $4
VAL=${ATTRIBUTE}
elif [[ "${ASK}" == "-" ]]; then
show "...with $5"
${ZFS} set $1=$5 $4
VAL=$5
else
show "..."
${ZFS} set $1=${ASK} $4
VAL=${ASK}
fi
else
VAL="${ATTRIBUTE}"
fi
}
function configure()
{
show "********* Configure pools ***********"
while read ITEM; do
show " - ${ITEM}"
attribute rclone:token passwd "Pcloud token" ${ITEM} ""
if [[ "${VAL}" == "" ]]; then
continue
fi
attribute rclone:password1 passwd "Pcloud password N1" ${ITEM} ""
if [[ "${VAL}" == "" ]]; then
continue
fi
attribute rclone:password2 passwd "Pcloud password N2" ${ITEM} ""
if [[ "${VAL}" == "" ]]; then
continue
fi
attribute sync:active bool "Sync active" ${ITEM} off
if [[ "${VAL}" == "on" ]]; then
attribute sync:dstpath str "Sync path" ${ITEM} ${RCLONE_PATH}
attribute sync:exclude str "Sync exclude" ${ITEM} ""
fi
attribute restic:password1 passwd "Restic password N1" ${ITEM} ""
if [[ "${VAL}" == "" ]]; then
continue
fi
attribute restic:password2 passwd "Restic password N2" ${ITEM} ""
if [[ "${VAL}" == "" ]]; then
continue
fi
attribute backup:active bool "Backup active" ${ITEM} off
if [[ "${VAL}" == "on" ]]; then
attribute restic:password passwd "Backup password" ${ITEM} ""
if [[ "${VAL}" == "" ]]; then
continue
fi
attribute backup:dstpath str "Backup path" ${ITEM} ${RESTIC_PATH}
attribute backup:exclude str "Backup exclude" ${ITEM} ""
attribute backup:retention str "Backup retention" ${ITEM} ${RESTIC_MONTHLY},${RESTIC_WEEKLY},${RESTIC_DAILY}
fi
done < <(${ZFS} list -o name -d 1 -t filesystem|grep "/")
}
function help()
{
show "Usage: admin [ command ] [ args... ]" 1
show ""
show "help for COMPLEX commands: admin command"
show ""
show "-< Save/Restore"
show "sync - sync, check data to cloud COMPLEX"
show "backup - backup data to cloud COMPLEX"
show "config - configure Restic and Rclone NOARG"
show "velero - backup object on kubernetes COMPLEX"
show ""
show "-< Tang"
show "tangcrypt - encrypt /dev/stdin to /dev/stdout NOARG"
show "tangdecrypt - decrypt /dev/stdin to /dev/stdout NOARG"
show ""
exit 2
}
function help_velero()
{
show "Usage: admin velero [init|backup|restore|info ] [dataname]" 1
show ""
show "Use the velero backend to make some kubernetes backup operations"
show ""
show "init - initialize the data storage on kubernetes"
show "uninstall - uninstall velero on kubernetes"
show "backup - backup the kubernetes objects"
show "restore - restore [dataname] backup on kubernetes"
show "info - get informations about [dataname]"
show ""
exit 2
}
function help_restic()
{
show "Usage: admin backup ${ZFS}dataset [ init|view|ls|check|now|prune|remove|config ]" 1
show ""
show "Use the restic backend to make some cloud backup operations"
show ""
show "init - initialize the data storage on cloud"
show "view - view snapshots stored on cloud"
show "ls - list all files 1ARG"
show "check - check integrity of distant data"
show "now - perform a backup on cloud"
show "prune - purge unused data on cloud storage"
show "remove - remove a snapshot store on cloud 1ARG"
show "unlock - unlock data storage on cloud"
show ""
exit 2
}
function help_rclone()
{
show "Usage: admin sync ${ZFS}dataset [ now|dryrun|copy|view|ls|check|config ]" 1
show ""
show "Use the rclone backend to make cloud mirror operations"
show ""
show "now - perform a sync with the cloud"
show "dryrun - perform a simulation of sync with the cloud"
show "copy - copy ARG to local"
show "view - view interactivly server data"
show "ls - list all files"
show "check - check integrity of distant data"
show ""
exit 2
}
function encrypt_now() {
SUMMARY="Encrypts using a Tang binding server policy"
if [ "$1" == "--summary" ]; then
echo "$SUMMARY"
exit 0
fi
if [ -t 0 ]; then
exec >&2
echo
echo "Usage: clevis encrypt tang CONFIG [-y] < PLAINTEXT > JWE"
echo
echo "$SUMMARY"
echo
echo " -y Use this option for skipping the advertisement"
echo " trust check. This can be useful in automated"
echo " deployments"
echo
echo "This command uses the following configuration properties:"
echo
echo " url: <string> The base URL of the Tang server (REQUIRED)"
echo
echo " thp: <string> The thumbprint of a trusted signing key"
echo
echo " adv: <string> A filename containing a trusted advertisement"
echo " adv: <object> A trusted advertisement (raw JSON)"
echo
echo "Obtaining the thumbprint of a trusted signing key is easy. If you"
echo "have access to the Tang server's database directory, simply do:"
echo
echo " $ jose jwk thp -i \$DBDIR/\$SIG.jwk "
echo
echo "Alternatively, if you have certainty that your network connection"
echo "is not compromised (not likely), you can download the advertisement"
echo "yourself using:"
echo
echo " $ curl -f \$URL/adv > adv.jws"
echo
exit 2
fi
if ! cfg="$(jose fmt -j- -Oo- <<< "$1" 2>/dev/null)"; then
echo "Configuration is malformed!" >&2
exit 1
fi
CLEVIS_DEFAULT_THP_ALG=S256 # SHA-256.
CLEVIS_ALTERNATIVE_THP_ALGS=S1 # SHA-1.
trust=
[ -n "${2}" ] && [ "${2}" == "-y" ] && trust=yes
if ! url="$(jose fmt -j- -Og url -u- <<< "$cfg")"; then
echo "Missing the required 'url' property!" >&2
exit 1
fi
thp="$(jose fmt -j- -Og thp -Su- <<< "$cfg")" || true
### Get the advertisement
if jws="$(jose fmt -j- -g adv -Oo- <<< "$cfg")"; then
thp="${thp:-any}"
elif jws="$(jose fmt -j- -g adv -Su- <<< "$cfg")"; then
if ! [ -f "$jws" ]; then
echo "Advertisement file '$jws' not found!" >&2
exit 1
fi
if ! jws="$(jose fmt --json="${jws}" -Oo- 2>/dev/null)"; then
echo "Advertisement file '$jws' is malformed!" >&2
exit 1
fi
thp="${thp:-any}"
elif ! jws="$(curl -sfg "$url/adv/$thp")"; then
echo "Unable to fetch advertisement: '$url/adv/$thp'!" >&2
exit 1
fi
if ! jwks="$(jose fmt --json="${jws}" -Og payload -SyOg keys \
-AUo- 2>/dev/null)"; then
echo "Advertisement is malformed!" >&2
exit 1
fi
### Check advertisement validity
ver="$(jose jwk use -i- -r -u verify -o- <<< "$jwks")"
if ! jose jws ver -i "$jws" -k- -a <<< "$ver"; then
echo "Advertisement is missing signatures!" >&2
exit 1
fi
### Check advertisement trust
if [ -z "${trust}" ]; then
if [ -z "$thp" ]; then
echo "The advertisement contains the following signing keys:" >&2
echo >&2
jose jwk thp -i- -a "${CLEVIS_DEFAULT_THP_ALG}" <<< "$ver" >&2
echo >&2
elif [ "$thp" != "any" ] && \
! jose jwk thp -i- -f "${thp}" -a "${CLEVIS_DEFAULT_THP_ALG}" \
-o /dev/null <<< "$ver"; then
# Thumbprint of trusted JWK did not match the signature. Let's check
# alternative thumbprints generated with clevis supported hash
# algorithms to be sure.
for alg in ${CLEVIS_ALTERNATIVE_THP_ALGS}; do
srv="$(jose jwk thp -i- -f "${thp}" -a "${alg}" <<< "${ver}")" \
&& break
done
if [ -z "${srv}" ]; then
echo "Trusted JWK '$thp' did not sign the advertisement!" >&2
exit 1
fi
fi
fi
### Perform encryption
if ! enc="$(jose jwk use -i- -r -u deriveKey -o- <<< "$jwks")"; then
echo "Key derivation key not available!" >&2
exit 1
fi
jose fmt -j "$enc" -Og keys -A || enc="{\"keys\":[$enc]}"
if ! jwk="$(jose fmt -j- -Og keys -Af- <<< "$enc")"; then
echo "No exchange keys found!" >&2
exit 1
fi
jwk="$(jose fmt -j- -Od key_ops -o- <<< "$jwk")"
jwk="$(jose fmt -j- -Od alg -o- <<< "$jwk")"
kid="$(jose jwk thp -i- -a "${CLEVIS_DEFAULT_THP_ALG}" <<< "$jwk")"
jwe='{"protected":{"alg":"ECDH-ES","enc":"A256GCM","clevis":{"pin":"tang","tang":{}}}}'
jwe="$(jose fmt -j "$jwe" -g protected -q "$kid" -s kid -UUo-)"
jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tang -q "$url" -s url -UUUUo-)"
jwe="$(jose fmt -j "$jwe" -g protected -g clevis -g tang -j- -s adv -UUUUo- <<< "$jwks")"
exec jose jwe enc -i- -k- -I- -c < <(echo -n "$jwe$jwk"; /bin/cat)
echo -en ""
}
function decrypt_now() {
[ $# -eq 1 ] && [ "$1" == "--summary" ] && exit 2
if [ -t 0 ]; then
exec >&2
echo
echo "Usage: clevis decrypt tang < JWE > PLAINTEXT"
echo
exit 2
fi
read -r -d . hdr
if ! jhd="$(jose b64 dec -i- <<< "$hdr")"; then
echo "Error decoding JWE protected header!" >&2
exit 1
fi
if [ "$(jose fmt -j- -Og clevis -g pin -u- <<< "$jhd")" != "tang" ]; then
echo "JWE pin mismatch!" >&2
exit 1
fi
if ! clt="$(jose fmt -j- -Og epk -Oo- <<< "$jhd")"; then
echo "JWE missing required 'epk' header parameter!" >&2
exit 1
fi
if ! kid="$(jose fmt -j- -Og kid -Su- <<< "$jhd")"; then
echo "JWE missing required 'kid' header parameter!" >&2
exit 1
fi
# Tang advertisement validation.
if ! keys="$(jose fmt -j- -Og clevis -g tang -g adv -Oo- <<< "${jhd}")"; then
echo "JWE missing required 'clevis.tang.adv' header parameter!" >&2
exit 1
fi
# Check if the thumbprint we have in `kid' is in the advertised keys.
CLEVIS_DEFAULT_THP_ALG=S256 # SHA-256.
CLEVIS_DEFAULT_THP_LEN=43 # Length of SHA-256 thumbprint.
CLEVIS_ALTERNATIVE_THP_ALGS=S1 # SHA-1.
# Issue a warning if we are using a hash that has a shorter length than the
# default one.
if [ "${#kid}" -lt "${CLEVIS_DEFAULT_THP_LEN}" ]; then
echo "WARNING: tang using a deprecated hash for the JWK thumbprints" >&2
fi
if ! srv="$(jose jwk thp -i- -f "${kid}" -a "${CLEVIS_DEFAULT_THP_ALG}" \
<<< "${keys}")"; then
# `kid' thumprint not in the advertised keys, but it's possible it was
# generated using a different algorithm than the default one.
# Let us try the alternative supported algorithms to make sure `kid'
# really is not part of the advertised keys.
for alg in ${CLEVIS_ALTERNATIVE_THP_ALGS}; do
srv="$(jose jwk thp -i- -f "$kid" -a "${alg}" <<< "${keys}")" && break
done
if [ -z "${srv}" ]; then
echo "JWE header validation of 'clevis.tang.adv' failed: key thumbprint does not match" >&2
exit 1
fi
fi
if ! url="$(jose fmt -j- -Og clevis -g tang -g url -Su- <<< "$jhd")"; then
echo "JWE missing required 'clevis.tang.url' header parameter!" >&2
exit 1
fi
if ! crv="$(jose fmt -j- -Og crv -Su- <<< "$clt")"; then
echo "Unable to determine EPK's curve!" >&2
exit 1
fi
if ! eph="$(jose jwk gen -i "{\"alg\":\"ECMR\",\"crv\":\"$crv\"}")"; then
echo "Error generating ephemeral key!" >&2
exit 1
fi
xfr="$(jose jwk exc -i '{"alg":"ECMR"}' -l- -r- <<< "$clt$eph")"
rec_url="$url/rec/$kid"
ct="Content-Type: application/jwk+json"
if ! rep="$(curl -sfg -X POST -H "$ct" --data-binary @- "$rec_url" <<< "$xfr")"; then
echo "Error communicating with server $url" >&2
exit 1
fi
if ! rep="$(jose fmt -j- -Og kty -q EC -EUUg crv -q "$crv" -EUUo- <<< "$rep")"; then
echo "Received invalid server reply!" >&2
exit 1
fi
tmp="$(jose jwk exc -i '{"alg":"ECMR"}' -l- -r- <<< "$eph$srv")"
rep="$(jose jwk pub -i- <<< "$rep")"
jwk="$(jose jwk exc -l- -r- <<< "$rep$tmp")"
(echo -n "$jwk$hdr."; /bin/cat) | exec jose jwe dec -k- -i-
echo -en ""
}
function rcloneapp()
{
if [ -z "$1" ]; then
help_rclone
fi
case "$2" in
copy)
DEST="/tmp/"
show "Copy from $3 to ${DEST}" 1
rclonemount $1 rclone
${RCLONE_CMD} -vv --config /mnt/usb/rclone/rclone.conf copy crypt:/$2 ${DEST}
;;
dryrun)
show "Dry run..." 1
echo "********* Synchonize *************" >> /var/log/rclone.log
date >> /var/log/rclone.log
rclonemount $1 rclone
excluded=$(excludepath $RCLONE_EXCLUDE)
while read src; do
dstemp=$(basename "${src^}")
dst=${dstemp^}
show "$src => $dst"
echo "$src => $dst" >> /var/log/rclone.log
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf sync -c -P --dry-run --links --checkers=20 --low-level-retries=10 --retries=10 --retries-sleep=1s --transfers=20 --delete-excluded $excluded --exclude ".zfs/**" $src crypt:/${dst}/ 2>&1 | tee -a /var/log/rclone.log
done < <(echo "$RCLONE_VOLS"|tr "," "\n")
echo "***********************************" >> /var/log/rclone.log
;;
now)
show "Synchronize..." 1
echo "********* Synchonize *************" >> /var/log/rclone.log
date >> /var/log/rclone.log
rclonemount $1 rclone
excluded=$(excludepath $RCLONE_EXCLUDE)
while read src; do
dstemp=$(basename "${src^}")
dst=${dstemp^}
show "$src => $dst"
echo "$src => $dst" >> /var/log/rclone.log
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf sync -c -P ${DRY} --links --checkers=20 --low-level-retries=10 --retries=10 --retries-sleep=1s --transfers=20 --delete-excluded $excluded --exclude ".zfs/**" $src crypt:/${dst}/ 2>&1 | tee -a /var/log/rclone.log
done < <(echo "$RCLONE_VOLS"|tr "," "\n")
echo "***********************************" >> /var/log/rclone.log
;;
view)
show "View..." 1
rclonemount $1 rclone
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf ncdu crypt:
;;
ls)
show "View files..." 1
rclonemount $1 rclone
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf lsd crypt: -R
;;
check)
show "Check..." 1
echo "************** Check **************" >> /var/log/rclone.log
date >> /var/log/rclone.log
rclonemount $1 rclone
excluded=$(excludepath $RCLONE_EXCLUDE)
while read src; do
dstemp=$(basename "${src^}")
dst=${dstemp^}
show "$src => $dst"
echo "$src => $dst" >> /var/log/rclone.log
${RCLONE_CMD} --config /mnt/usb/rclone/rclone.conf check -c -P --differ /var/log/differ_${dst}.log --links --checkers=20 --low-level-retries=10 --retries=10 --retries-sleep=1s --transfers=20 $excluded --exclude ".zfs/**" $src crypt:/${dst}/ 2>&1 | tee -a /var/log/rclone.log
done < <(echo "$RCLONE_VOLS"|tr "," "\n")
echo "***********************************" >> /var/log/rclone.log
;;
*)
help_rclone
;;
esac
nfcunmount
}
function veleroapp()
{
if [ -z "$1" ]; then
help_velero
fi
case "$1" in
init)
nfcmountonly
read -p "🔑 MinIO Access Key: " ACCESS_KEY
read -sp "🔒 MinIO Secret Key: " SECRET_KEY
cat <<EOF > /mnt/usb/credentials-vel
[default]
aws_access_key_id=${ACCESS_KEY}
aws_secret_access_key=${SECRET_KEY}
EOF
if ! command -v velero >/dev/null 2>&1; then
echo "🔍 Velero non trouvé, téléchargement et installation de v1.16.0…"
wget -q https://github.com/vmware-tanzu/velero/releases/download/v1.16.0/velero-v1.16.0-linux-amd64.tar.gz
tar -xzf velero-v1.16.0-linux-amd64.tar.gz
chmod +x velero-v1.16.0-linux-amd64/velero
chown root:root velero-v1.16.0-linux-amd64/velero
mv velero-v1.16.0-linux-amd64/velero /usr/local/bin/velero
rm -rf velero-v1.16.0-linux-amd64 velero-v1.16.0-linux-amd64.tar.gz
echo "✅ Velero installé."
else
echo "✅ Velero déjà présent, version : $(velero version --client-only | head -n1)"
fi
echo "▶️ Déploiement Velero dans le cluster…"
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.10.0 \
--bucket velero \
--backup-location-config region=us-east-1,s3ForcePathStyle="true",s3Url=https://minio-api.ia86.cc,checksumAlgorithm="" \
--snapshot-location-config region=us-east-1 \
--secret-file /mnt/usb/credentials-vel \
--uploader-type kopia \
--kubeconfig /home/user/.kube/config \
|| echo " Velero est peut-être déjà installé dans le cluster."
echo "🎉 Script terminé."
;;
uninstall)
velero uninstall --kubeconfig /home/user/.kube/config
;;
backup)
NOW=$(date +"%Y%m%d-%H%M")
velero backup create backup-complet-cluster2-${NOW} \
--include-namespaces '*' \
--include-resources '*' \
--include-cluster-resources=true \
--kubeconfig /home/user/.kube/config
# --default-volumes-to-fs-backup \
echo "${NOW}" > /var/log/lastfilename
;;
info)
velero backup describe $2 --kubeconfig /home/user/.kube/config
;;
restore)
BACKUP_NAME="$2"
read -p "Are you sure you want to restore from backup '$BACKUP_NAME'? [y/N] " confirm
case "$confirm" in
[Yy]* )
echo "▶️ Restoring from backup '$BACKUP_NAME'…"
#velero restore create --from-backup "$BACKUP_NAME" --kubeconfig /home/user/.kube/config
;;
* )
echo "❌ Restore aborted."
;;
esac
;;
*)
help_velero
;;
esac
nfcunmount
}
function resticapp()
{
if [ -z "$1" ]; then
help_restic
fi
export RCLONE_CONFIG
export RESTIC_PASSWORD
case "$2" in
init)
show "Initializing..." 1
echo "********* Initialiazing *************" >> /var/log/restic.log
date >> /var/log/restc.log
rclonemount $1 restic
${RESTIC_CMD} init -r rclone:crypt:/ | tee -a /var/log/restic.log
echo "***********************************" >> /var/log/restic.log
;;
unlock)
show "Unlocking..." 1
echo "********* Unlocking *************" >> /var/log/restic.log
date >> /var/log/restc.log
rclonemount $1 restic
${RESTIC_CMD} unlock -r rclone:crypt:/ | tee -a /var/log/restic.log
echo "***********************************" >> /var/log/restic.log
;;
ls)
show "View files..." 1
rclonemount $1 restic
${RESTIC_CMD} ls -r rclone:crypt:/ $3
;;
view)
show "View..." 1
rclonemount $1 restic
${RESTIC_CMD} snapshots -r rclone:crypt:/
;;
check)
show "Check..." 1
echo "************** Check **************" >> /var/log/restic.log
date >> /var/log/restic.log
rclonemount $1 restic
${RESTIC_CMD} check --read-data -r rclone:crypt:/ | tee -a /var/log/restic.log
${RESTIC_CMD} rebuild-index -r rclone:crypt:/ | tee -a /var/log/restic.log
echo "***********************************" >> /var/log/restic.log
;;
prune)
show "Cleaning..." 1
echo "************** Cleaning **************" >> /var/log/restic.log
date >> /var/log/restic.log
rclonemount $1 restic
${RESTIC_CMD} prune -r rclone:crypt:/ | tee -a /var/log/restic.log
echo "***********************************" >> /var/log/restic.log
;;
remove)
show "Removing..." 1
echo "************** Removing **************" >> /var/log/restic.log
date >> /var/log/restic.log
rclonemount $1 restic
${RESTIC_CMD} forget $2 -r rclone:crypt:/ | tee -a /var/log/restic.log
echo "***********************************" >> /var/log/restic.log
;;
now)
show "Backing up..." 1
echo "************** Backup **************" >> /var/log/restic.log
date >> /var/log/restic.log
rclonemount $1 restic
excluded=$(excludepath $RESTIC_EXCLUDE)
while read src; do
dstemp=$(basename "${src^}")
dst=${dstemp^}
show "$src => $dst"
echo "$src => $dst" >> /var/log/restic.log
${RESTIC_CMD} backup $src -r rclone:crypt:/ --verbose=1 $excluded --exclude ".zfs/**" --tag admin_command|tee -a /var/log/restic.log
${RESTIC_CMD} forget -r rclone:crypt:/ --tag admin_command --keep-monthly=$RESTIC_MONTHLY --keep-weekly=$RESTIC_WEEKLY --keep-daily=$RESTIC_DAILY
done < <(echo "$RESTIC_VOLS"|tr "," "\n")
echo "***********************************" >> /var/log/restic.log
;;
*)
help_restic
;;
esac
nfcunmount
}
function install()
{
apt install rclone restic ncdu jose clevis curl sudo zfsutils-linux -y
}
if [[ ! -f "${CONFIGURATION}" ]]; then
show "Creating configuration file..."
extract 4
fi
source "${CONFIGURATION}"
nfcunmount
COMMAND="$1"
shift
case "${COMMAND}" in
install)
install
;;
config)
configure
;;
velero)
veleroapp $1 $2 $3
;;
backup)
resticapp $1 $2 $3
;;
sync)
rcloneapp $1 $2 $3
;;
nfcunmount)
nfcunmount
;;
tangcrypt)
cat /dev/stdin|encrypt_now "{\"url\": \"${URL}\"}"
;;
tangdecrypt)
cat /dev/stdin|decrypt_now "{\"url\": \"${URL}\"}"
;;
*)
help
;;
esac
#4/home/user/scripts/admin.conf,644
#4# Hard settings
#4ALIB="--module /usr/lib/x86_64-linux-gnu/libykcs11.so.2"
#4ZFS="zfs"
#4PZFS="zfs"
#4ZPOOL="zpool"
#4PZPOOL="zpool"
#4PATH="/usr/local/bin:/usr/bin:$PATH"
#4FONT=""
#4MAXSIZE=700
#4RCLONE_CMD="rclone"
#4RESTIC_CMD="restic"
#4
#4# Settings
#4RCLONE_CONFIG="/mnt/usb/rclone/rclone.conf"
#4URL="https://tang.ia86.cc"
#4
#4# Default parameters
#4RCLONE_PATH="/hetzner/kube.ia86.cc"
#4RCLONE_EXCLUDE=""
#4RESTIC_PATH="/hetzner/restic"
#4RESTIC_MONTHLY="12"
#4RESTIC_WEEKLY="10"
#4RESTIC_DAILY="31"
#4RESTIC_EXCLUDE=""
#5/mnt/usb/rclone/rclone.conf,644
#5[pcloud]
#5type = pcloud
#5hostname = eapi.pcloud.com
#5token = {"access_token":"%TOKEN%","token_type":"bearer","expiry":"0001-01-01T00:00:00Z"}
#5[crypt]
#5type = crypt
#5remote = pcloud:%REMOTE%
#5filename_encryption = standard
#5directory_name_encryption = true
#5password = %PASSWD1%
#5password2 = %PASSWD2%
#5[sauvegarde]
#5type = crypt
#5remote = pcloud:%REMOTE%
#5filename_encryption = standard
#5directory_name_encryption = true
#5password = %PASSWD3%
#5password2 = %PASSWD4%