osquery ですべての Linux コマンド操作を SQL 化する

<!-- osquery ですべての Linux コマンド操作を SQL 化する -->

# osquery とは

[osquery] とは OS の情報取得を SQL を書くことで実現するためのコマンドラインツールです。
Facebook によって開発され、Windows, maxOS, Linux で使用可能です。

## 試した環境

- CentOS 7
- osquery 3.2.6

## なぜ osquery を使うのか

`osquery` を使うことで従来の Linux コマンドでは困難だった OS の情報取得を改善することができます。
それを理解するために、まずは従来の Linux コマンドを使う場合にどのような問題が生じるのかを見てみます。

例えば Linux 上で `httpd` という名前のプロセスを知りたい場合は `pgrep` コマンドが使えます。

```bash
$ pgrep -fla httpd
14071 /usr/sbin/httpd -k start
14072 /usr/sbin/httpd -k start
14073 /usr/sbin/httpd -k start
14074 /usr/sbin/httpd -k start
14075 /usr/sbin/httpd -k start
14076 /usr/sbin/httpd -k start
14197 /usr/sbin/httpd -k start
14387 /usr/sbin/httpd -k start
23047 /usr/sbin/httpd -k start
```

またプロセスが使用しているポートを知りたい場合は `lsof` コマンドが使えます。

```bash
$ sudo lsof -i:80 -P
COMMAND   PID   USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
httpd   14071 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14072 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14073 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14074 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14075 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14076 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14197 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   14387 apache    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
httpd   23047   root    3u  IPv4 174132163      0t0  TCP *:80 (LISTEN)
```

ここでもし 80 番ポートを使用しているプロセスの絶対パスを知りたいとなると 2 つのコマンドの出力結果から PID を突き合わせて情報を取得することになります。しかし Linux コマンドの出力結果はあまりパースしやすい形式で作られてないことが多いため、取得したい情報によっては複雑なシェル芸を書いてしまうことがあります。

こういうときに `osquery` を使うと、SQL 構文を使って欲しい情報を簡単に得ることができます。

## インストール

`osquery` の [Downloads] ページの説明に従ってインストールします。
下記は CentOS で実行する場合です。その他の OS については [Downloads] の内容を参考にインストールしてください。

[Downloads]: https://osquery.io/downloads/official/3.2.6

```bash
$ curl -L https://pkg.osquery.io/rpm/GPG | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-osquery
$ sudo yum-config-manager --add-repo https://pkg.osquery.io/rpm/osquery-s3-rpm.repo
$ sudo yum-config-manager --enable osquery-s3-rpm
$ sudo yum install osquery
```

## 使い方

`httpd` という名前のプロセスの情報は、次のような SQL で取得できます。

```bash
$ osqueryi --json "SELECT pid, name, cmdline  FROM processes WHERE name = 'httpd';"
[
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14071"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14072"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14073"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14074"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14075"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14076"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14197"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"14387"},
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"23047"}
]
```

`processes` というテーブルを参照してプロセスの情報が取得できます。実際にそのようなテーブルが DB に作られているわけではなく、あくまでも Linux コマンドのラッパのように振る舞います。

80 番ポートを使用しているプロセスの情報は、次のような SQL で取得できます。
（ポートの情報を取得するには root 権限が必要です）

```bash
$ sudo osqueryi --json "SELECT pid, port FROM listening_ports WHERE port = 80;"
[
  {"pid":"23047","port":"80"}
]
```

80 番ポートを使用しているプロセスの絶対パスを取得したければ `processes` テーブルと
`listening_ports` テーブルを JOIN することで取得できます。

```bash
$ sudo osqueryi --json "SELECT pid, name, cmdline, port FROM listening_ports INNER JOIN processes USING(pid) WHERE port = 80;"
[
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"23047","port":"80"}
]
```

SQL はファイルに書くこともできます。ファイルをパイプで `osqueryi` コマンドに渡すことで、引数に SQL を直接指定した場合と同じ結果を得ることができます。

**list-httpd.sql**

```sql
SELECT
    pid,
    name,
    cmdline,
    port
FROM
    listening_ports
        INNER JOIN processes USING(pid)
WHERE
    port = 80;
```

```bash
$ cat list-httpd.sql | sudo osqueryi --json
[
  {"cmdline":"/usr/sbin/httpd -k start","name":"httpd","pid":"23047","port":"80"}
]
```

`processes, listening_ports` 以外にどのようなテーブルを参照できるかは、公式サイトにある [Schema ドキュメント] にまとまっています。OS によって使用できるデーブルが異なるので注意してください。

[Schema ドキュメント]: https://osquery.io/schema/

## まとめ

ナビタイムではサーバのデプロイ時に `InSpec` を使ってサーバ構成のテストをしていますが、 `InSpec` コードの煩雑さを減らす目的で `osquery` を使っています。あらゆる情報が SQL と JSON で取得できるとかなりシンプルなチェックができるようになりますのでぜひお試しください。

[こちら]: (TODO)

## 参考

- [osquery] - 公式

[osquery]: https://osquery.io/