Enregistrement local horodaté de toutes les commands ssh?

Comment puis-je conserver un logging horodaté local de toutes les commands distantes que j'utilise dans ssh (client openssh en command line lancé par bash )?

Exigences:

Mon niveau de compétence:

  • Je ne suis pas nouveau dans la programmation, mais j'apprends toujours le bash et la "manière Linux", donc les exemples de code avec de brèves explications seraient très appréciés.

Stratégies possibles

  • keylogger – Problème: enregistre les passwords, ne se connecte pas à l'onglet / à l'historique (voir la réponse de glenn )
  • screen avec scrollback dumping une fois par seconde et diff entre eux pour find de nouvelles lignes de défilement – Problème: comment cela peut-il être mis en œuvre de manière automatisée et utile?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile) ssh "$@" | tee >(some_cleaner_function >> $logfile) – Problème: impossible de gérer les commands multilignes ou l'historique des sessions chaînées, nettoyage soigné nécessaire (voir ma réponse)
  • Une combinaison de certains de ces éléments

Un exemple

La session SSH suivante:

 user@local:~$ ssh user@remote Last login: Tue Jun 17 16:34:23 2014 from local user@remote:~$ cd test user@remote:~/test$ ls ab user@remote:~/test$ exit 

Peut résulter en un journal à ~/logs/ssh.log comme:

 2014-06-17 16:34:50 [user@remote - start] 2014-06-17 16:34:51 [user@remote] cd test 2014-06-17 16:34:52 [user@remote] ls 2014-06-17 16:34:53 [user@remote] exit 2014-06-17 16:34:53 [user@remote - end] 

Ou, peut-être un journal distinct sera créé pour chaque session avec la command line utilisée pour démarrer la session en haut du file.

J'ai été insortinggué par votre question. Je ne voulais pas donner de réponse à l'origine mais je me suis accroché.

Cela utilise expect et c'est vraiment un enregistreur key.

 #!/usr/bin/expect -f proc log {msg} { puts $::fh "[timestamp -format {%Y-%m-%d %H:%M:%S}]: $msg" } set ssh_host [lindex $argv 0] set ::fh [open "sshlog.$ssh_host" a] log "{session starts}" spawn ssh $ssh_host interact { -re "(.)" { set char $interact_out(1,ssortingng) if {$char eq "\r"} { log $keystrokes set keystrokes "" } else { append keystrokes $char } send -- $char } eof } log "{session ends}" 

Remarques:

  • il ajoute à un file avec la destination ssh dans le nom
  • c'est un enregistreur de keys: si vous n'avez pas configuré de keys ssh, vous obtenez le mot de passe de l'user dans le file journal
  • il est déjoué par la complétion de l'onglet: si l'user tape u p t Tab (pour la command uptime ), vous obtiendrez "upt \ t" dans le file journal, pas "uptime"
  • il attrape les caractères en mode "raw": si l'user est une mauvaise dactylo, vous aurez beaucoup de ^? (caractères de return arrière) dans le file journal.

J'utilise actuellement le script bash ci-dessous. Il y a beaucoup de problèmes, mais c'est la seule solution que j'ai trouvée qui réponde à toutes les exigences, à toutes les priorités et à tous les aspects de la vie (au less la plupart du time).

Cette réponse explique pourquoi la journalisation des sessions ssh localement est si difficile.

