TUTOS.EU

Lancer automatiquement un programme via un script au démarrage de Linux


Sachez que vous pouvez simplement utiliser crontab pour exécuter une commande au démarrage d'une machine
Pour cela ouvrez le ficher crontab avec

crontab -e
Lien vers le fichier : cliquez ici Copier le code

Ajoutez cette ligne (touche "o" dans vi pour ajouter une ligne puis "echap" et :x pour enregistrer

@reboot sleep 30 && /usr/bin/echo "mon test" > ~/test
Lien vers le fichier : cliquez ici Copier le code

Après reboot, vous devriez voir un fichier nommé "test" à la racine du home du compte root avec "mon test" en contenu


Pour l'exemple, je vais créer un fichier de configuration de firewall.
Utilisez d'autres commandes chez vous dans votre script sinon cela risque de mettre le souk dans votre configuration.

Donc j'ai commencé par créé un fichier de script dans /etc/init.d avec les commandes suivantes.
Le fichier de script va se nommer firewall.sh

cd /etc/init.d
nano firewall.sh
Lien vers le fichier : cliquez ici Copier le code

Comme expliqué sur https://abs.traduc.org/abs-fr/ch02.html, votre script doit commencer par un sha-bang

Un sha-bang est une en tête indique au système que le fichier est un ensemble de commandes à exécuter avec un interpréteur que l'on va indiquer.

Les 2 premiers caractères #! sont codés sur deux octets. Ils correspondent à un marqueur spécial qui désigne un type de fichier. Dans notre cas c'est un script shell exécutable (lancez man magic pour plus de détails).

Tout de suite après le sha-bang se trouve le chemin vers le programme qui va interpréter les commandes du script.

 

Votre fichier peut donc commencer en indiquant l'un de ces interpréteurs :
 

#!/bin/sh
#!/bin/bash
#!/usr/bin/perl
#!/usr/bin/tcl
#!/bin/sed -f
#!/bin/awk -f

 

Pour mon script de configuration de firewall, j'ai pris le premier :
#!/bin/sh

 

Ensuite Il faut aussi mettre ce type d'informations pour répondre au standard LSB (Linux Standard Base) .

C'est un standard de structure pour les scripts d'initialisation système :

 

## BEGIN INIT INFO
# Provides:          Firewall maison
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# X-Interactive:     false
# Short-Description: Firewall maison
### END INIT INFO

J'ai ensuite placé ce contenu qui va configurer mon firewall.
Vous vous mettrez les commandes qui vous conviennent.

#!/bin/sh
## BEGIN INIT INFO
# Provides:          Firewall maison
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# X-Interactive:     false
# Short-Description: Firewall maison
### END INIT INFO

#Réinitialiser iptables
	#-F pour -flush : Delete all rules in  chain or all chains
	#-X pour à priori --delete-chain : Delete a user-defined chain
sudo iptables -F
sudo iptables -X
sudo ip6tables -F
	
#permettre à une connexion déjà ouverte de recevoir du trafic :
	# notez que pour les nouvelles versions la commande peut être :
	# iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT

#Authoriser l'interface locale (loopback).
iptables -t filter -A INPUT -i lo -j ACCEPT
iptables -t filter -A OUTPUT -o lo -j ACCEPT

#Création d'une new user-defined chain pour pouvoir autoriser ET logger un flux avec le préfixe iptables
iptables -N LOGACCEPT
iptables -A LOGACCEPT -j LOG --log-prefix 'iptables:' -m limit --limit 2/min
iptables -A LOGACCEPT -j ACCEPT

#Création d'une new user-defined chain pour pouvoir explicitement bloquer et logger un flux avec le préfixe iptables
iptables -N LOGDROP
iptables -A LOGDROP -j LOG --log-prefix 'iptables:' -m limit --limit 2/min
iptables -A LOGDROP -j DROP

#On aurait pu préciser dans chaque règle de rejet qu'elle interface était concernée, comme par exemple eth0 en spécifiant -i eth0, mais avouez que c'est nettement plus compliqué.
#Si vous n'avez pas authorisé le traffic de loopback dans les première règles et donc que vous le faites après coup, il faut s'assurer que cette règle soit dans les premières. Pour cela on va faire un Insert en seconde position avec cette commande
#iptables -t filter -I INPUT 2 -i lo -j ACCEPT
#iptables -t filter -I OUTPUT 2 -i lo -j ACCEPT

#Permettre le trafic entrant et sortant pour le port SSH, cad le port 22
iptables -t filter -A INPUT -p tcp --dport 22 -j LOGACCEPT #-i eth0
iptables -t filter -A OUTPUT -p tcp --dport 22 -j ACCEPT
echo "ssh ok"

#Autoriser le ping en entrée et sortie
iptables -t filter -A INPUT -p icmp -j LOGACCEPT
iptables -t filter -A OUTPUT -p icmp -j ACCEPT
echo "ping ok"

#Autoriser les requêtes DNS en sortie
iptables -t filter -A OUTPUT -p tcp --dport 53 -j ACCEPT
iptables -t filter -A OUTPUT -p udp --dport 53 -j ACCEPT
echo "dns ok"

#Autoriser les requêtes NTP en sortie pour pouvoir se synchroniser au niveau temps
iptables -t filter -A OUTPUT -p udp --dport 123 -j ACCEPT
echo "ntp ok"

#Changer la politique par défaut sur les paquets entrants pour que, sans règle appliquée, le paquet soit rejeté. Attention donc à avoir au préalable autoriser le SSH par exemple.
#On aurait pu laisser la politique par défaut à ACCEPT et avoir placé en toute dernière règle une qui refuse tout. Les paquets autorisés par les règles précédentes n'atteindraient pas celle-ci.

#Modification de la politique par défaut pour iptables de ipV6. On bloque en entrée et en transfert
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP

#Modification pour ipv4
#iptables -A INPUT -j DROP
iptables -P INPUT DROP

#Modification de la politique par défaut sur les paquets transférés afin que par défaut ils soient bloqués
iptables -P FORWARD DROP

#On peut modifier la politique par défaut pour bloquer de base les paquets sortants mais personnellement je ne le fais pas car je trouve cela trop violent
#iptables -P OUTPUT ACCEPT

echo "Script de configuration de iptables terminé"
Lien vers le fichier : cliquez ici Copier le code

J'ai sauvegardé le fichier, quitté nano puis j'ai donné les droits d'exécution au fichier firewall.sh avec la commande

chmod +x firewall.sh
Lien vers le fichier : cliquez ici Copier le code

J'ai testé l'exécution du script avec la commande suivante, fermé ma session ssh et vérifié que je pouvais toujours me connecter en ssh sur mon linux

./firewall.sh
Lien vers le fichier : cliquez ici Copier le code

systemd remplace maintenant système V.

Pour que firewall.sh se lance automatiquement au lancement de Linux avec systemd, créer le fichier du service avec la commande

sudo nano /lib/systemd/system/iptables.service
Lien vers le fichier : cliquez ici Copier le code

Y placer ce contenu.

Au niveau de ExecStart, mettre le chemin de votre propre script.
Mettez également à jour la description.

sauvegarder et quitter

[Service]
Description=Iptables configuration
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/init.d/firewall.sh

[Install]
WantedBy=multi-user.target
Lien vers le fichier : cliquez ici Copier le code

La signification des valeurs est expliquée sur https://doc.ubuntu-fr.org/creer_un_service_avec_systemd
Voici un très petit aperçu

Champ Commande Valeur Signification
Service Type simple Valeur par défaut. Utilisé pour lancer un processus principal.
Service Type oneshot Typiquement utilisé comme équivalent aux commandes lancées au démarrage via les scripts d'init system V. Système similaire à un service de type simple. Cependant, systemd attend que le processus se termine avant de continuer ses traitements.
Service Type forking Correspond aux services UNIX traditionnels. Lance un processus père qui créera un processus fils dans le cadre de son démarrage. Le processus parent est prévu pour s’arrêter une fois le démarrage complet et que tous les canaux de communication sont mis en place.
Service Type dbus Similaire à un service de type simple. Cependant, le processus du service doit obtenir un nom via D-Bus. systemd pourra alors traiter les autres unités.
Service Type notify Similaire à un service de type simple. Cependant, c'est le processus du service qui avertira systemd qu'il peut traiter les autres unités.
Service RemainAfterExit yes Pour indiquer que quand la commande est lancée, le service est considéré toujours actif. Très utile pour les services de type "oneshot" qui exécutent une commande à leur lancement (ExecStart) sans qu'il y ait un processus spécifique qui reste en exécution.
Service ExecStart Programme Script ou programme à lancer, avec ses paramètres
Service ExecStop Programme Commande à exécuter pour arrêter le script ou programme
Install WantedBy multi-user.target Mode multi-utilisateur, non graphique

Une fois le fichier de configuration de service crée, il faut l'activer pour qu'il soit pris en compte par le système

systemctl enable iptables.service
Lien vers le fichier : cliquez ici Copier le code

Lancer le service et contrôler son status avec

systemctl start iptables.service
systemctl status iptables.service
Lien vers le fichier : cliquez ici Copier le code

Pour l'exemple et pour pouvoir faire une comparaison, voici comment est configuré un service kafka qui doit se lancer après celui de zookeeper.
C'est un vrai service. Il ne se lance pas en oneshot. Il est cencé toujours fonctionner.
Le type est donc ici 'simple' et non 'oneshot'

On trouve également en plus une section [Unit] qui donne une dépendance avec zookeeper

[Unit]
Requires=zookeeper.service
After=zookeeper.service

[Service]
Type=simple
User=kafka
ExecStart=/bin/sh -c '/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties > /opt/kafka/kafka.log 2>&1'
ExecStop=/opt/kafka/bin/kafka-server-stop.sh
Restart=on-abnormal

[Install]
WantedBy=multi-user.target
Lien vers le fichier : cliquez ici Copier le code

Taper ces commandes pour que le script firewall.sh se lance automatiquement à chaque boot avant l'ancien system V. system V ne fonctionne plus avec les nouveaux systèmes.

cd /etc/init.d
update-rc.d firewall.sh defaults
Lien vers le fichier : cliquez ici Copier le code

Pour annuler la commande précédente, taper

update-rc.d -f firewall.sh remove
Lien vers le fichier : cliquez ici Copier le code

Vérifiez que vous trouvez bien votre script après avoir tapé cette commande

ls -l /etc/rc*.d
Lien vers le fichier : cliquez ici Copier le code

Effectuer un reboot pour voir si le script se lançait bien

shutdown -r now
Lien vers le fichier : cliquez ici Copier le code

Pages Web

Site WebDescription
Dexterindustries.comFive Ways To Run a Program On Your Raspberry Pi At Startup
Guillaume.fenollar.frIntroduction à Journald et Journalctl

2