0Pricing
Linux Command Line & Bash Scripting Mastery · Lezione

Esecuzione con privilegi minimi e disciplina nell'uso di sudo

Riduca i privilegi, limiti con precisione le regole sudo e convalidi l'UID effettivo prima delle operazioni rischiose.

Esecuzione con privilegi minimi e disciplina nell'uso di sudo è una lezione Linux Command Line & Bash Scripting Mastery gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Linux Command Line & Bash Scripting Mastery, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Perché il principio del privilegio minimo è importante negli script shell

La maggior parte delle violazioni della sicurezza nell'automazione non avviene a causa di exploit sofisticati, ma perché gli script vengono eseguiti con più privilegi del necessario. Un cron job eseguito come root che deve solo ruotare un file di log è un incidente in attesa di verificarsi.

Il principio del privilegio minimo stabilisce che ogni processo debba operare usando solo i permessi necessari per svolgere il proprio compito, e nessun altro. Negli script Bash questo significa:

  • eseguire il processo come utente non privilegiato ogni volta che è possibile
  • acquisire i privilegi di root solo per i comandi specifici che li richiedono
  • abbandonare i privilegi non appena il lavoro con privilegi elevati è terminato
  • non memorizzare né ereditare mai le credenziali oltre il loro ambito

Questa lezione illustra tecniche concrete: definizione dell'ambito di sudo, abbandono dei privilegi con su, controlli di convalida dell'UID e rafforzamento di sudoers, per costruire un modello disciplinato dei privilegi negli script di produzione.

Controllare l'UID effettivo prima delle operazioni rischiose

Prima di qualsiasi blocco di codice che richieda realmente root, lo script dovrebbe verificare di essere eseguito con l'UID effettivo previsto. Non date nulla per scontato: verificate sempre.

$EUID è una variabile speciale di Bash che contiene l'ID utente effettivo del processo corrente. Root ha sempre EUID 0. Controllarlo all'inizio dello script, o intorno a un blocco privilegiato, impedisce l'esecuzione accidentale con l'identità sbagliata.

Usate questo pattern di controllo:

#!/usr/bin/env bash
set -euo pipefail

# Guard: this script must NOT run as root.
if [[ "$EUID" -eq 0 ]]; then
  echo "ERROR: Do not run this script as root. Use a normal user account." >&2
  exit 1
fi

echo "Running as UID $EUID — proceeding safely."

Richiedere root solo quando necessario

Alcuni script hanno legittimamente bisogno di root. In tal caso, il controllo funziona al contrario: terminare subito se root non è disponibile, invece di lasciare che lo script raggiunga una syscall privilegiata e produca un errore di permessi poco chiaro durante l'esecuzione.

Combinare l'uscita anticipata con un messaggio d'uso utile rende gli script autoesplicativi:

#!/usr/bin/env bash
set -euo pipefail

require_root() {
  if [[ "$EUID" -ne 0 ]]; then
    echo "ERROR: $(basename "$0") must be run as root." >&2
    echo "  Try: sudo $(basename "$0") $*" >&2
    exit 1
  fi
}

require_root "$@"

echo "Root confirmed (EUID=0). Starting privileged work..."

Limitare sudo a singoli comandi

L'errore più comune consiste nel mettere sudo all'inizio di uno script e poi eseguire tutto come root. Applicate invece sudo solo al comando esatto che ne ha bisogno: tutto il resto viene eseguito come utente normale.

In questo modo si limita il raggio d'azione: se un attaccante inserisce codice nello script, può eseguire con permessi di root solo le parti precedute da sudo.

Confrontate i due pattern seguenti. Il secondo è nettamente più sicuro:

#!/usr/bin/env bash
set -euo pipefail

# BAD: escalate early, do everything as root (avoid this)
# sudo bash -c '
#   cp config.conf /etc/app/config.conf
#   chown app:app /etc/app/config.conf
#   systemctl restart app
# '

# GOOD: escalate only for the commands that require it
LOCAL_CONF="./config.conf"
DEST="/etc/app/config.conf"

# Unprivileged: validate the config before touching anything as root
if ! grep -q '^[[:space:]]*\[main\]' "$LOCAL_CONF"; then
  echo "ERROR: config.conf is missing [main] section" >&2
  exit 1
fi

# Privileged: only these three commands run under sudo
sudo cp "$LOCAL_CONF" "$DEST"
sudo chown app:app "$DEST"
sudo systemctl restart app

echo "Config deployed and service restarted."

Scrivere regole sudoers restrittive

