Send Security Onion logs to a centralized Graylog Server


For anyone that doesn’t know, Security Onion is a custom Linux distribution running on Ubuntu that can be used as a Network Intrusion Detection System (NIDS). Security Onion integrates several configurable apps like BRO IDS, Snort, Suricata, and OSSEC to name a few. By default, there is an integrated ELSA Stack that can be configured, which makes SO a pretty interesting one stop shop for getting your feet wet with IDS technology. You can find more information about Security Onion at


This post isn’t about getting started with Security Onion though, it is about configuring logging to a remote syslog receiver from a Security Onion sensor. Again, if you aren’t familiar with Graylog, you can refer back to my posts about configuring a multi-tiered logging stack, where I go into detail about configuring rsyslog collectors, Elasticsearch, and Graylog itself.  Once Security Onion sensors are deployed, you will have a need to view the collected information. ELSA provides a good way to do that if you do not already have a remote syslog server setup. However, I wanted to send BRO and Suricata logs to Graylog.

In many cases, the sensor(s) can send logs directly to Graylog or another alternative log destination. Within my setup, I forward logs to an rsyslog host that acts as a primary log storage location and forwards data to Graylog. Configuration changes need to happen on the sensor(s), within Graylog, and on any intermediary syslog receiver/forwarder along the way. Security Onion utilizes Syslog-NG as the local logging client and can be easily configured to send log data to remote destinations. Graylog has to be configured to accept data on an incoming stream.

Configure Graylog Input

I won’t go into a lot of detail here since the Graylog docs cover creating an input. Of course, you can make whatever choices you like but I used the following settings for this post when configuring the new input.

  1. After you have logged into your Graylog Instance,  click “System” => “Inputs
  2. On the “Inputs” page, select “Syslog TCP” as the input type and click the “Launch new input” button
    Title: ids-tcp-input
    Bind Address:
    Port: 15514
    Check the box "allow overriding Date"
    Click "Save"
  3. Login to the CLI to create a new firewall rule, (you are using the firewall…right?). Example for RHEL 7 derivative.
    firewall-cmd --zone=internal --add-port=15514/tcp

Note: For arguments sake, let’s assume the server name of the Graylog host is graylog.server.tld.

Configure Stream for Graylog (Optional)

Streams are a way to route messages into different buckets basically. You don’t have to use them but they can be helpful. More about streams can be found here

  1. Click the “Stream” tab in the top navigation bar within your Graylog Instance
  2. Click the “Create Stream” button in the upper right of the “Streams” page
    Title: BRO IDS logs
    Description: Log messages from BRO IDS
    Click "Save"
  3. Edit the rules on the new stream by clicking on “Manage Rules
  4. Select the input we created above as the source for this stream (ids-tcp-input…)
  5. Click the “Add stream rule” button on the right.
    Field: application_name
    Select "match regular expression" from the dropdown
    Value: bro_*
    Description: Find all applications tagged from BRO
    Click "Save" then Click "I'm done!"

Configure Rsyslog

Note: if you are sending directly to Graylog you can skip this step. However, If rsyslog is already collecting logs and forwarding them on to a Graylog instance, some changes to the /etc/rsyslog.conf file are necessary.

Edit the rsyslog.conf file.

vi /etc/rsyslog.conf

It may be a good idea to allow for larger than normal syslog messages by adding this directive to your rsyslog.conf

#Set max message size for large syslog messages
$MaxMessageSize 64k

Add this to the rsyslog rules section. It looks for anything tagged with bro_* as the programname/app-name and forwards it to the specified host using TCP as the transport. That’s what the @@ is for. to send UDP a single @ is all that is necessary.

:app-name, regex, "bro_*" {
    *.* @@graylog.server.tld:15514;GRAYLOGRFC5424

If you currently use rsyslog to send data to Graylog, you most likely have the following template configured. See for other examples.

template (name="GRAYLOGRFC5424" type="string"
          string="<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME:::lowercase% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n"

On Redhat and derivatives running SELinux, you may have to allow rsyslog to use the new destination port.

semanage port -a -t syslogd_port_t -p tcp 15514

Restart rsyslog for the changes to take affect

systemctl restart rsyslog 
service rsyslog restart

Note: For arguments sake, let’s assume the server name of the Rsyslog host is rsyslog.server.tld.

Configure Syslog-NG on Security Onion

Note: If you are not using Security Onion, the location of the log files might be different and they may not contain the same exact configurations. Also, if you are using an older version of Security Onion, these setting may not be exactly right either.

On the Security Onion sensor(s) edit the syslog-ng config file.

vi /etc/syslog-ng/syslog-ng.conf

Make sure these lines are in your syslog-ng config.

rewrite r_from_pipes { subst('\|', "%7C", value("MESSAGE") flags(global) condition(program("bro_*" type(glob)))); };
rewrite r_pipes { subst("\t", "|", value("MESSAGE") flags(global)); };
filter f_bro_headers { message("^#") };

Verify you have entries like this in your syslog-ng config

source s_bro_conn { file("/nsm/bro/logs/current/conn.log" flags(no-parse) program_override("bro_conn")); };
source s_bro_http {
        file("/nsm/bro/logs/current/http_eth1.log" flags(no-parse) program_override("bro_http"));

source s_bro_dns { file("/nsm/bro/logs/current/dns.log" flags(no-parse) program_override("bro_dns")); }

You can view the entire syslog-ng config on the SO github pages

Add a new destination that points to either your Graylog instance or intermediary collector. In this example, rsyslog was already setup to receive logs on TCP port 514. If you plan on sending logs directly to Graylog, use the same port used when setting up the input that was created.

destination d_net { syslog("rsyslog.server.tld" transport(tcp) port(514)); };

Note: The BRO configuration on Security Onion comes with a lot of predefined configurations, which are primarily used to send logs to the internal ELSA instance. It is easiest to create a new log section configured with only the specific logs we want to send. There are many informational logs that can be beneficial but I will leave that up to the reader to decide what is right for them.

Setup a new log configuration of what will be sent over syslog to the remote host.

log {
        log { filter(f_bro_headers); flags(final); };
        log { destination(d_net); };

At this point, you can disable ELSA on the sensor(s) if you choose.

Edit the securityonion.conf file and find the line with ELSA=YES and change it to ELSA=NO

vi /etc/nsm/securityonion.conf

Note: Much of the ELSA config is buried in different config files so more will have to be done to completely disable ELSA after it has been configured. A better approach may be to never enable ELSA in the first place during a new SO deployment.

You will have to restart the sensor(s) after that change is made.

Logs are now being sent to the Graylog destination. You will notice, there are no predefined fields within the Graylog stream that was created. This is because Security Onion is sending raw ASCII data that is separated by pipes(|). to parse out data from different BRO logs, more work has to be done using grok patterns, standard regex, or some other mechanism within Graylog or Rsyslog.

There is a BRO plugin that converts logs into json, which can alleviate some extra work but I have not tried it.

You must be logged in to post a comment.

Proudly powered by WordPress   Premium Style Theme by