FreeBSD audit source for syslog-ng

Two weeks ago, I was at EuroBSDcon and received a feature request for syslog-ng. The user wanted to collect FreeBSD audit logs together with other logs using syslog-ng. Writing a native driver in C is time consuming. However, creating an integration based on the program() source of syslog-ng is not that difficult.

This blog shows you the current state of the FreeBSD audit source, how it works, and its limitations. It is also a request for feedback. Please share your experiences at https://github.com/syslog-ng/syslog-ng/discussions/5150!

Before you begin

First, you must enable audit logging on your FreeBSD box. If you do not want to enable it permanently, enable it only for the testing:

service auditd onestart

The syslog-ng package does not have XML parsing enabled by default. The sample configuration I show in the blog uses XML parsing. You should compile the sysutils/syslog-ng port with XML parsing enabled. If you do not enable XML parsing, you can still forward XML logs without parsing, or change the praudit command line to switch to plain text output.

Configuring syslog-ng

The actual “driver” is very simple, just a few lines. Once it is ready, it will be added to the syslog-ng configuration library (SCL), and you do not have to copy it into your configuration. For now, append it to syslog-ng.conf, or create a new configuration file, if you implemented using an include directory in your configuration.

@define def-praudit-params " -p -l -x"

block source freebsd-audit(params("`def-praudit-params`")) {
  program(
    "tail -F /var/audit/current | praudit `params`"
    flags(no-parse)
  );
};

It is a configuration block, typically used in the SCL. It uses the tail command to follow the FreeBSD audit log (with -F to detect file rotations), and praudit is configured to keep running, and print single lines in XML format.

And here comes the rest of the configuration, utilizing the new source in multiple setups. Once the above configuration block is part of SCL, you only need to include this part in your configuration.

source s_fbaudit_xml {
  freebsd-audit();
};

