├── .gitignore ├── README.md ├── example-original.gif ├── example.gif ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # REST adapter for osquery compatible with Vega 2 | 3 | This adapter allows you to visualize information about your OS, for example see running processes, hardware devices or opened ports. It does that by making [osquery](https://osquery.io/) data available as a REST endpoint. You can then browse and visualize the information using [Voyager](https://www.github.com/vega/voyager) or [Polestar](https://www.github.com/vega/polestar). 4 | 5 | ![PCI devices visualized using Voyager](example.gif) 6 | 7 | ## Usage 8 | 9 | Install: `npm install -g osquery-rest-adapter` 10 | 11 | Run it: `osquery-rest-adapter` 12 | 13 | Use different port (default is 8080): `PORT=3003 osquery-rest-adapter` 14 | 15 | ## Prerequisites 16 | 17 | 1. [Install osquery](https://osquery.io/downloads/) (you do not need to run `osqueryd`, only `osqueryi` needs to be available) 18 | 2. Download [Voyager](https://www.github.com/vega/voyager) or [Polestar](https://www.github.com/vega/polestar) 19 | 3. After opening Voyager or Polestar, add a dataset using *From Myria* tab. Put in `http://localhost:8080`, click update and select the table you want to explore. 20 | 21 | ## Standalone queries 22 | 23 | This adapter is best used by visualization tools. But you can also use the REST endpoint directly. 24 | 25 | ### Get list of available datasets 26 | 27 | You can use optional `q` parameter for search. 28 | 29 | `curl localhost:8080/dataset/search?q=usb` 30 | 31 | ``` 32 | [{ 33 | "userName": "local", 34 | "programName": "osquery", 35 | "relationName": "usb_devices" 36 | }] 37 | ``` 38 | 39 | ### Fetch a dataset 40 | 41 | In this example we fetch list of `usb_devices` in the system. 42 | 43 | `curl localhost:8080/dataset/user-local/program-osquery/relation-usb_devices/data` 44 | 45 | ## Technical details 46 | 47 | *Voyager* and *Polestar* use common components from [vega-lite-ui](https://github.com/vega/vega-lite-ui) that provide dataset loading functionality. One option is to load datasets from the [Myria](https://github.com/uwescience/myria) platform. This adapter works by providing small subset of API compatible with *Myria* so that *vega-lite-ui* can connect to it. 48 | 49 | **Warning!** This adapter exposes information about your system, so make sure to configure your firewall if you want to use it in a public or untrusted network. 50 | 51 | ## See also 52 | 53 | - [Envdb](https://github.com/mephux/envdb) is a web app that provides GUI for querying osquery. It helps you to browse and see the results in tables. An extra feature is that you can connect multiple machines to a cluster and run queries on all of them at the same time. 54 | - [Dashiell](https://github.com/maclennann/dashiell) is a web app that allows you to query osquery and also [facter](https://github.com/puppetlabs/facter) (which is internally used by [Puppet](https://puppetlabs.com/)). 55 | - [osquery-node](https://github.com/sidorares/osquery-node) is an advanced osquery client for node.js. It also allows you to write custom plugins for osquery in javascript. 56 | - [mysql-osquery-proxy](https://github.com/sidorares/mysql-osquery-proxy) allows you to use osquery with a mysql-compatible client. 57 | -------------------------------------------------------------------------------- /example-original.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dundalek/osquery-rest-adapter/268cc6f4cc3130b717560bc53275900eee0e2b69/example-original.gif -------------------------------------------------------------------------------- /example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dundalek/osquery-rest-adapter/268cc6f4cc3130b717560bc53275900eee0e2b69/example.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "osquery-rest-adapter", 3 | "version": "0.1.0", 4 | "description": "Visualize information about your OS (REST adapter for osquery compatible with Vega)", 5 | "bin": { 6 | "osquery-rest-adapter": "./server.js" 7 | }, 8 | "main": "server.js", 9 | "repository": "https://github.com/dundalek/osquery-rest-adapter", 10 | "dependencies": { 11 | "cors": "^2.7.1", 12 | "express": "^4.13.3", 13 | "fuzzy": "^0.1.1" 14 | }, 15 | "devDependencies": {}, 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1", 18 | "start": "node server.js" 19 | }, 20 | "keywords": [ 21 | "vega", 22 | "voyager", 23 | "polestar", 24 | "osquery", 25 | "visualization", 26 | "rest", 27 | "adapter", 28 | "os" 29 | ], 30 | "author": "Jakub Dundalek", 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var exec = require('child_process').exec; 2 | var fuzzy = require('fuzzy'); 3 | var express = require('express'); 4 | var cors = require('cors') 5 | 6 | var app = express(); 7 | app.use(cors()); 8 | 9 | var userName = 'local'; 10 | var programName = 'osquery'; 11 | 12 | var tables = new Promise(function(resolve, reject) { 13 | exec('osqueryi .tables', function(err, stdout, stderr) { 14 | if (err) return reject(err); 15 | var out = stdout.trim().replace(/=>/g, '').split('\n').map(function(table) { 16 | return { 17 | userName: userName, 18 | programName: programName, 19 | relationName: table.trim() 20 | } 21 | }) 22 | resolve(out); 23 | }); 24 | }); 25 | 26 | app.get('/dataset/search', function (req, res, next) { 27 | tables.then(function(results) { 28 | if (req.query.q) { 29 | var q = req.query.q.replace(/\s+/g, ''); 30 | var options = {extract: function(el) {return el.relationName;}} 31 | matches = fuzzy.filter(q, results, options); 32 | results = matches.map(function(el) {return el.original;}); 33 | } 34 | res.json(results); 35 | }).catch(next); 36 | }); 37 | 38 | function extractParam(req, param) { 39 | // get param and trip prefix, e.g. user-MyUser -> MyUser 40 | return req.params[param].slice(param.length + 1); 41 | } 42 | 43 | function isValidTableName(name) { 44 | return !!name.match(/^[_A-Za-z]+$/); 45 | } 46 | 47 | app.get('/dataset/:user/:program/:relation/data', function (req, res, next) { 48 | var user = extractParam(req, 'user'); 49 | var program = extractParam(req, 'program'); 50 | var relation = extractParam(req, 'relation'); 51 | 52 | if (!isValidTableName(relation)) return next('Invalid table name: ' + relation); 53 | 54 | exec('osqueryi --json "select * from ' + relation + '"', function(err, stdout, stderr) { 55 | if (err) return next(err); 56 | res.send(stdout); 57 | }); 58 | 59 | }); 60 | 61 | var server = app.listen(process.env.PORT || 8080, function () { 62 | var host = server.address().address; 63 | var port = server.address().port; 64 | 65 | console.log('Example app listening at http://%s:%s', host, port); 66 | }); 67 | --------------------------------------------------------------------------------