Best practices : autoriser la création de fichiers dans un répertoire etc.

15 réponses
Avatar
Francois Lafont
Bonjour à tous,

J'ai un question de sécurité en quelques sorte et j'aimerais
avoir votre avis. Avant, je pense que c'est mieux que je donne
le contexte même si ça va un peu allonger le message (désolé).
C'est un contexte de supervision mais la question elle, n'a pas
de rapport avec la supervision.

Nous avons plusieurs serveurs sur lesquels tournent des tâches
cron. On a une boîte mail dédiées qui reçoit la sortie des crons.
Au final, ça fait un nombre assez important de mails qui arrivent
chaque jour dans cette boîte et du coup plus personnes n'y prête
attention. Sans compter les crons écrits il y a x années qui, en
cas de soucis envoient un mail à telle ou telle personne qui ne
travaille même plus chez nous. Bref, c'est un peu le zouk et je
voudrais tenter te centraliser tout ça via notre logiciel de
supervision.

Ce que je voudrais mettre en place, c'est une sorte de wrapper
pour cron, appelons-le wcron, qui permettrait de stocker quelque
part le exit code du cron afin que le logiciel de supervision
puisse régulièrement aller checker que tous les exit code sont
bien à 0.

Plus précisément, je suppose que sur tous les serveurs, il
existe un répertoire /usr/local/crons/ (ça, ça va). Un appel
d'un cron, au lieu d'être ceci :

/usr/local/bin/cron-truc.sh -o -v arg1 arg2

deviendrait cela :

/usr/bin/wcron --label "cron-truc" -- /usr/local/bin/un-cron.sh -o -v arg1 arg2

Voilà ce que ferait la commande wcron ci-dessus :

- si, dans /usr/local/crons/, le fichier cron-truc (nom issu de
l'option --label) n'existe pas, celui-ci est créé.

- ensuite wcron exécute tout simplement le cron « truc » ie
lance la commande « /usr/bin/un-cron -o -v arg1 arg2 » en
prenant soin de récupérer le exit code cette commande.

- enfin wcron écrit le exit code récupéré précédemment dans le
fichier /usr/local/crons/cron-truc.

Et c'est tout. Ensuite, côté supervision, j'aurais un check
qui scruterait le répertoire /usr/local/crons/ et lancerait
une alerte si un fichier contiendrait autre chose que 0 (pas
de souci de ce côté là non plus).

Mon problème se trouve au niveau de la création du fichier
/usr/local/crons/cron-truc. En effet, je pensais définir les
droits au niveau du répertoire /usr/local/crons/ comme ceci :

drwxr-xr-x root:root

Du coup, si le wcron est lancé en tant que root, pas de souci,
le fichier /usr/local/crons/cron-truc pourra être créé sans
problème. Mais si le wcron est lancé par un compte autre que
root (ce qui arrive souvent), alors là j'ai un problème car le
compte n'aura tout simplement pas le droit de créer le fichier
dans lequel le exit code sera stocké.

Tout mon problème est là, comment faire ? Et je dirais même,
comment faire de manière correcte au niveau sécurité. Peut-être
que c'est une mauvaise idée et peut-être que ma manière de penser
le problème est mauvaise au départ ? (C'est pourquoi j'ai
préféré indiquer tout le contexte.)

Au tout début, j'ai pensé à faire mumuse avec le bit setuid etc.
mais on voit bien sur le web que ce n'est pas trop recommandé
au niveau sécurité. Du coup, pour l'instant, je pense passer
par sudo. Par exemple je crée une commande
/usr/bin/wcron_touch_file qui ferait ceci (en gros, je passe
toutes les étapes de vérifications) :

---------------------------------------------
#!/bin/sh

label="$1"
owner="$2"

touch "/usr/local/crons/$1"
chown "$owner:" "/usr/local/crons/$1"
---------------------------------------------

Et avec sudo, je m'arrangerais pour que /usr/bin/wcron_touch_file
puisse être exécuté par « n'importe qui » en tant que root et
sans mot de passe.

Est-ce ça se tient ou bien est-ce complètement foireux ?
Évidemment, par exemple, ça signifie que potentiellement
n'importe quel compte peu créer autant de fichiers qu'il
veut dans /usr/local/crons/ jusqu'à par exemple remplir
la table des inodes etc. Mais d'un autre côté il me semble
qu'on peut dire exacctement la même chose de /tmp/ et qu'a
priori personne ne s'en émeut, non ?

Sinon, une autre politique consiste à dire que la création
du fichier dans /usr/local/crons/ doit être faite manuellement
une première fois par celui qui met en place le cron. Mais
ça fait une tâche supplémentaire à faire et j'aimais bien
l'idée d'avoir qu'à rajouter le wcron « par dessus » le cron
(avec quand même l'obligation pour celui qui met en place
le cron de bien vérifier que "tout se passe bien" ssi le
exit code est 0).

Bref, je suis encore un peu dans le flou. Il est évident
que je ne souhaite pas mettre en place le moindre trou
de sécurité potentiel etc. C'est pourquoi je me tourne
vers vous. ;)

