「Linux Kernelに脆弱性が見つかった… 管理している大量のサーバのカーネルバージョンを取得してリスト化したい…」 そんな時にあなたならどうしますか? 1台1台SSHでログインして uname -r を叩くシェルスクリプトを作るのは汎用性が有りますが、遅い・エラーハンドリング・ホストのリストの管理・権限の管理等、様々な問題にぶつかると思います。

今回は、そんな問題を解決するためのツール達を紹介します。

osquery

https://osquery.io/

osqueryはSQLでマシンの様々な情報を取得するためのツールです。 ユーザが理解しやすいSQLで、セキュリティ・監査・DevOps等をサポートします。 Facebookが開発しており、コードはGithub上で公開されています。 対応プラットフォームはLinux, Windows, macOSと幅広いです。 osquery単体ではインストールした1台のマシンに対してのみクエリを行うことが出来ます。

https://github.com/osquery/osquery

まずはインストールして試してみましょう。 .rpm .tar.gz .msi などのパッケージや、brew, aptなどの各プラットフォーム向けのリポジトリが用意されています。 私は手っ取り早く試したかったので、 .tar.gz を手元のUbuntuマシンで展開しました。

https://osquery.io/downloads

$ wget https://pkg.osquery.io/linux/osquery-3.3.2_1.linux_x86_64.tar.gz
$ mkdir osquery
$ tar xf osquery-3.3.2_1.linux_x86_64.tar.gz -C ./osquery

インストールを行うと、3つのコマンドが利用可能になります。

  • osqueryi
    • インタラクティブなシェルを提供するCLIコマンド
    • 完全に独立して動作し、デーモンと通信することもなくマシンの情報を収集する
    • 管理者権限として実行する必要はない
  • osqueryd
    • 設定ファイルに記述されたクエリを定期的に実行するデーモン
    • OSの状態変化を記録することが出来る
    • 今回は使用しない
  • osqueryctl
    • osquerydの開始・終了・設定のチェックが行える
    • 今回は使用しない

今回はosqueryi単体で試してみます。 まずは手始めにOSのバージョンを取得してみます。 ここでは引数にSQLを渡しますが、引数無しで実行することでインタラクティブシェルに入ることも出来ます。

$ osqueryi "SELECT * FROM os_version;"
+--------+----------------------------+-------+-------+-------+-------+----------+---------------+----------+
| name   | version                    | major | minor | patch | build | platform | platform_like | codename |
+--------+----------------------------+-------+-------+-------+-------+----------+---------------+----------+
| Ubuntu | 16.04.1 LTS (Xenial Xerus) | 16    | 4     | 0     |       | ubuntu   | debian        | xenial   |
+--------+----------------------------+-------+-------+-------+-------+----------+---------------+----------+

利用可能なテーブルについての情報は、公式サイトのリファレンスで確認します。 sysctlなどのOS関連・debなどのパッケージマネージャ・Dockerなどのミドルウェアを始めとする様々な情報が取得可能であることが分かります。https://osquery.io/schema

SQLで利用可能な構文は、SQLiteで利用可能なものです。 必要であればJOIN等も行うことが出来ます。http://www.sqlite.org/lang.html

osqueryを複数サーバで実行したい

今紹介したosqueryは、単一のマシンの情報を取得するためのツールでした。 例えば100台のサーバにインストールすると、SQLでOSの情報を一括で取得できて便利そうです。 そういったニーズに応えるのが、Kolide FleetとKolide Launcherです。

各コンポーネントの関係・通信の流れはこのようになります。

  1. ユーザはブラウザを使用してクエリの入力・対象マシンの選択を行う
  2. Kolide Fleetが対象マシンに対してクエリを送信する
  3. 各マシンで動作するKolide Launcherが、osqueryにクエリする
  4. クエリ結果をKolide Fleetに返却する
  5. 複数マシンからのレスポンスを集計し、ユーザのブラウザに返却する

Kolide Fleet

Kolideは利便性を重視したセキュリティ監査のためのプラットフォームです。 2019年7月現在、1台のデバイス・月額あたり6USDの有償サービスです。 Kolide Launcher というエージェントをOSにインストールし、マシン毎の数千の情報をクラウド上のサーバに送信することで、ダッシュボード・Slackなどを通じて情報を得ることが出来ます。 例えば、従業員の全てのPCにインストールすることで、「ディスクを暗号化していないマシン」「Chromeで危険な拡張機能を入れているマシン」などのリストを取得することが可能です。

こうしたOS上の情報を収集するために、先ほど紹介したosqueryを使用しています。 決められた情報を定期的に収集する・必要な時に迅速にマシンから任意の情報を収集するという、2つのワークロードへ非常にマッチしていると感じます。

Kolideの機能を詳しく知りたい場合は、公式サイトから無償体験が行えるようです。 https://kolide.com/

この便利なプラットフォームであるKolideの機能を減らして自分のオンプレ環境で動かせるようにしたOSSがKolide Fleetです。 先程紹介したようなSlack連携などの便利そうな機能は無いものの、複数マシンのosqueryに対してSQLを送信して情報を収集することができます。

Kolide Fleetのインストール

OSS版のKolide Fleetをdocker-composeで動作させてみましょう。 動作条件は以下のとおりです。

  • Docker, Docker Compose
  • サーバへのドメイン名の割当 (ここではkolide-fleet.example.comとします)
  • TLS証明書

TLSの利用が必須なので、自己署名証明書を生成します。 本番環境であれば、Let’s Encrypt等を利用できるかと思います。

