Monitorizando el acceso a través de SSH o Webmin

Hace ya más de un año, he hablado de este tema y desarrollado un script que cumplía su cometido… Pero ya que hemos actualizado el Servidor a Debian 9, he aprovechado para actualizar el Script de monitoreo para que sea más funcional y más claro en sus avisos.

Parte de este código fue obtenido del Blog de Stephen C Phillips y gracias a su contribución, no he tenido que exprimir más mis sesos 😛
Entre las mejoras aplicadas, es la utilización de un script en bash. Este script lo utilizamos para crear un servicio donde podremos lanzar el script Python o en otro lenguaje como un Servicio en el inicio del equipo. Con este cambio, tendremos el control en el script para arrancarlo, pararlo o reiniciarlo.

  • seguridad_users.sh start
  • seguridad_users.sh stop
  • seguridad_users.sh restart
#!/bin/bash

DIR=/root
DAEMON=$DIR/seguridad_users.py
DAEMON_NAME=seguridad_users

# Add any command line options for your daemon here
DAEMON_OPTS=""

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=root

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
    log_end_msg $?
}
do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in

    start|stop)
        do_${1}
        ;;

    restart|reload|force-reload)
        do_stop
        do_start
        ;;

    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
        ;;

    *)
        echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
        exit 1
        ;;

esac
exit 0Copy
#!/usr/bin/env python

import logging
import logging.handlers
import argparse
import smtplib
import subprocess
import sys
import time 

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# CUANTA DE CORREO PARA ENVIAR EL AVISO --> User/Password para enviar correo electronicos
mail_destino = 'xxxxxx@xxxxxx.xxx'
mail_origen = 'xxxxxx@xxxxxx.xx'
username = 'xxxxxx'
password = 'xxxxxx'

def send_mail (sms_mail):	
	# Parametrizacion del mensaje
	msg = MIMEMultipart()
	msg['From'] = mail_origen
	msg['To'] = mail_destino
	msg['Subject'] = "Logueo en el Servidor --> valero-torres.es <--"
	msg.attach(MIMEText(sms_mail, 'plain'))
	 
	# Modulo smtplib  -- https://docs.python.org/3/library/smtplib.html
	try:
		smtpObj = smtplib.SMTP('xxxxxx.xx') # Servidor SMTP
		smtpObj.ehlo()
		smtpObj.starttls()
		smtpObj.ehlo()
		smtpObj.login(username,password)
		smtpObj.sendmail(mail_origen, mail_destino, msg.as_string())
		print 'Correo enviado con Exito.'	
		smtpObj.quit()
	except SMTPException:
		print 'Error: el mensaje no pudo enviarse.'		   
	return;

def writelastline (fname):
	f = open (fname, 'a')
	f.write('n------------------> WARNING | AVISANDO DE ESTA ULTIMA CONEXION <------------------')
	f.write('n								' + mail_origen )
	f.write('n------------------> WARNING | AVISANDO DE ESTA ULTIMA CONEXIONN <-----------------nn')
	f.close()


LOG_FILENAME = "/var/log/seguridad-users.log"
parser = argparse.ArgumentParser(description="Servicio de Control de Acceso")
parser.add_argument("-l", "--log", help="file to write log to (default '" + LOG_FILENAME + "')")
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO) # Could be e.g. "DEBUG" or "WARNING"
handler = logging.handlers.TimedRotatingFileHandler(LOG_FILENAME, when="midnight", backupCount=3) # 3 Copias del LOG
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

# Make a class we can use to capture stdout and sterr in the log
class MyLogger(object):
        def __init__(self, logger, level):
                """Needs a logger and a logger level."""
                self.logger = logger
                self.level = level

        def write(self, message):
                # Only log if there is a message (not just a new line)
                if message.rstrip() != "":
                        self.logger.log(self.level, message.rstrip())

sys.stdout = MyLogger(logger, logging.INFO)
sys.stderr = MyLogger(logger, logging.ERROR)


while True :	
	return_getlastline = subprocess.check_output('tail -6 /var/log/auth.log', shell=True)
	for line in return_getlastline.splitlines():
		if 'Successful login as' in line: # Webmin
			intruso = line.split("as ")
			datos_intruso = intruso[1].split("from ")
			txt_mail = 'Conexion establecida al Servidor a traves de Webmin...nn		Usuario = '+ datos_intruso[0] +'n		IP = '+ datos_intruso[1] +'nnUltimas 10 lineas del log /var/log/auth.logn------------------------------------------------------- n' + subprocess.check_output('tail -10 /var/log/auth.log', shell=True)
			send_mail(txt_mail)
			writelastline('/var/log/auth.log')

		if 'Accepted password for' in line: # SSH
			intruso = line.split("for ")
			datos_intruso = intruso[1].split("from ")
			txt_mail = 'Conexion establecida al Servidor a traves de SSH...nn		Usuario = '+ datos_intruso[0] +'n		IP = '+ datos_intruso[1] +'nnUltimas 10 lineas del log /var/log/auth.logn------------------------------------------------------- n' + subprocess.check_output('tail -10 /var/log/auth.log', shell=True)
			send_mail(txt_mail)
			writelastline('/var/log/auth.log')

		time.sleep(1)   # Esperar (1 segundos).
		
		
Copy

Como mejorar del Script Python y para mí la más importante, es el envío de un mensaje al destinatario más entendible en vez de enviar las últimas 10 líneas de /var/log/auth.log cuando detecta una conexión.

Mensaje SSH

ssh_monitoring

Mensaje WEBMIN

ssh_webmin-3251014