feat(cloudpex): track the on-demand SMB mount helper, add installer + README
cloudpex/cloudpex mounts //192.168.1.111/CloudPex on /mnt/cloudpex on demand (password prompted, nothing stored, noexec/nosuid/nodev, dir_mode 0750). cloudpex/install.sh reproduces the live deployment: /usr/local/bin/cloudpex root:root 0755, /mnt/cloudpex, cifs-utils if mount.cifs is missing. README (FR) explains why on-demand and not fstab (RECOVERY doc 04).
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
# cloudpex : montage à la demande du partage SMB CloudPex
|
||||||
|
|
||||||
|
`cloudpex` monte et démonte le partage SMB `CloudPex` du NAS (`//192.168.1.111/CloudPex`)
|
||||||
|
sur `/mnt/cloudpex`. Le mot de passe SMB est demandé à chaque montage. Rien n'est
|
||||||
|
écrit sur disque, rien ne passe en argument (le mot de passe est transmis à
|
||||||
|
`mount.cifs` par la variable d'environnement `PASSWD`, invisible dans `ps`).
|
||||||
|
|
||||||
|
## Pourquoi à la demande, et pas dans fstab
|
||||||
|
|
||||||
|
Sur l'ancien serveur le partage était monté en permanence, en écriture, avec
|
||||||
|
`uid=1000` forcé. Tout processus de l'utilisateur pouvait donc tout effacer, agents
|
||||||
|
Claude compris. C'est ce qui a rendu l'incident du 21/09 total (voir
|
||||||
|
`RECOVERY/01-prochain-systeme/04-NAS-cloudpex-sauvegardes.md` sur le partage).
|
||||||
|
|
||||||
|
Ce script applique la règle 2 de ce document :
|
||||||
|
|
||||||
|
- montage à la demande, par un humain, jamais automatique au boot ;
|
||||||
|
- aucun identifiant stocké (`/root/.smbcredentials` n'existe plus) ;
|
||||||
|
- `noexec,nosuid,nodev` : rien ne s'exécute depuis le partage ;
|
||||||
|
- `dir_mode=0750`, propriétaire = l'utilisateur qui a lancé `sudo` : les autres
|
||||||
|
comptes (dont les comptes agents) ne voient pas le contenu.
|
||||||
|
|
||||||
|
Démonte quand tu as fini (`cloudpex -u`). Un partage monté reste effaçable par
|
||||||
|
tes propres processus.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cloudpex # monte (demande le mot de passe de bchanot_smb)
|
||||||
|
cloudpex -s # état
|
||||||
|
cloudpex -u # démonte (alias : -d, dc, disconnect, disable)
|
||||||
|
cloudpex -h # aide
|
||||||
|
```
|
||||||
|
|
||||||
|
Le script se relance lui-même via `sudo` : pas besoin de le préfixer.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./cloudpex/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce que ça fait, à l'identique de cette machine :
|
||||||
|
|
||||||
|
| Cible | Détail |
|
||||||
|
| --- | --- |
|
||||||
|
| `/usr/local/bin/cloudpex` | copie du script, `root:root`, `0755` |
|
||||||
|
| `/mnt/cloudpex` | point de montage, créé vide |
|
||||||
|
| `cifs-utils` | installé via `apt-get` seulement si `mount.cifs` manque |
|
||||||
|
|
||||||
|
Réexécutable. `../install.sh` l'appelle sur Linux, donc une installation complète
|
||||||
|
du dépôt suffit. Rien n'est monté à l'installation.
|
||||||
|
|
||||||
|
## Paramètres
|
||||||
|
|
||||||
|
En tête de `cloudpex` : `SHARE`, `MNT`, `SMB_USER`, `SMB_VERS`. Pour changer de NAS
|
||||||
|
ou de compte, édite ces valeurs puis relance `./cloudpex/install.sh`.
|
||||||
|
|
||||||
|
## Dépannage
|
||||||
|
|
||||||
|
- Échec du montage : `dmesg | tail` (mot de passe, réseau, ou version SMB
|
||||||
|
refusée par le NAS : essayer `SMB_VERS="3.1.1"`).
|
||||||
|
- Démontage refusé (fichiers ouverts) : `lsof +D /mnt/cloudpex`, fermer, réessayer.
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# cloudpex-mount — monte / démonte le partage SMB CloudPex du NAS
|
||||||
|
# Usage : cloudpex-mount -> monte (demande le mot de passe)
|
||||||
|
# cloudpex-mount -u -> démonte
|
||||||
|
# cloudpex-mount -s -> état
|
||||||
|
# Aucun credential n'est écrit sur disque ni passé en argument (invisible dans ps).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SHARE="//192.168.1.111/CloudPex"
|
||||||
|
MNT="/mnt/cloudpex"
|
||||||
|
SMB_USER="bchanot_smb"
|
||||||
|
SMB_VERS="3.0"
|
||||||
|
|
||||||
|
# Re-lance le script en root si nécessaire (avant toute saisie du mot de passe)
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
exec sudo -- "$0" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Propriétaire des fichiers montés : l'utilisateur qui a lancé sudo, sinon 1000
|
||||||
|
OWNER_UID="${SUDO_UID:-1000}"
|
||||||
|
OWNER_GID="${SUDO_GID:-1000}"
|
||||||
|
|
||||||
|
die() { echo "Erreur : $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
is_mounted() { mountpoint -q "$MNT"; }
|
||||||
|
|
||||||
|
do_status() {
|
||||||
|
if is_mounted; then
|
||||||
|
echo "Monté : $SHARE -> $MNT"
|
||||||
|
df -h "$MNT" | tail -n 1
|
||||||
|
else
|
||||||
|
echo "Non monté."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_umount() {
|
||||||
|
is_mounted || { echo "Déjà démonté."; return 0; }
|
||||||
|
umount "$MNT" || die "démontage impossible (fichiers ouverts ? voir : lsof +D $MNT)"
|
||||||
|
echo "Démonté : $MNT"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_mount() {
|
||||||
|
command -v mount.cifs >/dev/null || die "cifs-utils absent (sudo apt install cifs-utils)"
|
||||||
|
is_mounted && { echo "Déjà monté : $MNT"; return 0; }
|
||||||
|
|
||||||
|
mkdir -p "$MNT"
|
||||||
|
|
||||||
|
local pass
|
||||||
|
read -rsp "Mot de passe SMB pour ${SMB_USER}@${SHARE} : " pass
|
||||||
|
echo
|
||||||
|
[[ -n "$pass" ]] || die "mot de passe vide"
|
||||||
|
|
||||||
|
# mount.cifs lit PASSWD dans l'environnement : pas d'exposition dans ps ni sur disque
|
||||||
|
if PASSWD="$pass" mount -t cifs "$SHARE" "$MNT" \
|
||||||
|
-o "username=${SMB_USER},uid=${OWNER_UID},gid=${OWNER_GID},iocharset=utf8,vers=${SMB_VERS},file_mode=0640,dir_mode=0750,nosuid,nodev,noexec"; then
|
||||||
|
unset pass
|
||||||
|
echo "Monté : $SHARE -> $MNT"
|
||||||
|
else
|
||||||
|
unset pass
|
||||||
|
die "échec du montage (mot de passe, réseau ou version SMB ; voir : dmesg | tail)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
"") do_mount ;;
|
||||||
|
-u|-d|--umount|dc|disconnect|disable) do_umount ;;
|
||||||
|
-s|--status) do_status ;;
|
||||||
|
-h|--help) sed -n '2,6p' "$0" ;;
|
||||||
|
*) die "option inconnue : $1 (voir -h)" ;;
|
||||||
|
esac
|
||||||
Executable
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# cloudpex/install.sh — installe la commande `cloudpex` (montage à la demande du
|
||||||
|
# partage SMB CloudPex du NAS, voir README.md) telle qu'elle est déployée ici :
|
||||||
|
# /usr/local/bin/cloudpex root:root 0755
|
||||||
|
# /mnt/cloudpex point de montage (vide tant que rien n'est monté)
|
||||||
|
# cifs-utils installé si mount.cifs manque (apt-get)
|
||||||
|
# Réexécutable : réinstalle en place. Ne monte rien, ne stocke aucun identifiant.
|
||||||
|
# Usage : ./cloudpex/install.sh (appelé aussi par ../install.sh sur Linux)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
TARGET=/usr/local/bin/cloudpex
|
||||||
|
MNT=/mnt/cloudpex
|
||||||
|
|
||||||
|
if ! command -v mount.cifs >/dev/null 2>&1; then
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
sudo apt-get install -y cifs-utils
|
||||||
|
else
|
||||||
|
echo "mount.cifs absent et apt-get introuvable : installe cifs-utils à la main" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo install -m 0755 -o root -g root "$SCRIPT_DIR/cloudpex" "$TARGET"
|
||||||
|
sudo install -d -m 0755 "$MNT"
|
||||||
|
echo "cloudpex installé : $TARGET (monter : cloudpex · état : cloudpex -s · démonter : cloudpex -u)"
|
||||||
Reference in New Issue
Block a user