Sélectionner une page

Octopuce est un hébergeur de serveurs entièrement infogérés : nous gérons vos machine physiques (dans nos baies ou chez un autre hébergeur), le système d’exploitation (Debian), les mises à jour logicielles de celui-ci et des services (mariadb, nginx, php, python, elasticsearch etc.) la sécurisation et la supervision, y compris sous astreinte.

Cela passe aussi par une collaboration fine avec les développeurs de vos applications, sites web, progiciels métier divers. il faut souvent que les développeurs aient des accès SSH, voir un accès SSH root. De plus, nos administrateurs système ayant besoin de root pour 90% des commandes qu’ils saisissent, nous nous connectons directement en tant que root (compte « super administrateur ») avec nos clés SSH.

En cas d’audit, de panne ou de tout problème nécessitant un peu d’investigation du passé, nous avons souvent besoin de savoir quelles commandes ont été lancées sur les serveurs, par qui, dans quel répertoire etc. Pour cela nous avons donc mis en place un système d’historisation des commandes saisies sur les serveurs, que nous vous décrivons ci-dessous. Cela se passe en plusieurs étapes. C’est parti !

Étape 1 : savoir qui est connecté au serveur

Lorsqu’un utilisateur se conencte via SSH, il utilise une clé SSH (rsa4096, ed25519 ou ecdsa). Cette clé SSH est située dans le fichier ~/.ssh/authorized_keys Nous utilisons les possibilités offertes par ce système pour identifier l’utilisateur : en ajoutant des variables d’environnement qui lui sont spécifique, on peut ainsi préciser :

  • ses noms et prénom
  • son adresse email (pour un humain)
  • son éditeur favori (vim ? emacs ? nano ?)
  • qui il est pour d’autres logiciels comme GIT

Voici un exemple de ligne de authorized_keys sur un serveur d’Octopuce :

environment="SSHCLIENTUSER=Benjamin Sonntag",environment="SSHCLIENTLOGINNAME=benjamin",environment="EDITOR=/usr/bin/emacs",environment="GIT_AUTHOR_EMAIL=benjamin@octopuce.fr",environment="GIT_AUTHOR_NAME=Benjamin Sonntag" ssh-ed25519 AAK7sb5zUAAC3NzaC1lZDI1NTE5AAAAI8GljckgLTt0rHkkGc94tJleZnAIfdi11ctJV benjamin@mg

À partir de là, si j’utilise une commande comme crontab -e ou visudo, l’éditeur lancé sera le mien (emacs <3), et si je fais un git commit, il sera fait en mon nom ! pratique non ?

Attention : l’utilisation de variables d’environnement dans le authorized_keys n’est possible qu’à condition d’autoriser celles-ci dans /etc/ssh/sshd_config avec la directive

PermitUserEnvironment yes

Étape 2 : logguer localement les commandes saisies

Une fois l’environnement rempli, on souhaite stocker dans un fichier de log local les commandes saisies. Pour cela, nous avons mis tout en bas du /etc/bash.bashrc (qui est sourcé à chaque lancement de SSH pour tous les utilisateurs) le bout de code suivant :

function trap_to_syslog {
printf "%s %s from %s %s" "$HOSTNAME" "$SSHCLIENTUSER" "$SSH_CLIENT" "$USER[$$]@$PWD> $BASH_COMMAND" |logger -p local3.notice
}
trap trap_to_syslog DEBUG

Cette ligne logge donc dans local3.notice, qui, pour des raisons de sécurité évidente, doit absolument être stocké dans un fichier non accessible aux utilisateurs normaux, les informations suivantes :

  • sur quelle machine (en local cela a peut d’intérêt, mais vous verrez à l’étape 3 ;) ) a été lancée la commande
  • quelle personne (son prénom / nom, d’après la variable d’environnement de sa clé SSH)
  • depuis quelle adresse IP distante, si applicable (ssh_client est renseignée par SSHD)
  • connecté en tant que quel utilisateur Unix (USER est renseigné par login ou sshd)
  • avec quel PID de shell ($$, utile car nous loggons aussi les processus lancés sur le système…)
  • dans quel dossier (PWD est le dossier courant)
  • a lancé quelle commande (BASH_COMMAND)

Cela fait de belles lignes du genre :

May 30 17:26:48 alice root: alice Benjamin Sonntag from 2001:67c:288:dead:beef::22f 53940 22 root[18777]@/root> tail -f /var/log/auth.log

Ensuite, il faut demander à rsyslog de logguer cela dans un fichier sûr. On a choisi /var/log/auth.log pour cela, qui journalise les événements d’authentification.

