Use osquery for Linux Host Visibility
Install osquery on Linux, write SQL queries against processes, files, and sockets, configure FIM packs, and enroll hosts into a Fleet manager for full fleet visibility.
Before you start
- ▸Root or sudo access on the target host
- ▸Outbound HTTPS access to pkg.osquery.io to add the repository
- ▸Familiarity with basic SQL SELECT syntax
- ▸For fleet enrollment: a running Fleet or osctrl server and a valid enrollment secret
osquery turns your Linux host into a queryable database. Instead of grepping through /proc, parsing log files, or writing custom scripts, you write SQL against tables that expose processes, open files, network sockets, users, kernel modules, cron jobs, and hundreds of other system objects. It is a foundational tool for detection engineering, incident response, and continuous compliance — and it runs on every major Linux distribution.
Install osquery
The osquery project publishes signed packages for all major distributions. Use the official repository rather than distro-packaged versions, which are often several releases behind.
Debian / Ubuntu
export OSQUERY_KEY=1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B
curl -L https://pkg.osquery.io/deb/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/osquery.gpg
echo "deb [signed-by=/usr/share/keyrings/osquery.gpg arch=amd64] https://pkg.osquery.io/deb deb main" \
| sudo tee /etc/apt/sources.list.d/osquery.list
sudo apt update && sudo apt install -y osquery
Fedora / RHEL / Rocky
curl -L https://pkg.osquery.io/rpm/GPG | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-osquery
sudo tee /etc/yum.repos.d/osquery.repo <<'EOF'
[osquery]
name=osquery
baseurl=https://pkg.osquery.io/rpm
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-osquery
EOF
sudo dnf install -y osquery
Arch Linux
yay -S osquery # or paru, or clone the osquery AUR package directly
Start the Daemon
osqueryd is the long-running daemon that logs scheduled query results and forwards them to a fleet manager. osqueryi is the interactive shell for ad-hoc queries. Both are installed by the package.
sudo systemctl enable --now osqueryd
systemctl status osqueryd
The daemon reads its configuration from /etc/osquery/osquery.conf. If that file does not exist, the daemon starts with defaults and logs to /var/log/osquery/. Create a minimal config to verify the daemon accepts it:
sudo tee /etc/osquery/osquery.conf <<'EOF'
{
"options": {
"logger_plugin": "filesystem",
"logger_path": "/var/log/osquery",
"disable_events": "false",
"schedule_splay_percent": "10"
},
"schedule": {}
}
EOF
sudo systemctl restart osqueryd
Interactive Queries with osqueryi
Launch the interactive shell as root for full table access:
sudo osqueryi
The prompt looks like osquery>. Every statement is SQL against a virtual schema. Start with discovery:
# List all available tables
SELECT name FROM osquery_tables ORDER BY name;
# Schema for a specific table
.schema processes
Query Processes
-- Running processes with network connections (join processes + process_open_sockets)
SELECT p.pid, p.name, p.path, p.cmdline, s.remote_address, s.remote_port
FROM processes p
JOIN process_open_sockets s ON p.pid = s.pid
WHERE s.remote_port != 0
ORDER BY p.name;
Query Open Files and Sockets
-- Processes listening on TCP
SELECT p.name, p.pid, s.local_address, s.local_port, s.state
FROM listening_ports s
JOIN processes p ON s.pid = p.pid
WHERE s.protocol = 6
ORDER BY s.local_port;
-- Writable files in /tmp owned by root but world-writable
SELECT path, mode, uid, gid, size
FROM file
WHERE directory = '/tmp'
AND (CAST(mode AS INTEGER) & 2) != 0;
Query Users and Cron
-- All cron entries system-wide
SELECT command, path, minute, hour, day_of_month, month, day_of_week
FROM crontab;
-- Users with UID 0 (should normally be only root)
SELECT username, uid, gid, shell, directory
FROM users
WHERE uid = 0;
-- Kernel modules currently loaded
SELECT name, size, status, address
FROM kernel_modules
ORDER BY name;
Scheduled Queries and Packs
Packs are JSON bundles of scheduled queries with their own intervals and platform filters. osquery ships with community packs in /usr/share/osquery/packs/ (exact path varies by distro). Notable packs include incident-response, it-compliance, and ossec-rootkit.
Enable packs by referencing them in osquery.conf:
sudo tee /etc/osquery/osquery.conf <<'EOF'
{
"options": {
"logger_plugin": "filesystem",
"logger_path": "/var/log/osquery",
"disable_events": "false",
"schedule_splay_percent": "10",
"events_expiry": "3600"
},
"schedule": {
"system_info": {
"query": "SELECT hostname, cpu_brand, physical_memory FROM system_info;",
"interval": 3600
},
"listening_ports": {
"query": "SELECT pid, port, protocol, family, address FROM listening_ports;",
"interval": 300
}
},
"packs": {
"incident-response": "/usr/share/osquery/packs/incident-response.conf",
"it-compliance": "/usr/share/osquery/packs/it-compliance.conf"
}
}
EOF
sudo systemctl restart osqueryd
Scheduled results accumulate in /var/log/osquery/osqueryd.results.log as newline-delimited JSON. Each record includes the query name, a diff of added/removed rows, and the epoch timestamp — directly ingestible by most SIEM and log aggregation tools.
sudo tail -f /var/log/osquery/osqueryd.results.log | python3 -m json.tool
File Integrity Monitoring with FIM
osquery's file_events table provides inotify-backed FIM. Define paths to watch in osquery.conf under the file_paths key, then query file_events in a schedule:
sudo tee /etc/osquery/osquery.conf <<'EOF'
{
"options": {
"disable_events": "false"
},
"file_paths": {
"etc": ["/etc/%%"],
"ssh": ["/home/%/.ssh/%%", "/root/.ssh/%%"],
"binaries": ["/usr/bin/%%", "/usr/sbin/%%"]
},
"schedule": {
"file_events": {
"query": "SELECT target_path, action, md5, sha256, time FROM file_events;",
"interval": 60,
"removed": false
}
}
}
EOF
sudo systemctl restart osqueryd
Note: %% is osquery's recursive glob; % is a single directory wildcard. Monitoring very large directory trees will increase CPU and inotify watch usage. Check your inotify limit with cat /proc/sys/fs/inotify/max_user_watches and increase it in /etc/sysctl.d/ if needed.
Fleet Management
Running osquery on a single host is useful; running it across a fleet is transformative. The two most common open-source fleet managers are Fleet (formerly Kolide Fleet, now fleetdm.com) and osctrl. Both implement the osquery TLS remote API.
Enroll a Host with Fleet
After deploying the Fleet server (a separate task covered in the Fleet documentation), generate an enrollment secret from the Fleet UI or CLI, then configure osquery to use the TLS plugin:
sudo tee /etc/osquery/osquery.flags <<'EOF'
--tls_hostname=fleet.example.com
--host_identifier=hostname
--enroll_secret_path=/etc/osquery/enroll_secret
--tls_server_certs=/etc/osquery/fleet.crt
--config_plugin=tls
--config_tls_endpoint=/api/v1/osquery/config
--logger_plugin=tls
--logger_tls_endpoint=/api/v1/osquery/log
--enroll_tls_endpoint=/api/v1/osquery/enroll
EOF
# Write your enrollment secret (obtained from the Fleet server)
echo -n 'YOUR_ENROLL_SECRET' | sudo tee /etc/osquery/enroll_secret
sudo chmod 600 /etc/osquery/enroll_secret
sudo systemctl restart osqueryd
Once enrolled, Fleet distributes pack configurations centrally and lets you run live queries against any or all enrolled hosts from a single interface — no SSH required.
Verify Everything is Working
# Confirm the daemon is active
systemctl is-active osqueryd
# Check for startup errors
journalctl -u osqueryd -n 50 --no-pager
# Confirm results are being written
sudo ls -lh /var/log/osquery/
# Quick ad-hoc check from the interactive shell
sudo osqueryi --line "SELECT * FROM os_version;"
Troubleshooting
- osqueryd won't start after config change: Validate JSON syntax with
python3 -m json.tool /etc/osquery/osquery.confbefore restarting. A single trailing comma breaks the parser. - file_events table is empty: Confirm
--disable_events=falseis set (it defaults to false, but an explicit flag in an olderosquery.flagsfile may override the config). Also verify inotify watches are not exhausted. - High CPU on a busy host: Increase
schedule_splay_percentand raise query intervals. Theprocess_eventstable in particular can generate high volume on active servers — filter aggressively in the query's WHERE clause. - TLS enrollment fails: Check that the clock on the host is within a few seconds of the Fleet server (NTP drift causes TLS failures). Also verify the CA certificate path in
--tls_server_certs. - Permission errors in osqueryi: Most tables that read
/procor/etc/shadowrequire root. Runsudo osqueryifor full visibility.
Frequently asked questions
- Does osquery work on Wayland desktops or does it require X11?
- osquery is a daemon and CLI tool with no display dependency. It works identically on headless servers, Wayland desktops, and X11 systems. Desktop session information is exposed through the logged_in_users table regardless of display server.
- How does osquery differ from auditd for monitoring file and process events?
- auditd writes raw audit records to a flat log and requires aureport or ausearch to make sense of them. osquery uses the same kernel event sources but exposes results as structured SQL tables with JOIN support, making correlation across process, file, and network data far easier to express and automate.
- Will running osquery noticeably impact production server performance?
- At default intervals (300–3600 seconds for most scheduled queries) the overhead is negligible on modern hardware. Tables like process_events or dns_lookup_events that fire on every kernel event can be expensive; always add specific WHERE filters and keep their intervals short to limit log volume, not query frequency.
- Can osquery detect rootkits or kernel-level tampering?
- osquery can detect many rootkit indicators using the ossec-rootkit pack: SUID files, unexpected kernel modules, processes hidden from /proc, and setuid binaries in unusual locations. It cannot detect sophisticated bootkit or hypervisor-level tampering that manipulates the kernel before osquery runs.
- What is the difference between osquery packs and scheduled queries defined directly in osquery.conf?
- Functionally identical — packs are simply a way to bundle related queries into separate JSON files for easier versioning and sharing. The Fleet manager also lets you target packs to specific host labels, so separating queries into packs enables fine-grained fleet-wide targeting.
Related guides
Manage Secrets with Ansible Vault
Encrypt Ansible secrets with AES-256 using ansible-vault: encrypt files and inline vars, automate with password files, and isolate group-level secrets with vault IDs.
AppArmor Explained
Learn how AppArmor profiles work, how to switch between enforce and complain mode, create new profiles, and diagnose access denials on Ubuntu, Debian, and Arch.
Apply CIS Benchmarks with OpenSCAP
Use OpenSCAP and scap-security-guide to evaluate, report on, and remediate Linux systems against CIS Benchmarks — covering install, eval, and automation.
How to Audit a Linux System with auditd
Set up auditd on Linux to track file access, syscalls, and privilege use. Covers persistent rules, file watches, ausearch, and aureport across major distros.