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:
bastien
2026-09-22 16:57:08 +02:00
parent 5a8b575f1a
commit 9dacef3823
3 changed files with 160 additions and 0 deletions
+63
View File
@@ -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.
+71
View File
@@ -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
+26
View File
@@ -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)"