16 KiB
Dependencies
We include a make deps
command to make it easier for developers to get started with the osquery project. make deps
uses Homebrew for macOS and Linuxbrew for Linux. The following basic dependencies are need before running make deps
:
sudo
make
(that is, GNU make)python
ruby
git
bash
NOTICE: This will install or build various dependencies on the build host that are not required to "use" osquery, only build osquery binaries and packages.
For our build hosts (CentOS, Ubuntu 12, 14, 16, macOS 10.12, Windows 2016) we use a sysprep
target to update the host and install these basic dependencies.
make sysprep
Building on macOS
make deps
will take care of installing the appropriate library dependencies, but it's recommended to take a look at the Makefile, just in case something conflicts with your environment.
The complete installation/build steps are as follows:
$ git clone https://github.com/facebook/osquery.git
$ cd osquery
$ # make sysprep
$ make deps
$ make
Once the project is built, try running the project's unit tests:
$ make test
And the binaries are built in:
$ ls -la ./build/darwin/osquery/
Building on Linux
osquery supports almost all distributions of Linux.
For some distros, we supply vagrant infrastructure for creating native operating system packages. To create a package (e.g. a deb on Ubuntu or an rpm on CentOS), simply spin up a vagrant instance.
For example:
$ vagrant up ubuntu14
$ vagrant ssh ubuntu14
By default vagrant will allocate 2 virtual CPUs to the virtual machine instance. You can override this by setting OSQUERY_BUILD_CPUS
environment variable before spinning up an instance. To allocate the maximum number of CPUs, OSQUERY_BUILD_CPUS
can be set as:
OSQUERY_BUILD_CPUS=`nproc` # for Linux
OSQUERY_BUILD_CPUS=`sysctl -n hw.ncpu` # for MacOS
Once you have logged into the vagrant box, run the following to create a package:
$ cd /vagrant
$ make sysprep
$ make deps
$ make
$ make test
The binaries are built to a distro-specific folder within build and symlinked in:
$ ls -la ./build/linux/osquery/
Submitting Pull Requests
Once you have made changes you'll want to submit them to Github as a Pull Request. There are tons of wonderful guides and documentation around Pull Requests, and that is just out of scope for this wiki-- but consider the following workflow:
$ git checkout -b new_feature1
$ # write some code!
$ make -j 4
$ git commit -m "New Feature: do something wonderful"
$ git push
This assumes your remote origin
is your osquery fork, and that you receive updates from an upstream
. It is also common to use origin
as facebook/osquery
then add your fork as a target named after your Github username.
In that case the final push becomes git push USERNAME
.
Testing changes
Our Jenkins CI will test your changes in three steps.
- A code audit is run using
make audit
. - The code is rebuilt, built again for release, then a package is generated using
./tools/build.sh
on various Linux and macOS versions. - The same step is run on Windows 10.
The audit step attempts to build the documentation, run code formatting checks, and a brief static code analysis. The formatting check is performed with clang-format
(installed with make deps
to your osquery dependencies directory). Your changes are compared against the local master
branch. Within the build host this is always the TIP of facebook/osquery
, but locally the branch may be behind.
To speed up the format auditing process please configure your code editor to run clang-format
on files changed. Or periodically during your development run make format_master
. Running make check
is also helpful, but it will use cppcheck
which is not installed by default.
Dependencies and build internals
The make deps
command is fairly intense and serves two purposes: (1) to communicate a standard set of environment setup instructions for our build and test nodes, (2) to provide an environment for reproducing errors. The are wonderful auxiliary benefits such as controlling the compiler and compile flags for almost all of our dependencies, controlling security-related features for dependencies, allowing a "mostly" universal build for Linux that makes deployment simple. To read more about the motivation and FAQ for our dependencies environment see the Github Refererence #2253.
When using make deps
the environment the resultant binaries will have a minimum set of requirements to run:
glibc
version 2.13libgcc_s
libz
All other dependencies are built, compiled, and linked statically. This makes for a rather large set of output binaries (15M on Linux and 9M on macOS) but the trade-off for deployment simplicity is very worthwhile.
Under the hood the make deps
script is calling ./tools/provision.sh
, which performs the simplified set of steps:
- Create a "runtime" directory or dependency home:
/usr/local/osquery
. - Clone a pinned version of Homebrew or Linuxbrew into that home.
- Install a local Tap using
./tools/provision/formulas
into that home. - Run optional distro-specific setup scripts from
./tools/provision/DISTRO.sh
. - Install a list of packages from the local Tap defined in
./tools/provision.sh
.
We use a minimum set of packages from Homebrew and Linuxbrew, mostly just tools. The remaining tools and C/C++ library dependencies as well as C and C++ runtimes are built from source. If we need to change compile options or variables we can bump these formula's bottle revisions.
Adding or changing dependencies
If you need to bump a dependency version, change the way it is built, or add a new dependency-- use the formulas in ./tools/provision/formula/
. Let's consider a simple example:
require File.expand_path("../Abstract/abstract-osquery-formula", __FILE__)
class Libaudit < AbstractOsqueryFormula
desc "Linux auditing framework"
url "https://github.com/Distrotech/libaudit/archive/audit-2.4.2.tar.gz"
sha256 "63020c88b0f37a93438894e67e63ccede23d658277ecc6afb9d40e4043147d3f"
def install
system "./autogen.sh"
system "./configure", "--prefix=#{prefix}"
cd "lib" do
system "make"
system "make", "install"
end
end
end
This looks A LOT like normal *brew formulas. For a new dependency do not add a bottle
section. For help with writing formulas see Homebrew's Formula Cookbook. Note that we use an Abstract to control the environment variables and control relocation on Linux.
If you want to make build changes see the Cookbook for revision
edits. Note that committing new or edited formulas will invalidate package caches this will cause the package to be built from source on the test/build hosts.
If this is a new dependency then you need to add a line to ./tools/provision.sh
for Linux and or macOS at the order/time it should be installed.
When a dependency is updated by a maintainer or contributor the flow should follow:
- Update the target formula in
./tools/provision/formula/
. - Run
make deps
and the dependency change should cause a rebuild from source. - Build and run the osquery tests, and submit the change in a pull request.
After the change is merged, a maintainer can provide a bottle/binary version:
- Run
./tools/provision.sh uninstall TARGET
to remove the from-source build. - Run
make build_deps
to build a bottle version from source. - Run
./tools/provision.sh bottle TARGET
to generate the bottle. - Update the formula again with the SHA256 printed to stdout.
- Upload the
/usr/local/osquery/TARGET-VERSION.tar.gz
to the S3bottles
folder. - Create a pull request with the updated SHA256.
AWS EC2 Backed Vagrant Targets
The osquery vagrant infrastructure supports leveraging AWS EC2 to run virtual machines. This capability is provided by the vagrant-aws plugin, which is installed as follows:
$ vagrant plugin install vagrant-aws
Next, add a vagrant dummy box for AWS:
$ vagrant box add andytson/aws-dummy
Before launching an AWS-backed virtual machine, a few environment variables must be set:
# Required. Credentials for AWS API. vagrant-aws will error if these are unset.
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
# Name of AWS keypair for launching and accessing the EC2 instance.
export AWS_KEYPAIR_NAME=my-osquery-vagrant-security-group
export AWS_SSH_PRIVATE_KEY_PATH=/path/to/keypair.pem
# Name of AWS security group that allows TCP/22 from vagrant host.
# If using a non-default VPC use the security group ID instead.
export AWS_SECURITY_GROUP=my-osquery-vagrant-security-group
# Set this to the AWS region, "us-east-1" (default) or "us-west-1".
export AWS_DEFAULT_REGION=...
# Set this to the AWS instance type. If unset, m3.medium is used.
export AWS_INSTANCE_TYPE=m3.large
# (Optional) Set this to the VPC subnet ID.
# (Optional) Make sure your subnet assigns public IPs and there is a route.
export AWS_SUBNET_ID=...
Spin up a VM in EC2 and SSH in (remember to suspect/destroy when finished):
$ vagrant up aws-amazon2015.03 --provider=aws
$ vagrant ssh aws-amazon2015.03
Debug Builds, formatting, and more
To generate a non-optimized debug build use make debug
.
CMake regenerates build information every time make [all]
is run. To avoid the "configure" and project setup use make build
.
make building and testing macros:
make # Default optimized configure/build
make test # Test the default build
make debug # Configure and build non-optimized with debuginfo
make test_debug # Test the debug build
make build # Skip the CMake project configure (compile only)
make debug_build # Same as build, but applied to the debug target
make test_debug_build # Take a guess ;)
make clean # Clean the CMake project configuration
make distclean # Clean all cached information and build dependencies
make deps # Install the osquery dependency environment into /usr/local/osquery
make depsclean # Remove the dependency environment
make docs # Build the Doxygen and mkdocs wiki
There are several additional code testing and formatting macros:
make format_master # Format everything changed from the local master branch
make format_all # Not recommended but formats the entire code base
make format # Apply clang-format using osquery's format spec*
make analyze # Run clean first, then rebuild with the LLVM static analyzer
make sanitize # Run clean first, then rebuild with sanitations
make fuzz # Run basic fuzz tests, as defined in each table spec
make audit # The clang-format and other PR-blocking checks
make check # Run cpp-check and output style/performance/error warnings
Generating the osquery SDK or sync:
make sdk # Build only the osquery SDK (libosquery.a)
make sync # Create a tarball for building the SDK externally
Finally, subtle changes to the build are mostly controlled through environment
variables. When making these changes it is best to removed your build cache
by removing the ./build/
or ./build/{platform}/
directory.
OSQUERY_BUILD_LINK_SHARED=True # Prefer linking against shared libraries
OSQUERY_BUILD_SHARED=True # Build and link a shared libosquery.
OSQUERY_BUILD_DEPS=True # Install dependencies from source when using make deps
OSQUERY_BUILD_BOTTLES=True # Create bottles from installed dependencies
OSQUERY_BUILD_VERSION=9.9.9 # Set a wacky version string
OSQUERY_PLATFORM=custom_linux;1.0 # Set a wacky platform/distro name
SDK_VERSION=9.9.9 # Set a wacky SDK-version string.
OSX_VERSION_MIN=10.11 # Override the native minimum macOS version ABI
OSQUERY_DEPS=/path/to/dependencies # Use a custom dependency environment
FAST=True # Build and link as quick as possible.
SANITIZE_THREAD=True # Add -fsanitize=thread when using "make sanitize"
SANITIZE_UNDEFINED=True # Add -fsanitize=undefined when using "make sanitize"
OPTIMIZED=True # Enable specific CPU optimizations (not recommended)
SQLITE_DEBUG=True # Enable SQLite query debugging (very verbose!)
There are various features that can be disabled with a customized build. These are also controlled by environment variables to be as cross-platform as possible and take the form: SKIP_*
. These are converted into CMake variables within the root CMakeLists.txt
.
SKIP_AWS=True # Skip the various AWS integrations
SKIP_TSK=True # Skip SleuthKit integrations
SKIP_LLDPD=True # Skip LLDP tables
SKIP_YARA=True # Skip Yara integrations, both events and the virtual tables
SKIP_KAFKA=True # Skip support for Kafka logger plugins
SKIP_CARVER=True # Skip support for file carving
SKIP_KERNEL=True # Enabled by default, set to 'False' to enable
SKIP_TESTS=True # Skip unit test building (very very not recommended!)
SKIP_INTEGRATION_TESTS=True # Skip python tests when using "make test"
SKIP_BENCHMARKS=True # Build unit tests but skip building benchmark targets
SKIP_TABLES=True # Build platform without any table implementations or specs
SKIP_DISTRO_MAIN=False # Run the sysprep update/install within make deps
Custom Packages
Building osquery on macOS or Linux requires a significant number of dependencies, which are not needed when deploying. It does not make sense to install osquery on your build hosts. See the Custom Packages guide for generating PKGs, debs or RPMs.
Debug and from-source package building is not recommended but supported. You may generate several packages including devel, debuginfo, and additional sets of tools:
make package # Generate an osquery package for the build target
make packages # Generate optional/additional packages
These targets set the environment variable PACKAGE=1
and the CMake variable OSQUERY_BUILD_RELEASE
that enables allows build and CMake logic to make compile and linking decisions. This may enable additional compile defines or remove sources from targets.
The osquery package build hosts run a series of additional unit and integration tests. This involves building targets with debug routines, testing, building the same targets ready for packaging, testing, and running a final set of "sanity" and deployment tests.
To mimic and follow the same build/release testing workflow use:
export RUN_BUILD_DEPS=1
export RUN_RELEASE_TESTS=1
./tools/build.sh
Pay attention to the environment variable RUN_RELEASE_TESTS=1
, which enables the deployment sanity tests. If you are building an optimized or distribution package manager target this will most likely fail. The RUN_BUILD_DEPS
variable tells the build to begin with a make deps
.
Notes and FAQ
When trying to make, if you encounter:
Requested dependencies may have changed, run: make deps
You must run make deps
to make sure you are pulling in the most-recent dependency assumptions. This error typically means a new virtual table has been added that includes new third-party development libraries.
make deps
will take care of installing everything you need to compile osquery. However, to properly develop and contribute code, you'll need to install some additional programs. If you write C++ often, you likely already have these programs installed. We don't bundle these tools with osquery because many programmers are quite fond of their personal installations of LLVM utilities, debuggers, etc.
- clang-format: we use clang-format to format all code in osquery. After staging your commit changes, run
make format
(requires clang-format). - valgrind: performance is a top priority for osquery, so all code should be thoroughly tested with valgrind or instruments. After building your code use
./tools/analysis/profile.py --leaks
to run all queries and test for memory leaks.
Build Performance
Generating a virtual table should NOT impact system performance. This is easier said than done as some tables may seem inherently latent such as SELECT * from suid_bin;
if your expectation is a complete filesystem traversal looking for binaries with suid permissions. Please read the osquery features and guide on performance safety.
Some quick features include:
- Performance regression and leak detection CI guards.
- Blacklisting performance-impacting virtual tables.
- Scheduled query optimization and profiling.
- Query implementation isolation options.