Merci d'avance pour vos lumières.

--
François Lafont

10 réponses

1 2
Avatar
Julien Salgado
Francois Lafont a écrit :
Ce que je voudrais mettre en place, c'est une sorte de wrapper
pour cron, appelons-le wcron, qui permettrait de stocker quelque
part le exit code du cron afin que le logiciel de supervision
puisse régulièrement aller checker que tous les exit code sont
bien à 0.



Bonjour,


L'option -L du cron d'ISC ne conviendrait-elle pas ? Elle permet de
journaliser des informations comme le début, la fin, le code d'erreur...

Ensuite, il suffit de récupérer ces informations via syslog.


--
Julien
Avatar
Francois Lafont
Bonjour,

Le 09/05/2014 17:32, Julien Salgado a écrit :

L'option -L du cron d'ISC ne conviendrait-elle pas ? Elle permet de
journaliser des informations comme le début, la fin, le code d'erreur...

Ensuite, il suffit de récupérer ces informations via syslog.



Merci pour la réponse qui m'a fait découvrir l'option -L
du daemon cron. ;) Ceci étant dit, ça ne me conviendrait
pas trop car cela suppose d'aller chercher l'info dans
syslog. Or sur certains serveurs le syslog se remplit très
vite. J'essaye autant que possible de faire en sorte que
les checks ne demandent pas trop de travail aux serveurs
(et qu'ils soient simple à coder).

Enfin, un autre argument qui fait que je préférerais avoir
un fichier texte dédié pour un cron donné, c'est que je
pourrais par exemple checker le mtime du fichier et si ce
mtime est plus vieux de N jours alors je pourrais lever
une alerte.

--
François Lafont
Avatar
Christophe PEREZ
Le Thu, 08 May 2014 16:19:55 +0200, Francois Lafont a écrit :

Mon problème se trouve au niveau de la création du fichier
/usr/local/crons/cron-truc. En effet, je pensais définir les droits au
niveau du répertoire /usr/local/crons/ comme ceci :

drwxr-xr-x root:root



Je vais sans doute dire une grosse bêtise tellement ça me parait simple,
mais pourquoi ne pas simplement mettre le répertoire "writable" par le
groupe cron, donc 770 :

drwxrwx--- root:cron

Normalement, tout utilisateur pouvant utiliser cron doit appartenir au
groupe cron, et donc pouvoir écrire dans ce répertoire, non ?

sinon, l'autre solution qui m'est venue à l'esprit fait intervenir les
ACL, mais sur X serveurs, ce n'est pas forcément simple à mettre en
oeuvre.
Avatar
Francois Lafont
Bonsoir,

Le 09/05/2014 20:03, Christophe PEREZ a écrit :

Je vais sans doute dire une grosse bêtise tellement ça me parait simple,
mais pourquoi ne pas simplement mettre le répertoire "writable" par le
groupe cron, donc 770 :

drwxrwx--- root:cron

Normalement, tout utilisateur pouvant utiliser cron doit appartenir au
groupe cron, et donc pouvoir écrire dans ce répertoire, non ?



Hélas, sur nos serveurs Debian ça ne semble pas être le cas.
Déjà, je n'ai pas de groupe "cron" mais "crontab", mais bon
c'est un détail. Le point important ici, c'est qu'appartenir
à ce groupe "crontab" ne semble pas nécessaire pour pouvoir
lancer une tâche cron. J'ai un exemple sous les yeux où un
compte non root lance un cron tous les jours sans souci et ce
compte n'appartient pas au groupe crontab.

--
François Lafont
Avatar
Olivier Miakinen
Bonjour,

Le 08/05/2014 16:19, Francois Lafont a écrit :

[...]

Au tout début, j'ai pensé à faire mumuse avec le bit setuid etc.
mais on voit bien sur le web que ce n'est pas trop recommandé
au niveau sécurité.



C'est vraiment déconseillé, ou il est juste recommandé de bien faire
attention à ce que l'on fait ?

Si tu mets le bit setuid à un exécutable que tu as écrit toi-même, et
dont tu sais qu'il ne peut pas être détourné pour faire autre chose
que ce que tu lui demandes de faire, je ne vois pas ce qu'on peut lui
reprocher en terme de sécurité.

Entre autres choses, tu dois t'assurer que le programme peut aller
écrire dans un fichier « cron-truc » sous « /usr/local/crons » mais
pas dans le fichier « ../../../etc/passwd » ! Il faut donc interdire
les « / » dans le nom... ou encore mieux : n'autoriser que les
caractères que tu as explicitement définis au départ, par exemple
[a-zA-Z] et rien d'autre.

Et donc, cela te demandera pas mal d'attention lors de l'écriture du
programme pour t'assurer que l'on ne *peut* pas l'utiliser de façon
dangereuse, mais ensuite à mon avis tu peux lui mettre un bit setuid.

Cordialement,
--
Olivier Miakinen
Avatar
Erwan David
Olivier Miakinen <om+ écrivait :

Bonjour,

Le 08/05/2014 16:19, Francois Lafont a écrit :

[...]

Au tout début, j'ai pensé à faire mumuse avec le bit setuid etc.
mais on voit bien sur le web que ce n'est pas trop recommandé
au niveau sécurité.



C'est vraiment déconseillé, ou il est juste recommandé de bien faire
attention à ce que l'on fait ?

Si tu mets le bit setuid à un exécutable que tu as écrit toi-même, et
dont tu sais qu'il ne peut pas être détourné pour faire autre chose
que ce que tu lui demandes de faire, je ne vois pas ce qu'on peut lui
reprocher en terme de sécurité.

Entre autres choses, tu dois t'assurer que le programme peut aller
écrire dans un fichier « cron-truc » sous « /usr/local/crons » mais
pas dans le fichier « ../../../etc/passwd » ! Il faut donc interdire
les « / » dans le nom... ou encore mieux : n'autoriser que les
caractères que tu as explicitement définis au départ, par exemple
[a-zA-Z] et rien d'autre.

Et donc, cela te demandera pas mal d'attention lors de l'écriture du
programme pour t'assurer que l'on ne *peut* pas l'utiliser de façon
dangereuse, mais ensuite à mon avis tu peux lui mettre un bit setuid.

Cordialement,



Mais ici je ne vois pas ce que crontab(1) ne fait pas ?
Le programme existe déjà...


--
Les simplifications c'est trop compliqué
Avatar
Olivier Miakinen
Le 10/05/2014 13:41, Erwan David m'a répondu :

Mais ici je ne vois pas ce que crontab(1) ne fait pas ?
Le programme existe déjà...



Je ne répondais qu'à la question de la dangerosité du setuid.

S'il existe une solution plus simple (cf. ta réponse et celles
de Julien et Christophe), oui, ce sera toujours mieux que de
devoir écrire un nouveau programme en faisant attention à ce
qu'il ne présente pas de risque de sécurité.
Avatar
Damien Wyart
* Francois Lafont in fr.comp.os.linux.configuration:
Hélas, sur nos serveurs Debian ça ne semble pas être le cas.
Déjà, je n'ai pas de groupe "cron" mais "crontab", mais bon
c'est un détail. Le point important ici, c'est qu'appartenir
à ce groupe "crontab" ne semble pas nécessaire pour pouvoir
lancer une tâche cron. J'ai un exemple sous les yeux où un
compte non root lance un cron tous les jours sans souci et ce
compte n'appartient pas au groupe crontab.



