RPM package creation for BRO IDS Deployments.
Basically, there are two ways to install BRO. One is, download the source and compile it for your machine. The other option is to install BRO from a package. Compiling from source is a great option, which allows for customization but can become problematic when deploying BRO on several sensors. To address this challenge, compiling BRO on a build machine, and distributing the resulting package to sensor nodes for installation, seems like a good idea.
There is no shortage of articles on how to compile BRO from source but there aren’t many that discuss building custom packages. I hope this information is helpful in that regard. There are some key differences worth noting between the source built package and the pre-built repo packages. Namely, when using the --binary-package build option, permissions on the target folder are not set the same, a specific group is not set, nor is the bro group created on the system during install. Another thing is RPATH is stripped as part of the package build so Dynamic linking loaders need to be properly identified on the target machine by placing a file in etc/ld.so.conf.d/.
Building a custom BRO IDS binary package.
All the steps within this article assume CentOS 7 as the platform of choice. The steps should be similar on other platforms but they are out of scope of this document. The first thing to do is install prerequisite software using yum on the build system. In this case, the build system is a Centos 7.5.1804 (Core) VM running on VMware 6.5 with kernel 3.10.0-862.6.3.el7.x86_64.
Install prerequisite software:
install pf_ring:
The pf_ring package was installed from an rpm using the ntop.org repo.
Install build tools:
yum install cmake make gcc gcc-c++ flex bison libpcap-devel openssl-devel python-devel swig zlib-devel rpm-build
Building the BRO IDS package:
Get the sources from the git repo
cd ~ (use of an unprivileged user account is fine) git clone --recursive https://github.com/zeek/zeek.git
Edit files prior to the build:
The two files below provide content for the %post and %pre sections of the spec file.
/bro/cmake/package_postupgrade.sh.in /bro/cmake/package_preinstall.sh.in
Edit package_postupgrade.sh.in and change the section defining world writable directories.
Change from this
# Set up world writeable spool and logs directory for broctl, making sure # to set the sticky bit so that unprivileged users can't rename/remove files. # (CMake/CPack is supposed to install them, but has problems with empty dirs) if [ -n "@EMPTY_WORLD_DIRS@" ]; then for dir in "@EMPTY_WORLD_DIRS@"; do mkdir -p ${dir} chmod 777 ${dir} chmod +t ${dir} done fi
to this
# Set up world writeable spool and logs directory for broctl, making sure # to set the sticky bit so that unprivileged users can't rename/remove files. # (CMake/CPack is supposed to install them, but has problems with empty dirs) if [ -n "@EMPTY_WORLD_DIRS@" ]; then for dir in "@EMPTY_WORLD_DIRS@"; do mkdir -p ${dir} chmod 3770 ${dir} chgrp bro ${dir} done fi
Make additions to the spec file template:
Note: Managing the creation of the /etc/ld.so.conf.d/bro-x86_64.conf file is well handled using the spec file. However, I was having some trouble figuring out where/what to update to make changes stick(I’m still not sure of the right way to do it but I’ll keep looking). Eventually, I found the CPackRPM.cmake file, which has a template. The way I worked around this as a temporary solution was editing the template in /usr/share/cmake/Modules/CPackRPM.cmake, which is bad form I’m sure but it works.
Add ldconfig to the %post and %postun sections so the library path is loaded. Example below.
%post ldconfig \@CPACK_RPM_SPEC_POSTINSTALL\@ %postun ldconfig
Then make additions to the %pre and %preun sections and changes to the %defattr setting in the spec file template:
%pre /usr/bin/getent group bro >/dev/null || /usr/sbin/groupadd -r bro # Check for additional library declaration files in /etc/ld.so.conf.d/ # Create file on install if [ ! -f /etc/ld.so.conf.d/bro-x86_64.conf ]; then echo \"/opt/bro/lib\" > /etc/ld.so.conf.d/bro-x86_64.conf echo \"/opt/bro/lib64\" >> /etc/ld.so.conf.d/bro-x86_64.conf fi \@CPACK_RPM_SPEC_PREINSTALL\@ %preun # Check if library declaration files are in /etc/ld.so.conf.d/ # Remove them on uninstall if [ -f /etc/ld.so.conf.d/bro-x86_64.conf ]; then rm /etc/ld.so.conf.d/bro-x86_64.conf fi \@CPACK_RPM_SPEC_PREUNINSTALL\@ %files %defattr(-,root,bro,-)
Configure for deployment:
cd ~/zeek LDFLAGS="-lpfring -lpcap" ./configure --prefix=/opt/bro --with-pcap=/usr/local/ --pkg-name-prefix=Bro --binary-package --build-type=Release cd build make package
Finishing up:
The above process will leave us with an rpm package in ~/bro/build named something like Bro-2.5-725-Linux-x86_64.rpm. At this point we need to distribute the package in some way to other nodes and perform the final configuration. Distribution options are up to the reader but I can offer a few ideas.
- Use scp to copy the file to intended sensors and install using yum localinstall
- Use deployment tools like salt to deploy and configure BRO on the remote sensors
- Host the file on an internal repo server for distribution
- Build a golden image and spin up sensors using that image
REF: https://www.ntop.org/guides/pf_ring/thirdparty/bro.html
REF: https://www.bro.org/sphinx/install/install.html#prerequisites
REF: https://www.bro.org/development/howtos/cmake.html
REF: https://codeyarns.com/2017/11/02/how-shared-library-locations-are-found-at-runtime/
REF: https://codeyarns.com/2014/01/14/how-to-fix-shared-object-file-error/
REF: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/rpm_packaging_guide/index#what-is-a-spec-file