Richiamare sudo somecommand in uno script è sicuro solo se il file sudoers è configurato per consentire esattamente quel comando, e nient'altro. Evitate regole come ALL=(ALL) NOPASSWD: ALL per gli account di servizio.

Limitate invece le regole a comandi specifici con argomenti specifici, usando la sintassi sicura per visudo. Campi principali di una regola sudoers:

  • User — chi può invocare sudo
  • Host — su quale macchina (usate ALL per la portabilità)
  • RunAs — quale identità assumere (quasi sempre root)
  • Command — percorso assoluto completo, facoltativamente con argomenti letterali

Esempi di regole restrittive per un account di servizio di deployment (deployer):

# /etc/sudoers.d/deployer  (edit with: sudo visudo -f /etc/sudoers.d/deployer)
#
# Allow 'deployer' to restart exactly one service — nothing else
deployer ALL=(root) NOPASSWD: /usr/bin/systemctl restart app

# Allow copying a config file to a fixed destination only
deployer ALL=(root) NOPASSWD: /usr/bin/cp /home/deployer/staging/config.conf /etc/app/config.conf

# Allow chown of that specific file only
deployer ALL=(root) NOPASSWD: /usr/bin/chown app\:app /etc/app/config.conf

# NEVER do this — gives full root shell:
# deployer ALL=(ALL) NOPASSWD: ALL

Abbandonare i privilegi con su e runuser

Quando uno script viene avviato come root (ad esempio da un sistema init o da cron in esecuzione come root), ma la maggior parte del lavoro dovrebbe essere svolta da un utente non privilegiato, abbandonate esplicitamente i privilegi invece di eseguire l'intero script come root.

Due strumenti per farlo:

  • su -s /bin/bash -c 'command' username — avvia una shell come username ed esegue il comando
  • runuser -u username -- command args — preferibile su Linux per il cambio di utente all'interno di script di proprietà di root; è più pulito di su

Il pattern seguente mostra un wrapper di deployment di proprietà di root che passa all'utente app per la logica effettiva dell'applicazione:

#!/usr/bin/env bash
# This script is called by systemd as root during pre-deployment
set -euo pipefail

APP_USER="app"
DEPLOY_DIR="/opt/myapp"

# Step 1: privileged — fix ownership of deploy directory
chown -R "${APP_USER}:${APP_USER}" "$DEPLOY_DIR"

# Step 2: drop to app user for the actual migration/startup logic
# runuser is available on most modern Linux systems
runuser -u "$APP_USER" -- bash -c "
  cd $DEPLOY_DIR
  ./bin/migrate.sh
  ./bin/start.sh
"

echo "Deploy complete. Privileged wrapper exiting."

Usare sudo -u per eseguire un singolo comando come un altro utente

Non è sempre necessario avviare una sessione shell completa. sudo -u username command esegue un singolo comando come l'utente specificato, quindi torna all'identità chiamante. È utile per modificare file di proprietà di un account di servizio senza concedere a quell'account alcun accesso interattivo.

Abbinate questa tecnica a una regola sudoers che consenta esattamente quella combinazione di utente e comando:

#!/usr/bin/env bash
set -euo pipefail

# Scenario: deploy script runs as 'deployer'; DB migrations must run as 'postgres'
# sudoers entry needed:
#   deployer ALL=(postgres) NOPASSWD: /opt/app/bin/run_migrations.sh

DB_MIGRATION_SCRIPT="/opt/app/bin/run_migrations.sh"

if [[ ! -x "$DB_MIGRATION_SCRIPT" ]]; then
  echo "ERROR: migration script not found or not executable: $DB_MIGRATION_SCRIPT" >&2
  exit 1
fi

echo "Running DB migrations as postgres user..."
sudo -u postgres "$DB_MIGRATION_SCRIPT"

echo "Migrations done. Returning to deployer context (EUID=$EUID)."

Evitare l'escalation dei privilegi tramite le variabili d'ambiente

Una superficie d'attacco sottile è rappresentata dalle variabili d'ambiente ereditate da una sessione sudo. Per impostazione predefinita, sudo reimposta l'ambiente, ma configurazioni errate di env_keep o override di env_reset possono passare variabili controllate dall'attaccante, come LD_PRELOAD, PATH o PYTHONPATH, ai comandi privilegiati.

Buone pratiche:

  • Usate sempre percorsi assoluti negli script eseguiti tramite sudo: non fate mai affidamento su $PATH
  • Passate solo le variabili esplicitamente necessarie: sudo env VAR=value /path/to/cmd
  • In sudoers, evitate env_keep += PATH o env_keep += LD_*
  • Usate sudo -E solo quando controllate completamente e considerate attendibile l'ambiente chiamante
