Journalisation locale et horodatée de toutes les commandes ssh?

12

Comment puis-je conserver un enregistrement local horodaté de toutes les commandes distantes que j'utilise dans ssh(client openssh en ligne de commande démarré bash)?

Exigences:

  • Essentiel:

    • 100% côté client sans dépendre de la journalisation du serveur
    • Configuré ou installé par utilisateur avec des journaux stockés dans le répertoire personnel de l'utilisateur.
    • Prise en charge de la distinction entre plusieurs sessions simultanées avec différents utilisateurs et hôtes.
    • Non intrusif (pas besoin de l'activer à chaque fois et n'interfère pas de manière significative avec l'utilisation de ssh)
  • Haute priorité:

    • La sortie n'est pas enregistrée ou filtrée autant que possible
    • Soit les entrées de mot de passe ne sont pas enregistrées, soit le fichier est crypté
    • Indique les commandes réelles utilisées (après la fin de l'onglet / historique, les espaces arrière, CTRL+ C, etc ... ont été traités)
  • Bon d'avoir:

    • Enregistre également les commandes dans les sessions chaînées (commandes entrées lors de sessions sshou à distance su <user>)
    • Le début et la fin de la session doivent être enregistrés
    • Une bashsolution simple et non root serait la meilleure (peut-être un script aliasou un bashwrapper pour la sshcommande?)

Mon niveau de compétence:

  • Je ne suis pas nouveau dans la programmation, mais j'apprends toujours bashet la "façon Linux", donc des exemples de code avec de brèves explications seraient les plus appréciés.

Stratégies possibles

  • Enregistreur de frappe - Problème: enregistre les mots de passe, n'enregistre pas la fin de l'onglet / historique (voir la réponse de Glenn )
  • screenavec défilement défilant une fois par seconde et diffentre elles pour trouver de nouvelles lignes de défilement - Problème: comment cela peut-il être implémenté de manière automatisée et utile?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile) - Problème: ne peut pas gérer les commandes multilignes ou l'historique dans les sessions chaînées, un nettoyage soigneux est nécessaire (voir ma réponse)
  • Une combinaison de certains des éléments ci-dessus

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
a  b
user@remote:~/test$ exit

Peut entraîner un journal ~/logs/ssh.logtel que:

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 ligne de commande utilisée pour démarrer la session en haut du fichier.

Oleg
la source
Il devrait également gérer des éditeurs comme nano ou vim
daisy

Réponses:

4

J'ai été intrigué par votre question. Au départ, je n'allais pas donner de réponse, mais je suis devenu accro.

Cela utilise expectet c'est vraiment un enregistreur de frappe.

#!/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,string)
        if {$char eq "\r"} {
            log $keystrokes
            set keystrokes ""
        } else {
            append keystrokes $char
        }
        send -- $char
    }
    eof
}

log "{session ends}"

Remarques:

  • il ajoute à un fichier avec la destination ssh dans le nom
  • c'est un enregistreur de frappe: si vous n'avez pas configuré de clé ssh, vous obtenez le mot de passe de l'utilisateur dans le fichier journal
  • il est déjoué par la complétion des tabulations: si l'utilisateur tape uptTab(pour la uptimecommande), vous obtiendrez "upt \ t" dans le fichier journal, pas "uptime"
  • il saisit les caractères en mode "brut": si l'utilisateur est un mauvais dactylographe, vous obtiendrez beaucoup de ^?(caractères de retour arrière) dans le fichier journal.
glenn jackman
la source
Merci beaucoup pour votre réponse. Il est intéressant de noter qu'il ne semble pas y avoir de réponse simple à cela, peut-être native du client ssh. Merci d'avoir expliqué les limites; Je pense que la complétion des onglets / la journalisation des caractères de retour arrière / la journalisation des mots de passe sont suffisantes pour m'empêcher de l'utiliser souvent. Cela m'a également fait réfléchir davantage sur mes priorités, et je vais clarifier celles de la question.
Oleg
La sortie du processus généré peut être analysée pour extraire la commande souhaitée. Vous auriez besoin de connaître l'invite de l'utilisateur pour le rendre plus facile.
glenn jackman
J'utilise beaucoup la complétion d'onglets. Cela ne signifie-t-il pas que ces commandes ne seront pas enregistrées?
Oleg
Ah, je vois ce que tu dis. Comment la sortie serait-elle analysée? L'invite peut être entrée quelque part comme option de configuration.
Oleg
J'ai ajouté la liste des solutions possibles au bas de la question. ssh ... | tee -ai <logfile> fonctionne bien pour enregistrer les entrées et les sorties en toute sécurité, mais je ne sais pas comment ajouter des horodatages et / ou filtrer la sortie en arrière-plan.
Oleg
2