$ mkdir keys
$ openssl genrsa 2048 > keys/server.key
$ openssl req -new -key keys/server.key > keys/server.csr
$ openssl x509 -days 3650 -req -signkey keys/server.key < keys/server.csr > keys/server.crt

以下は必要となるDockerComposeファイル・設定ファイルです。 パスワード等は仮で設定しています。実際に試す際は変更を推奨します。

# docker-compose.yml
version: '3'
services:
  mysql:
    image: mysql:5.7
    command: mysqld --datadir=/tmp/mysqldata
    environment:
      MYSQL_ROOT_PASSWORD: toor
      MYSQL_DATABASE: kolide
      MYSQL_USER: kolide
      MYSQL_PASSWORD: kolide
      TZ: 'Asia/Tokyo'
    volumes:
      - mysqldata:/tmp
    expose:
      - "3306"
  redis:
    image: redis:5.0
    expose:
      - "6379"
  fleet:
    image: kolide/fleet:latest
    command: sh -c "echo '\n' | /usr/bin/fleet prepare db --config=/tmp/kolide.yml && /usr/bin/fleet serve --config=/tmp/kolide.yml"
    depends_on:
      - mysql
      - redis
    volumes:
      - .:/tmp
    ports:
      - "443:443"
volumes:
  mysqldata: {}
# kolide.yml
mysql:
  address: mysql:3306
  database: kolide
  username: kolide
  password: kolide
redis:
  address: redis:6379
server:
  address: 0.0.0.0:443
  tls: true
  key: /tmp/keys/server.key
  cert: /tmp/keys/server.crt
logging:
  json: true
  debug: false
auth:
  jwt_key: changeme

docker-compose up でサービスを起動後、ブラウザで https://kolide-fleet.example.com/ のようにアクセスすると管理画面が表示されます。 各種登録を済ませるとホスト一覧画面が表示されます。

Add New Host をクリックして Enroll Secret を取得しておきます。

Kolide Launcher

クラウドサービスのKolideや、オンプレ環境のKolide Fleetに情報を送信するためのエージェントがKolide Launcherです。 osqueryのデーモンであるosquerydとKolideの通信を橋渡しするコンポーネントです。 大規模な利用でのインストール・更新・設定が簡単になります。

こちらは残念ながらOSSとしては便利なインストーラー等が用意されていないので、GithubのRelease上からZIPファイルをダウンロードしてインストールします。 各プラットフォーム向けの launcher 実行ファイル・ osqueryd osquery-extension.ext のデーモン等が同包されています。

https://github.com/kolide/launcher/releases

$ wget https://github.com/kolide/launcher/releases/download/0.10.2/launcher_0.10.2.zip
$ unzip launcher_0.10.2.zip
$ ls launcher_0.10.2/linux/
launcher  osqueryd  osquery-extension.ext

launcherの起動を行うには、先程建てたKolide Fleetサーバのホスト名とEnroll Secretを指定する必要があります。 今回はサーバ証明書に自己署名証明書を導入しているので --insecure オプションを追加していますが、本番環境であれば外すべきでしょう。

launcher \
  --hostname=kolide-fleet.example.com:443 \
  --enroll_secret=32IeN3QLgckHUmMD3iW40kyLdNJcGzP5 \
  --insecure

設定がうまく行っていれば、すぐにKolide Fleetの管理画面にホストが表示されます。 数台入れておくとクエリを行う際に楽しいので、数台サーバを用意することをおすすめします。

ダッシュボードの操作

まずは単純なクエリを実行してみましょう。 QUERY タブ→CREATE NEW QUERYボタンをクリックします。

デフォルトで入力されている SELECT * FROM osquery_info を全てのノードに対して実行してみましょう。 Select Targetsで All Hosts の右にある + ボタンをクリックします。 あとは RUN ボタンをクリックすれば全てのノードでSQLが実行されます。

試しに60台ほどのマシンで試してみましたが、クエリは数秒で完了しました。

クエリを書く

osqueryでは、sysctlなどのOS関連・debなどのパッケージマネージャ・Dockerなどのミドルウェアを始めとする様々な情報が取得可能です。 Kolide Fleetでは、osqueryが扱うその全てが取得可能です。 テーブルの一覧はこちらです。https://osquery.io/schema/

クエリの例を何個か載せておきます。

SELECT * FROM os_version;  -- OSバージョンを取得する
SELECT * FROM docker_containers;  -- Docker上で動作しているコンテナを取得する
SELECT * FROM system_controls where name = "vm.max_map_count";  -- カーネルパラメータを取得する
SELECT * FROM file WHERE path = '/etc/nginx/nginx.conf';  -- 指定されたパスのファイル情報を取得する

冒頭に書いていたLinux Kernelのバージョンを調べるためのSQLはこのようになります。

SELECT version FROM kernel_info;

最後に

弊社で提供しているIoTサービスである「sakura.io」のサーバ管理の省力化を行うために調べていた結果、見つけたプロダクトがosquery・それを活用するKolide Fleetでした。 プロダクトの成長と共に徐々にサーバの台数も増加しており、一部のミドルウェア・ライブラリのバージョンが揃っていない場合が有りました。 そういった場合に、エンジニアが数分で目的の情報を手軽に得ることが出来る環境が整いました。 メトリクス監視・ログ収集などのツールと組み合わせることで、障害発生時のオペレーションも効率的に行えるようになると感じます。

さくらインターネットでは、sakura.ioを始めとした様々なサービスを作る仲間を募集しています。 興味が有る方は https://www.sakura.ad.jp/recruit/ から採用情報をチェックしてください!