parser p_xml {
  xml(prefix("fbaudit."));
};
destination d_fbaudit_json {
  file("/var/log/fbaudit.json" template("$(format-flat-json
  --leave-initial-dot --scope rfc5424 --scope dot-nv-pairs
        --scope nv-pairs)\n\n"));
};
log {
  source(s_fbaudit_xml);
  parser(p_xml);
  destination(d_fbaudit_json);
};

source s_fbaudit {
  freebsd-audit(params("-p -l"));
};

destination d_fbaudit {
  file("/var/log/fbaudit");
};
log {
  source(s_fbaudit);
  destination(d_fbaudit);
};

This configuration contains two test setups. The first one calls the freebsd-audit() source without any additional parameters, thus having an XML formatted output. It parses the incoming message using the XML parser, and saves it to a JSON formatted file, so you can see the name-value pairs parsed from the XML.

The second one sets the output to single line plain text format and writes it as a regular syslog message.

Note, that in both cases we use the no-parse flag, so the original message is stored in the $MESSAGE macro of syslog-ng, and syslog-ng creates a syslog-ng message header.

Bugs and limitations

While testing the freebsd-audit() source, I ran into a few bugs and limitations.

  • If a field has a space in it, syslog-ng adds double quotation marks.

  • The XML parser adds a leading underscore to tag names, which cannot be changed / removed.

  • As we read the logs using the tail command, there might be some missing or duplicate audit logs when syslog-ng is restarted (depending on the rate of audit logs and the downtime of syslog-ng).

  • The XML parser throws an error message while reading the beginning of the XML formatted audit log, as it cannot properly parse the header lines.

Testing

Add the above lines to your syslog-ng configuration (disable the XML parser, if you do not have it compiled into syslog-ng), and restart syslog-ng. The easiest way to generate some audit log messages is to login on the FreeBSD console, or using ssh. Once you generated some audit logs, you should see two new log files under the /var/log/ directory.

root@fb14:/usr/local/etc # tail -3 /var/log/fbaudit
Sep 27 15:02:37 fb14 header,97,11,OpenSSH login,0,Fri Sep 27 12:34:25 2024, + 830 msec,subject_ex,root,root,wheel,root,wheel,1321,1321,57418,172.16.167.1,text,successful login root,return,success,0,trailer,97,
Sep 27 15:02:37 fb14 header,97,11,OpenSSH login,0,Fri Sep 27 12:56:15 2024, + 188 msec,subject_ex,root,root,wheel,root,wheel,1404,1404,48770,172.16.167.1,text,successful login root,return,success,0,trailer,97,
Sep 27 15:07:45 fb14 header,97,11,OpenSSH login,0,Fri Sep 27 13:07:45 2024, + 379 msec,subject_ex,root,root,wheel,root,wheel,1522,1522,42126,172.16.167.1,text,successful login root,return,success,0,trailer,97,

root@fb14:/usr/local/etc # tail -6 /var/log/fbaudit.json
{"fbaudit.record.text":"\"successful login root\"","fbaudit.record.subject._uidit-uid":"root","fbaudit.record.subject._tiddt-uid":"57418172.16.167.1","fbaudit.record.subject._siddt-uid":"1321","fbaudit.record.subject._ruidt-uid":"root","fbaudit.record.subject._rgidt-uid":"wheel","fbaudit.record.subject._piddt-uid":"1321","fbaudit.record.subject._gidit-uid":"wheel","fbaudit.record.subject._audit-uid":"root","fbaudit.record.return._retval":"0","fbaudit.record.return._errval":"success","fbaudit.record._version":"11","fbaudit.record._timefier":"\"Fri Sep 27 12:34:25 2024\"","fbaudit.record._msecfier":"\" + 830 msec\"","fbaudit.record._modifier":"0","fbaudit.record._eventon":"\"OpenSSH login\"","TRANSPORT":"local+program","SOURCE":"s_fbaudit_xml","PRIORITY":"notice","MSGFORMAT":"raw","MESSAGE":"<record version=\"11\" event=\"OpenSSH login\" modifier=\"0\" time=\"Fri Sep 27 12:34:25 2024\" msec=\" + 830 msec\" ><subject audit-uid=\"root\" uid=\"root\" gid=\"wheel\" ruid=\"root\" rgid=\"wheel\" pid=\"1321\" sid=\"1321\" tid=\"57418172.16.167.1\" /><text>successful login root</text><return errval=\"success\" retval=\"0\" /></record>","HOST_FROM":"fb14","HOST":"fb14","FACILITY":"user","DATE":"Sep 27 15:02:37"}

{"fbaudit.record.text":"\"successful login root\"","fbaudit.record.subject._uidit-uid":"root","fbaudit.record.subject._tiddt-uid":"48770172.16.167.1","fbaudit.record.subject._siddt-uid":"1404","fbaudit.record.subject._ruidt-uid":"root","fbaudit.record.subject._rgidt-uid":"wheel","fbaudit.record.subject._piddt-uid":"1404","fbaudit.record.subject._gidit-uid":"wheel","fbaudit.record.subject._audit-uid":"root","fbaudit.record.return._retval":"0","fbaudit.record.return._errval":"success","fbaudit.record._version":"11","fbaudit.record._timefier":"\"Fri Sep 27 12:56:15 2024\"","fbaudit.record._msecfier":"\" + 188 msec\"","fbaudit.record._modifier":"0","fbaudit.record._eventon":"\"OpenSSH login\"","TRANSPORT":"local+program","SOURCE":"s_fbaudit_xml","PRIORITY":"notice","MSGFORMAT":"raw","MESSAGE":"<record version=\"11\" event=\"OpenSSH login\" modifier=\"0\" time=\"Fri Sep 27 12:56:15 2024\" msec=\" + 188 msec\" ><subject audit-uid=\"root\" uid=\"root\" gid=\"wheel\" ruid=\"root\" rgid=\"wheel\" pid=\"1404\" sid=\"1404\" tid=\"48770172.16.167.1\" /><text>successful login root</text><return errval=\"success\" retval=\"0\" /></record>","HOST_FROM":"fb14","HOST":"fb14","FACILITY":"user","DATE":"Sep 27 15:02:37"}

{"fbaudit.record.text":"\"successful login root\"","fbaudit.record.subject._uidit-uid":"root","fbaudit.record.subject._tiddt-uid":"42126172.16.167.1","fbaudit.record.subject._siddt-uid":"1522","fbaudit.record.subject._ruidt-uid":"root","fbaudit.record.subject._rgidt-uid":"wheel","fbaudit.record.subject._piddt-uid":"1522","fbaudit.record.subject._gidit-uid":"wheel","fbaudit.record.subject._audit-uid":"root","fbaudit.record.return._retval":"0","fbaudit.record.return._errval":"success","fbaudit.record._version":"11","fbaudit.record._timefier":"\"Fri Sep 27 13:07:45 2024\"","fbaudit.record._msecfier":"\" + 379 msec\"","fbaudit.record._modifier":"0","fbaudit.record._eventon":"\"OpenSSH login\"","TRANSPORT":"local+program","SOURCE":"s_fbaudit_xml","PRIORITY":"notice","MSGFORMAT":"raw","MESSAGE":"<record version=\"11\" event=\"OpenSSH login\" modifier=\"0\" time=\"Fri Sep 27 13:07:45 2024\" msec=\" + 379 msec\" ><subject audit-uid=\"root\" uid=\"root\" gid=\"wheel\" ruid=\"root\" rgid=\"wheel\" pid=\"1522\" sid=\"1522\" tid=\"42126172.16.167.1\" /><text>successful login root</text><return errval=\"success\" retval=\"0\" /></record>","HOST_FROM":"fb14","HOST":"fb14","FACILITY":"user","DATE":"Sep 27 15:07:45"}

What is next?

The above configuration collects FreeBSD audit logs to some local files. In most cases you want to collect log messages centrally.

Also, do not forget to provide us with feedback at https://github.com/syslog-ng/syslog-ng/discussions/5150. We are happy to hear problem reports, as it also means that you are actually testing what we are working on. It helps us to make syslog-ng even better. And of course we are also very happy to hear success stories!

-

If you have questions or comments related to syslog-ng, do not hesitate to contact us. You can reach us by email or even chat with us. For a list of possibilities, check our GitHub page under the “Community” section at https://github.com/syslog-ng/syslog-ng. On Twitter, I am available as @PCzanik, on Mastodon as @Pczanik@fosstodon.org.

Related Content