Problèmes avec le script que j'ai trouvé jusqu'à présent:

  1. Les commands multilignes provoquent des problèmes:

    • Si vous parcourez un élément multiligne dans l'historique distant (avec les touches haut / bas), il savea un élément d'historique à la place de la dernière command. Vous pouvez éviter cela en supprimant de l'historique bash les commands multilignes immédiatement après leur utilisation.
    • Seule la première command lines multilignes est enregistrée.
  2. Les sessions chaînées (en utilisant les commands ssh ou su sur l'extrémité distante) provoquent le défilement de l'historique pour save les commands défilées au lieu des commands réelles utilisées

  3. Les expressions régulières peuvent être améliorées et peuvent devoir être modifiées pour certains environnements:

    • Je sortingche en convertissant les caractères non imprimables avec cat -v avant le nettoyage. Par conséquent, le contenu valide peut être supprimé si vous utilisez des strings comme ^[[ dans vos commands.
    • Parfois, vous obtenez une input supplémentaire avant la command, par exemple si vous parcourez l'historique très rapidement. Ceci est généralement suivi d'un "^ M" avant la command réelle et pourrait donc être enlevé si désiré.
    • D'autres caractères de contrôle se produisent parfois. Je les laisse tous pour le moment jusqu'à ce que je sache qui sont sûrs d'enlever. ^ M comme je viens de le mentionner est utile pour détecter les inputs non valides, et ^ C vous dira si la command a été abandonnée.
    • L'expression rationnelle rapide peut devoir être modifiée pour des invites particulières, et je pourrais imaginer que différents environnements distants peuvent avoir différents templates de caractères de contrôle.
  4. Pas d'achèvement de la command ssh bash, comme pour le nom d'hôte. Vous pouvez get la complétion bash si vous aliasez ce script avec ssh avec alias ssh="sshlog"

Source du script et installation:

Pour l'installer, collez ce qui suit dans ~ / bin / sshlog et faites un exécutable. Appelez avec les sshlog <ssh command options> . Optionellement alias à 'ssh' dans le file .bashrc de l'user.

 #!/bin/bash # A wrapper for the ssh command that produces a timestamped log of all ssh commands declare -r logfile=~/logs/ssh.log declare -r description="sshlog-${$} ${@}" declare -r TAB=$'\t' logdir=`dirname ${logfile}` [ -d ${logdir} ] || mkdir "${logdir}"; clean_control_chars() { while IFS= read -r line; do # remove KNOWN control characters. Leave the rest for now. # line=$(echo "${line}" | sed 's/\^\[\[K//g') # unkown control character: ^[[K # line=$(echo "${line}" | sed 's/\^\[\[[0-9]\+[P]//g') # these are generated by up/down completion - eg ^[[2P line=$(echo "${line}" | sed 's/\^\[\[[0-9]*[AZ]//g') # all other ^[[.. # replay character deletions (backspaces) while [[ $(echo "${line}" | grep -E --color=never '.\^H') != "" ]]; do line=$(echo "${line}" | sed 's/.\^H//') done # remove common control characters line=$(echo "${line}" | sed 's/\^M$//') # remove end of line marker from end line=$(echo "${line}" | sed 's/^\^G//g') # remove start marker from start # remove ^G from other locations - possibly a good idea # line=$(echo "${line}" | sed 's/\^G//g') # remove all other control characters - not recommended (many like ^C and ^M indicate which section was processed/ ignored) # line=$(echo "${line}" | sed 's/\^[AZ]//g') echo ${line}; done } filter_output() { while IFS= read -r line; do # convert nonprinting characters and filter out non-prompt (in Ubuntu 14.04 tests, ^G indicates prompt start) line=$(echo "${line}" | cat -v | grep -Eo '[\^][G].*[\$#].*') [[ ${line} != "" ]] && echo "${line}" done } format_line() { while IFS= read -r line; do raw=${line}; line=$(echo "${line}" | clean_control_chars); prompt=$(echo "${line}" | grep -Po '^.*?(\$|#)[\s]*') command=${line:${#prompt}} timestamp=`date +"%Y-%m-%d %H:%M:%S %z"` echo -e "${timestamp}${TAB}${description}${TAB}${prompt}${TAB}${command}" done } echo "Logging ssh session: ${description}" echo "[START]" | format_line >> ${logfile} /usr/bin/ssh "$@" | tee >(filter_output | format_line >> ${logfile}) echo "[END]" | format_line >> ${logfile} 

Exemple de contenu de journal:

 2014-06-29 23:04:06 -0700 sshlog-24176 remote [START] 2014-06-29 23:04:12 -0700 sshlog-24176 remote oleg@remote:~$ cd test 2014-06-29 23:04:13 -0700 sshlog-24176 remote oleg@remote:~/test$ ls 2014-06-29 23:04:14 -0700 sshlog-24176 remote oleg@remote:~/test$ exit 2014-06-29 23:04:14 -0700 sshlog-24176 remote [END] 

Que diriez-vous de strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd) ? Ceci journalise toutes les sessions ssh. Vous pouvez avoir besoin d'un outil pour parsingr le journal ultérieurement, ou simplement utiliser grep , awk etc.

  • -f : trace des enfants fourchus
  • -ff : consigne chaque enfant séparément dans ssh_log.PID
  • -s8192 : augmente la limite de consignation des strings (si nécessaire)
  • -T -ttt : microseconde en quelques secondes depuis l'époque
  • -p N : joindre à pid N

J'ai une réponse less compliquée, et sûrement pas un keylogger. Je n'obtiens pas votre point d'être indépendant du journal du server (cela signifie que toutes les actions doivent être sockets sur le server et tous les journaux sont des journaux côté server), et j'ai donc pensé qu'une bonne idée est de passer à bashrc une command rapide comme:

 PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -t "$USER[$$] $SSH_CONNECTION")' 

Dans debian, vous devez éditer le file: /etc/bash.bashrc et en centos le file: / etc / bashrc

Si vous souhaitez démarrer la journalisation de la session, vous devez générer le file que vous avez édité, par exemple:

 source /etc/bash.bashrc 

dans un système debian ou

 source /etc/bashrc 

dans un système centos.

A partir de maintenant, chaque command de chaque session ssh sera enregistrée dans / var / log / syslog sur un système debian, et dans / var / log / messages sur un système centos.

Si vous voulez les save sur un file séparé et ne pas gâcher avec d'autres files journaux, vous pouvez utiliser:

 PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")' 

à la place de l'exemple précédent de PROMPT_COMMAND, puis configurez le rsyslogd selon les besoins.

Par exemple, sur un système Debian, éditez le file /etc/rsyslog.conf : changez la ligne:

 . ;auth,authpriv.none -/var/log/syslog 

à

 . ;auth,authpriv.none,local6 -/var/log/syslog 

et ajoutez la ligne suivante à la fin du file:

 local6.info /var/log/history.log 

puis exécutez:

 touch /var/log/history.log && /etc/init.d/rsyslog restart