#!/usr/bin/env bash
set -euo pipefail

# BAD: relies on $PATH — attacker who controls PATH can hijack 'cp'
# sudo cp config.conf /etc/app/

# GOOD: absolute paths for every command called under elevated context
SUDO_BIN="/usr/bin/sudo"
CP_BIN="/usr/bin/cp"
CHOWN_BIN="/usr/bin/chown"
SYSTEMCTL_BIN="/usr/bin/systemctl"

"$SUDO_BIN" "$CP_BIN" ./config.conf /etc/app/config.conf
"$SUDO_BIN" "$CHOWN_BIN" app:app /etc/app/config.conf
"$SUDO_BIN" "$SYSTEMCTL_BIN" restart app

echo "Deployed with hardened absolute-path invocations."

Limitare sudo con la convalida degli argomenti dei comandi

Anche quando una regola sudoers consente uno script specifico, a tale script possono essere passati argomenti arbitrari, a meno che anche questi non siano limitati dalla regola. Un errore comune è il seguente:

deployer ALL=(root) NOPASSWD: /opt/scripts/manage.sh

Questo consente sudo /opt/scripts/manage.sh restart, ma anche sudo /opt/scripts/manage.sh --arbitrary-flag. Se manage.sh passa gli argomenti senza controlli ai sottocomandi privilegiati, avete un problema.

Applicate la difesa in profondità: convalidate gli argomenti all'interno dello script privilegiato e anche in sudoers:

#!/usr/bin/env bash
# /opt/scripts/manage.sh — called via sudo; must validate its own args
set -euo pipefail

# Allowlist of valid actions
declare -A ALLOWED_ACTIONS=(
  [restart]=1
  [status]=1
  [reload]=1
)

ACTION="${1:-}"

if [[ -z "$ACTION" ]]; then
  echo "Usage: $(basename "$0") <restart|status|reload>" >&2
  exit 1
fi

if [[ -z "${ALLOWED_ACTIONS[$ACTION]:-}" ]]; then
  echo "ERROR: Unknown action '${ACTION}'. Allowed: ${!ALLOWED_ACTIONS[*]}" >&2
  exit 2
fi

/usr/bin/systemctl "$ACTION" app
echo "Action '$ACTION' executed successfully."

Elevazione temporanea dei privilegi con trappola di pulizia

Quando uno script deve disporre brevemente di un file, una credenziale o una risorsa con privilegi elevati, utilizzi trap di Bash per garantire che la pulizia venga eseguita anche in caso di errore o di segnale. In questo modo si evitano fughe di privilegi, ad esempio un binario setuid temporaneo o un socket di proprietà di root lasciato sul sistema se lo script va in crash.

Il modello seguente crea un file temporaneo come root, lo utilizza e poi lo rimuove: l'operazione è garantita da una trap su EXIT:

#!/usr/bin/env bash
set -euo pipefail

# Must run as root for this demo
if [[ "$EUID" -ne 0 ]]; then
  echo "Run as root" >&2; exit 1
fi

TMP_SECRET=""

cleanup() {
  local exit_code=$?
  if [[ -n "$TMP_SECRET" && -f "$TMP_SECRET" ]]; then
    # Overwrite before deletion to reduce forensic recovery risk
    shred -u "$TMP_SECRET" 2>/dev/null || rm -f "$TMP_SECRET"
    echo "[cleanup] Removed privileged temp file." >&2
  fi
  exit "$exit_code"
}

trap cleanup EXIT INT TERM

# Create a root-owned temp file for a short-lived secret
TMP_SECRET="$(mktemp /tmp/deploy_secret.XXXXXXXX)"
chmod 600 "$TMP_SECRET"

# Simulate fetching a secret into the temp file
echo "super-secret-token" > "$TMP_SECRET"

# Use the secret (e.g., pass to a sub-command via file descriptor)
/usr/bin/some-privileged-tool --key-file "$TMP_SECRET"

echo "Privileged operation complete."

Verifica e registrazione delle azioni con privilegi

Il principio del privilegio minimo è più facile da applicare quando ogni evento di elevazione viene registrato con il relativo contesto: chi ha eseguito l'operazione, che cosa, quando e perché. Combini due livelli:

  1. sudo stesso — /var/log/auth.log (Debian/Ubuntu) o /var/log/secure (RHEL) registra automaticamente ogni invocazione di sudo
  2. Registro di audit a livello di script — scriva una voce strutturata all'inizio di ogni funzione con privilegi, in modo che l'intento venga registrato insieme al log di sistema