Cependant, cela ne suffit pas : si un utilisateur est root, il peut tout à fait supprimer le fichier /var/log/auth.log et donc faire disparaitre les traces de son passage… de plus, en cas de panne franche (très rare), ou malversation violente (très très rare) la machine peut être inaccessible temporairement ou définitivement. Aussi, il faut journaliser ces commandes à distances. Mais pas question de faire cela en clair !! D’où …

Étape 3 : journalisation à distance en utilisant TLS

Une fois les commandes envoyées à rsyslog dans /dev/log, on peut demander à ce dernier d’envoyer ces lignes à distances en utilisant syslog over tcp + tls, à l’aide de la configuration suivante :

# cette partie sert à journaliser localement :
auth,authpriv,local3.* /var/log/auth.log
# On utilise la CA de Puppet générale à toutes les machines Octopuce
$DefaultNetstreamDriverCAFile /var/lib/puppet/ssl/certs/ca.pem
$DefaultNetstreamDriverCertFile /var/lib/puppet/ssl/certs/alice.octopuce.fr.pem
$DefaultNetstreamDriverKeyFile /var/lib/puppet/ssl/private_keys/alice.octopuce.fr.pem
$DefaultNetstreamDriver gtls # use gtls netstream driver
$ActionSendStreamDriverMode 1 # require TLS for the connection
$ActionSendStreamDriverAuthMode x509/certvalid
local3.notice @@(z9)remote.octopuce.fr:514 # send bash messages

Remarquez une idée intéressante : pour envoyer des messages via SSL/TLS, il faut généralement que le serveur dispose d’un certificat serveur, sinon rien ne prouve qu’il est qui il prétend. Cependant, dans notre cas, on souhaitait aussi protéger le serveur recevant les messages de tout envoi non sollicité. Il faut donc aussi identifier le client TLS à l’aide d’un certificat client. Octopuce disposant, dans le cadre de son administration système centralisée, d’une CA (autorité de certification gérant la signature de clés privées pour TLS) utilisée par Puppet qui distribue donc un certificat et une clé privée sur chaque machine, nous pouvons identifier à la fois le client et le serveur grâce à cela.

Enfin, sur le serveur « remote », nous avons installé le même genre de configuration rsyslog comme suit :

# provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
$InputTCPMaxSessions 10000 # Maximum TCP sessions (default 200)
$MaxOpenFiles 10000 # Maximum open files
# certificate files - use PUPPET cert !
$DefaultNetstreamDriverCAFile /var/lib/puppet/ssl/certs/ca.pem # CA cert
$DefaultNetstreamDriverCertFile /var/lib/puppet/ssl/certs/ubal.octopuce.fr.pem # User public key
$DefaultNetstreamDriverKeyFile /var/lib/puppet/ssl/private_keys/ubal.octopuce.fr.pem # User private key
# set up the receiver
$DefaultNetstreamDriver gtls # use gtls netstream driver
$InputTCPServerStreamDriverAuthMode x509/certvalid
$InputTCPServerStreamDriverMode 1 # run driver in TLS-only mode

local3.notice /var/log/octopuce.logging.log

et donc dans le fichier /var/log/octopuce.logging.log de cette machine, on retrouve :

May 30 17:26:48 alice root: alice Benjamin Sonntag from 2001:67c:288:2::226 53940 22 root[18777]@/root> tail -f /var/log/auth.log

Étape א : comment y échapper ?

Bien entendu, ce système de log systématique des commande n’est pas infaillible, il y a plusieurs façon de lancer des commandes sans qu’elles soient logguées, et la plus simple est tout simplement de faire

trap DEBUG

qui désactive l’envoi des commandes de bash au rsyslog local. Il y a un véritable usage à cette commande : quand on doit par exemple lancer une commande en boucle dans un screen juste pour quelques heures, cela peut remplir les logs de cette commande, sans intérêt. Cependant, le TRAP lui-même est loggué dans octopuce.logging.log, et une alerte spécifique peut prévenir les administrateur système de manière active (par exemple via un message sur notre mattermost) que quelqu’un a utilisé cette commande d’échappement.

Il y a d’autres façon d’y échapper, mais cela sort de l’objet de cet article, et ces autres façons sont gérées par le fait que nous journalisons tout process lancé sur la machine ;)

Tout cela pour dire que cette solution nous permet de partager un shell entre nos clients, notre équipe d’administrateurs systèmes et leurs agence web, ou leur développeurs, en toute confiance. Et comme dirait un célèbre moine zen sysadmin

« la confiance n’exclut pas le contrôle »