← retour aux snippets

setcap: écouter sur 80/443 sans root

Autoriser un binaire à lier des ports <1024 (CAP NET BIND SERVICE) sans exécuter l'app en root.


objectif

Permettre à une application (web, proxy) d’écouter sur 80/443 sans sudo ni root en lui accordant uniquement la capability CAP_NET_BIND_SERVICE, plus sûre que lancer tout le process en root.

code minimal

# donner CAP_NET_BIND_SERVICE au binaire (Linux, paquet libcap2-bin)
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/myapp
getcap -v /usr/local/bin/myapp

# exécuter en utilisateur non privilégié, l'app peut écouter sur :80/:443
/usr/local/bin/myapp --port 80

utilisation

# vérifier l'écoute effective (Linux)
ss -ltnp | grep -E ':(80|443)\s'

# retirer la capability (rollback)
sudo setcap -r /usr/local/bin/myapp
getcap -v /usr/local/bin/myapp || echo "aucune capability"

# éviter de donner la capability à un interpréteur (node, python): préférez un wrapper dédié
# 1) wrapper minimal
sudo install -m 0755 /dev/stdin /usr/local/bin/myapp-bind80 <<'SH'
#!/usr/bin/env bash
exec /usr/local/bin/myapp --port 80 "$@"
SH
# 2) capability sur le wrapper uniquement
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/myapp-bind80
getcap -v /usr/local/bin/myapp-bind80
# 3) lancer en user standard
/usr/local/bin/myapp-bind80

variante(s) utile(s)

# systemd (service file): accorder la capability au process sans setcap sur le fichier
# (dans la section [Service] du unit)
# AmbientCapabilities=CAP_NET_BIND_SERVICE
# CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# NoNewPrivileges=true
# User=www-data
# Group=www-data

# alternative sans capabilities: rediriger le port 80 -> 8080 (nftables/iptables)
# nftables (recommandé sur distributions récentes)
sudo nft add table ip nat
sudo nft 'add chain ip nat PREROUTING { type nat hook prerouting priority 0; }' 2>/dev/null || true
sudo nft add rule ip nat PREROUTING tcp dport 80 redirect to :8080
# pour trafic local (OUTPUT -> 8080)
sudo nft add chain ip nat OUTPUT "{ type nat hook output priority 0; }" 2>/dev/null || true
sudo nft add rule ip nat OUTPUT tcp dport 80 redirect to :8080

# iptables (héritage)
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 8080

# vérifier la capability effective à l'exécution (capsh)
capsh --print | grep -i cap_net_bind_service || true

notes

  • setcap 'cap_net_bind_service=+ep' ajoute la capability au fichier (extended attributes). Un remplacement du binaire lors d’un déploiement efface la capability: réappliquez-la après mise à jour.
  • n’accordez jamais la capability à un interpréteur générique (node, python): tout script hériterait du droit. Utilisez un wrapper ou la configuration systemd avec AmbientCapabilities.
  • exécutez toujours l’application sous un utilisateur dédié non privilégié; gardez un umask strict et des permissions minimales.
  • si vous ne pouvez pas utiliser les capabilities, redirigez le port 80 vers un port haut (8080) via nftables/iptables et laissez l’app écouter sur 8080.
  • macOS ne supporte pas Linux capabilities; utilisez un reverse proxy local ou une redirection de port (pf) au besoin.