L'utilizzo di una semplice funzione per i log strutturati mantiene coerenti e facili da cercare con grep le tracce di audit:

#!/usr/bin/env bash
set -euo pipefail

AUDIT_LOG="/var/log/app_deploy_audit.log"

log_privileged_action() {
  local action="$1"
  local reason="${2:-unspecified}"
  local ts
  ts="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
  printf '{"ts":"%s","user":"%s","euid":%d,"action":"%s","reason":"%s"}\n' \
    "$ts" "${SUDO_USER:-$USER}" "$EUID" "$action" "$reason" \
    | sudo tee -a "$AUDIT_LOG" > /dev/null
}

# Each privileged step is logged before execution
log_privileged_action "cp_config" "deploy release v2.4.1"
sudo /usr/bin/cp ./config.conf /etc/app/config.conf

log_privileged_action "chown_config" "ensure app user owns config"
sudo /usr/bin/chown app:app /etc/app/config.conf

log_privileged_action "restart_service" "activate new config"
sudo /usr/bin/systemctl restart app

echo "Deployment complete. Audit entries written to $AUDIT_LOG"

Verifica delle conoscenze: ambito di sudo

Verifichi la propria comprensione dell'esecuzione con privilegi minimi negli script Bash.

Riepilogo: esecuzione con privilegi minimi e uso disciplinato di sudo

In questa lezione ha acquisito le tecniche per eseguire gli script Bash con il livello minimo di privilegi necessario in ogni passaggio. Ecco un riepilogo conciso dei principi fondamentali:

  • Verifichi con $EUID — interrompa subito l'esecuzione se lo script viene eseguito con l'identità sbagliata, sia che ciò significhi rifiutare root, sia che ne richieda l'uso
  • Limiti sudo ai singoli comandi — non elevi mai i privilegi di un intero script; applichi sudo solo alle righe che ne hanno realmente bisogno
  • Scriva regole sudoers restrittive — specifichi i percorsi assoluti completi e gli argomenti letterali; eviti i caratteri jolly e ALL
  • Rinunci ai privilegi con runuser o sudo -u — quando uno script avviato da root deve passare il controllo a un utente senza privilegi, utilizzi lo strumento appropriato invece di eseguire tutto come root
  • Utilizzi percorsi assoluti — non faccia mai affidamento su $PATH all'interno del codice con privilegi; codifichi direttamente i percorsi dei binari per impedire il loro dirottamento
  • Convalidi gli argomenti all'interno degli script con privilegi — le regole sudoers sono la prima linea di difesa, non l'unica; utilizzi delle allowlist
  • Imposti una trap e pulisca le risorse — utilizzi trap cleanup EXIT per garantire che le risorse temporanee con privilegi vengano distrutte anche in caso di errore
  • Registri ogni elevazione — le voci di audit strutturate, unite al syslog integrato di sudo, garantiscono la tracciabilità di ogni azione con privilegi

Applicate con coerenza, queste pratiche riducono la superficie di attacco della Sua automazione da root sempre a root solo dove è dimostrabilmente necessario: il segno distintivo di Bash consolidato e adatto alla produzione.

Domande Frequenti

La lezione «Esecuzione con privilegi minimi e disciplina nell'uso di sudo» è gratuita?

Sì — il testo completo di «Esecuzione con privilegi minimi e disciplina nell'uso di sudo» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Linux Command Line & Bash Scripting Mastery, passa a CoddyKit PRO. Il corso Linux Command Line & Bash Scripting Mastery include 4 lezioni in totale.

Cosa imparerò in «Esecuzione con privilegi minimi e disciplina nell'uso di sudo»?

Riduca i privilegi, limiti con precisione le regole sudo e convalidi l'UID effettivo prima delle operazioni rischiose. Eserciti Linux Command Line & Bash Scripting Mastery con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Linux Command Line & Bash Scripting Mastery?

Non è richiesta alcuna esperienza precedente. Linux Command Line & Bash Scripting Mastery su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Esecuzione con privilegi minimi e disciplina nell'uso di sudo»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Linux Command Line & Bash Scripting Mastery?

Sì. Ogni lezione Linux Command Line & Bash Scripting Mastery include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Prevenire l'iniezione di comandi e argomenti
  2. Gestire i segreti in sicurezza e mantenere pulito l'ambiente
  3. Esecuzione con privilegi minimi e disciplina nell'uso di sudo
  4. Analisi statica e audit con ShellCheck
← Torna a Linux Command Line & Bash Scripting Mastery