web-dev-qa-db-fra.com

Réécriture des journaux reçus via syslog d'une autre machine

J'ai la machine A, qui est une installation pfsense, qui envoie des journaux via syslog à une boîte Ubuntu. La boîte Ubuntu devra réécrire les journaux, pour remplacer par exemple les noms d'hôte et changer un peu le format.

Le format est généralement le suivant

Mar  7 00:05:32 hostname service: field1 field2 field3 field4 field5 field6 field7

Je voudrais la possibilité de réécrire le nom d'hôte, le service et changer l'ordre des champs, et filtrer les messages avec une certaine valeur dans un certain champ, car ils ne sont pas intéressants.

Après filtrage et traitement, les messages doivent être écrits sur le disque dans un fichier journal et envoyés à une autre machine via syslog.

Maintenant, la partie de journalisation est triviale - configurez simplement rsyslogd pour accepter les messages entrants et transférez-les. Cependant, je suis un peu coincé sur la partie de réécriture. Je ne suis pas marié à rsyslogd; n'importe quel démon syslog-esque fera l'affaire.

6
vidarlo

La question est un peu vague mais je vais essayer de proposer une solution possible. Pour réécrire les messages rsyslog fournit un certain nombre de modules dont l'un est mmfields . Il divise un message entrant à un certain caractère (juste un caractère) en champs et permet ensuite d'accéder à ces champs. Pour un message comme

a=1 b=two c=3 d=four

le séparateur serait vide et les champs sont alors accessibles comme $!f2, $!f3, $!f4, et $!f5. Malheureusement, le tout premier champ ($!f1) est toujours vide car le message est précédé d'un espace et ce serait le premier champ. Ainsi, pour le message ci-dessus, nous obtenons $!f1=="", $!f2=="a=1", $!f3=="b=two", $!f4=="c=3", et $!f5=="d=four".

rsyslog est livré avec d'autres modules de modification de message modules également mais en l'absence de détails supplémentaires j'ai choisi celui-ci. Stockez le fichier suivant en tant que /etc/rsyslog.d/10-so.conf. Modifiez le nom selon l'ordre d'exécution souhaité mais conservez le .conf extension.

# Load the "Message Modification" module "mmfields" to split
# incoming messages into fields at a certain separator:
module(load="mmfields")

# Format used for messages that are forwarded to another Host.
# The fields are re-ordered and field #3 is omitted.
template(name="rewrite_forward" type="list") {
    constant(value="<")
    property(name="pri")
    constant(value=">")
    property(name="timestamp" dateFormat="rfc3339")
    constant(value=" ")
    property(name="hostname")
    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")
    property(name="$!f4")
    constant(value=" ")
    property(name="$!f2")
    constant(value=" ")
    property(name="$!f5")
}

# Format used for messages that are written to a local logfile.
# The format is almost the same as above, but lacks the priority,
# uses a different timestamp format, and ends with a "\n" as this
# is suitable for messages printed to a logfile.
template(name="rewrite_file" type="list") {
    property(name="timestamp")
    constant(value=" ")
    property(name="hostname")
    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")
    property(name="$!f4")
    constant(value=" ")
    property(name="$!f2")
    constant(value=" ")
    property(name="$!f5")
    constant(value="\n")
}

if ( $programname == "so" ) then {

    # split message into fields at (exactly) one space character.
    # The "fields" can then be referred to as "$!f1", "$!f2", ..., "$!fN".
    # Note that "$!f1" will always be an empty string because the message
    # usually starts with a blank and that is considered to be the first
    # field. 
    action( type="mmfields" 
            separator=" " 
    )

    # If the second field is the string "b=2", then go ahead and log and
    # forward the message. Change the condition to your liking.
    if ($!f3 == "b=2") then {

        # write rewritten logmessage to local file
        action( type     = "omfile"
                file     = "/var/log/so-rewrite-fields.log"
                template = "rewrite_file"
        )

        # just for reference: write the unmodified message to the
        # very same logfile. Drop this for actual processing. It 
        # serves just as a debugging aid.
        action( type = "omfile"
                file = "/var/log/so-rewrite-fields.log"
        )

        # forward rewritten message to another Host
        action( type = "omfwd"  
                target   = "127.0.0.1"  # change to actual destination
                port     = "514"        # change to actual destination
                protocol = "udp"        # change to actual destination
                template = "rewrite_forward"
        )

    }

    # no further processing:
    stop
}

Redémarrez rsyslog (via Sudo systemctl restart rsyslog.service) et essayez-le:

# A message that won't be logged because `$!f3 != "b=2"`:
logger -t so --id=$$ "a=1 b=3 txt=Hello number=$RANDOM"

# A message that will be logged because `$!f3 == "b=2"`:
logger -t so --id=$$ "a=1 b=2 txt=Hello number=$RANDOM"

La sortie de la deuxième instruction logger sera:

Mar 14 21:40:34 stratum9 so[3533]: txt=Hello a=1 number=6484        # rewritten msg
Mar 14 21:40:34 stratum9 so[3533]: a=1 b=2 txt=Hello number=6484    # original msg

Pour changer le nom d'hôte, remplacez simplement

constant(value=" ")
property(name="hostname")
constant(value=" ")

dans les modèles avec

constant(value=" fromElsewhere ")

Pour modifier le syslogtag (ce que vous avez appelé service ), remplacez

    constant(value=" ")
    property(name="syslogtag")
    constant(value=" ")

avec

constant(value=" otherService: ")

La sortie sera alors:

Mar 14 22:05:51 fromElsewhere otherService: txt=Hello a=1 number=11763   # rewritten
Mar 14 22:05:51 stratum9 so[3533]: a=1 b=2 txt=Hello number=11763       # original

Voir ici pour d'autres propriétés de message.

Notez que mon approche (avec mmfields ) repose sur les champs pour toujours avoir le même ordre et ne permet pas facilement de réécrire des messages comme a=1 b=2 à b=1 a=2 (réorganiser et modifier les paires clé-valeur). Pour cela, un autre module pourrait être plus approprié.

6
PerlDuck

Autant que je sache, cela pourrait être réalisé en utilisant logstash elasticsearch et Kibana. J'essaie de faire de même et j'avais plus ou moins réussi en mettant en place une pile d'élans. Ensuite, utilisez des filtres grok dans logstash pour diviser le message syslog en différents champs et les utiliser pour faire correspondre un modèle et envoyer des alertes. Jetez un oeil à cela guide il pourrait vous donner des réponses sur où commencer.

Ce type de configuration a déjà intégré des filtres pour des choses comme les journaux mysql ou les journaux Apache ou nginx pour commencer. Voici bon aperç des fonctionnalités et de l'architecture de la pile elk. J'espère que ça aide.

1
ognjen