Ce sont les fichiers /etc/cron.allow et /etc/cron.deny qui contrôlent
ceci. Extrain du man crontab :

,----
| If the /etc/cron.allow file exists, then you must be listed (one user
| per line) therein in order to be allowed to use this command. If the
| /etc/cron.allow file does not exist but the /etc/cron.deny file does
| exist, then you must not be listed in the /etc/cron.deny file in order
| to use this command.
|
| If neither of these files exists, then depending on site-dependent
| configuration parameters, only the super user will be allowed to use
| this command, or all users will be able to use this command.
|
| If both files exist then /etc/cron.allow takes precedence. Which means
| that /etc/cron.deny is not considered and your user must be listed in
| /etc/cron.allow in order to be able to use the crontab.
|
| Regardless of the existance of any of these files, the root
| administrative user is always allowed to setup a crontab. For standard
| Debian systems, all users may use this command.
`----

--
DW
Avatar
Francois Lafont
Bonjour,

Le 10/05/2014 13:19, Olivier Miakinen a écrit :

C'est vraiment déconseillé, ou il est juste recommandé de bien faire
attention à ce que l'on fait ?

Si tu mets le bit setuid à un exécutable que tu as écrit toi-même, et
dont tu sais qu'il ne peut pas être détourné pour faire autre chose
que ce que tu lui demandes de faire, je ne vois pas ce qu'on peut lui
reprocher en terme de sécurité.

Entre autres choses, tu dois t'assurer que le programme peut aller
écrire dans un fichier « cron-truc » sous « /usr/local/crons » mais
pas dans le fichier « ../../../etc/passwd » ! Il faut donc interdire
les « / » dans le nom... ou encore mieux : n'autoriser que les
caractères que tu as explicitement définis au départ, par exemple
[a-zA-Z] et rien d'autre.

Et donc, cela te demandera pas mal d'attention lors de l'écriture du
programme pour t'assurer que l'on ne *peut* pas l'utiliser de façon
dangereuse, mais ensuite à mon avis tu peux lui mettre un bit setuid.



Effectivement, dans l'absolu tu as raison. Après, je pense justement
que les compétences me manquent pour faire quelque chose dont je puisse
garantir la sécurité. Déjà, je me serais orienté naturellement vers
un script shell mais le setuid est désactivé sur Debian pour les
scripts shell et pour le coup, j'ai cru comprendre que c'était vraiment
à éviter (dans le cas des scripts shell). Perso, je ne me sens pas trop
de coder un truc en C tant mon niveau est faible. :)

--
François Lafont
Avatar
Kevin Denis
Le 09-05-2014, Francois Lafont a écrit :
Ensuite, il suffit de récupérer ces informations via syslog.



Merci pour la réponse qui m'a fait découvrir l'option -L
du daemon cron. ;) Ceci étant dit, ça ne me conviendrait
pas trop car cela suppose d'aller chercher l'info dans
syslog. Or sur certains serveurs le syslog se remplit très
vite.



Tu peux peut-être mettre les logs de cron dans un fichier dédié?
comme /var/log/cron? Ou /usr/local/cron/logs

Sous debian, le démon rsyslog permet de filtrer à peu près comme on
veut les messages qui lui sont envoyés.

--
Kevin
1 2