J'utilise actuellement le script bash ci-dessous. Il a de nombreux problèmes, mais c'est la seule solution que j'ai trouvée qui réponde à toutes les exigences, priorités et "nice to haves" (au moins la plupart du temps).

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

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

  1. Les commandes multilignes provoquent des problèmes:

    • Si vous parcourez un élément multiligne dans l'historique distant (avec les touches haut / bas), il enregistrera un élément d'historique au lieu de la dernière commande. Vous pouvez éviter cela en supprimant de l'historique bash toutes les commandes multilignes immédiatement après leur utilisation.
    • Seule la première ligne de commandes multilignes est enregistrée.
  2. Les sessions chaînées (en utilisant sshou les sucommandes sur l'extrémité distante) provoquent un défilement de l'historique pour enregistrer les commandes passées par défilement au lieu des commandes 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 triche en convertissant les caractères non imprimables avec cat -vavant le nettoyage. Par conséquent, le contenu valide peut être supprimé si vous utilisez des chaînes comme ^[[dans vos commandes.
    • Parfois, vous obtenez une entrée supplémentaire enregistrée avant la commande, comme si vous parcourez l'historique très rapidement. Ceci est généralement suivi d'un "^ M" avant la commande réelle et peut donc être supprimé si vous le souhaitez.
    • D'autres caractères de contrôle apparaissent parfois. Je les laisse tous pour l'instant jusqu'à ce que je sache lesquels sont sûrs à retirer. ^ M comme je viens de le mentionner est utile pour détecter une entrée consignée invalide, et ^ C vous dirait si la commande a été abandonnée.
    • Le regex d'invite peut devoir être modifié pour des invites particulières, et je pourrais imaginer que différents environnements distants peuvent avoir différents modèles de caractères de contrôle.
  4. Pas de complétion de la commande ssh, comme pour le nom d'hôte. Vous pouvez obtenir l'achèvement de bash si vous alias ce script sshavecalias ssh="sshlog"

Source de script et installation:

Pour installer, collez ce qui suit dans ~ / bin / sshlog et rendez exécutable. Appelez avec sshlog <ssh command options>. Éventuellement alias vers 'ssh' dans le fichier .bashrc de l'utilisateur.

#!/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 - e.g. ^[[2P
        line=$(echo "${line}" | sed 's/\^\[\[[0-9]*[A-Z]//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/\^[A-Z]//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 du 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]
Oleg
la source
0

J'ai une réponse moins compliquée et sûrement pas un enregistreur de frappe. Je ne comprends pas pourquoi vous êtes indépendant du journal du serveur (cela signifie que toutes les actions doivent être effectuées sur le serveur et que tous les journaux sont des journaux côté serveur), et j'ai donc pensé qu'une bonne idée était de passer à bashrc à l'échelle du système une commande rapide comme:


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

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

Si vous souhaitez démarrer la journalisation de la session dans laquelle vous vous trouvez, vous devez rechercher le fichier que vous avez modifié, par exemple exécuter:


source /etc/bash.bashrc

dans un système Debian ou


source /etc/bashrc
dans un système centos.

Désormais, chaque commande, 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.

Dans le cas où vous souhaitez les enregistrer dans un fichier séparé et ne pas gâcher d'autres fichiers journaux, vous pouvez utiliser:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
au lieu de l'exemple précédent PROMPT_COMMAND, puis configurez rsyslogd selon vos besoins.

Par exemple, sur un système Debian, éditez le fichier /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 fichier:

local6.info                     /var/log/history.log

puis exécutez:

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

strimpak
la source
Cette question concerne spécifiquement le problème de la journalisation des sessions ssh du côté de l'ordinateur initiateur / local / client, sans avoir à (se souvenir / être autorisé) à configurer chaque serveur distant ou à télécharger manuellement les journaux de tous les serveurs distants que vous connectez à. Je pense que votre réponse, bien qu'elle ne réponde pas à cette question, serait utile à quelqu'un intéressé à améliorer l'audit de son serveur et devrait peut-être être déplacée vers une question plus pertinente.
Oleg
0

Et alors strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)? Cela enregistre toutes les sessions ssh. Vous pouvez avoir besoin d'un outil pour analyser le journal ultérieurement, ou simplement utiliser grep, awketc.

  • -f: retracer des enfants fourchus
  • -ff: connectez chaque enfant séparément à ssh_log.PID
  • -s8192: augmenter la limite de journalisation des chaînes (si nécessaire)
  • -T -ttt: estampillage microseconde en quelques secondes depuis l'époque
  • -p N: attacher au pid N
Anul
la source