shawkを動かしてみた

このブログは僕が yuuk1/shawk を動かしてみただけのブログで、技術的に得られる情報は少ないです。もしなにかを求められてきた方は、こちらの動画でなにかを得てください。

ということでやっていきましょう。上記のソフトウェアは下記の資料の実装体です。

僕のモチベーションとしてはペパボのサーバ間ネットワークをゼロトラストネットワークを前提として再構築する際に、既存のサーバ間がどのように通信しているのかを洗い出すためであったり、不正な通信の検知をできないかというちょっともとの研究とはそれた使い方かもしれません。

自分で使うとなると、僕の背景からはeBPFを利用するにはカーネルのバージョンアップを途方も無い台数実行必要が生まれるため、そのときはカーネルモジュールでの実装やauditdでの実装をコントリビュートする必要があるだろうなと思ったりもした。

そして、どうせブログ書くからrpm/debパッケージ作ったり、docker-compose.ymlでも書くかと思ってたいのですが、それもすでにあったので動かすだけでした。

まずはバイナリ作っていきましょう。

% make all

ほいで、docker-composeあるんで使っていきます。

% docker-compose up
shawk_db_1 is up-to-date
Starting shawk_agent_1 ... error

ERROR: for shawk_agent_1  Cannot start service agent: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/go/bin/shawk\": stat /go/bin/shawk: no such file or directory": unknown

ERROR: for agent  Cannot start service agent: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/go/bin/shawk\": stat /go/bin/shawk: no such file or directory": unknown
ERROR: Encountered errors while bringing up the project.

あー、これdocker-composeは別途buildしろってことか。

% docker-compose build
db uses an image, skipping
Building agent
Step 1/3 : FROM golang:1.14.2
 ---> 2421885b04da
Step 2/3 : ENV PKG github.com/yuuki/shawk
 ---> Using cache
 ---> eff5000775c7
Step 3/3 : WORKDIR /go/src/$PKG
 ---> Using cache
 ---> 141e5f1d2e8f

Successfully built 141e5f1d2e8f
Successfully tagged shawk_agent:latest
% docker-compose up
shawk_db_1 is up-to-date
Starting shawk_agent_1 ... error

ERROR: for shawk_agent_1  Cannot start service agent: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/go/bin/shawk\": stat /go/bin/shawk: no such file or directory": unknown

ERROR: for agent  Cannot start service agent: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/go/bin/shawk\": stat /go/bin/shawk: no such file or directory": unknown
ERROR: Encountered errors while bringing up the project.

あかんな。これbuildしたバイナリもっていかないかん。

    volumes:
      - ./shawk:/go/bin/shawk

雑に追加。

% docker-compose up
shawk_db_1 is up-to-date
Recreating shawk_agent_1 ... done
Attaching to shawk_db_1, shawk_agent_1
db_1     | Error: Database is uninitialized and superuser password is not specified.
db_1     |        You must specify POSTGRES_PASSWORD to a non-empty value for the
db_1     |        superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
db_1     |
db_1     |        You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
db_1     |        connections without a password. This is *not* recommended.
db_1     |
db_1     |        See PostgreSQL documentation about "trust":
db_1     |        https://www.postgresql.org/docs/current/auth-trust.html
d

fmfm.ということで、dbのパスワード追加したり、環境変数入れたり。

services:
  agent:
    build: .
    depends_on:
      - db
    entrypoint: /go/bin/shawk probe
    command: ["--dbhost", "db"]
    volumes:
      - ./shawk:/go/bin/shawk
    environment:
      - SHAWK_CMDB_URL=postgres://shawk:shawk@db:5432/shawk?sslmode=disable
  db:
    image: postgres:11.7
    ports:
      - 5432
    environment:
      - POSTGRES_USER=shawk
      - POSTGRES_DB=shawk
      - POSTGRES_PASSWORD=shawk
    restart: always
    user: postgres
    volumes:
      - ./postgres/init:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ttracer"]
      interval: 3s
      timeout: 3s
      retries: 5
      start_period: 3s

そうすると、

agent_1  | flag provided but not defined: -dbhost
agent_1  |
agent_1  | Usage: shawk probe [options]
agent_1  |
agent_1  | start agent for collecting flows and processes.
agent_1  |
agent_1  | Options:
agent_1  |   --env
agent_1  |   --once                    run once only if --mode='polling'
agent_1  | flag provided but not defined: -dbhost
shawk_agent_1 exited with code 11

引き数変わったっぽいのでdbhostを削ってと。。

(⎈ |nks-production:drone)[13:52:25] ~/src/github.com/yuuki/shawk (not-exist-task) <U>
% docker-compose up
Starting shawk_db_1 ... done
Starting shawk_agent_1 ... done
Attaching to shawk_db_1, shawk_agent_1
db_1     |
db_1     | PostgreSQL Database directory appears to contain a database; Skipping initialization
db_1     |
db_1     | 2020-05-09 04:52:37.680 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
db_1     | 2020-05-09 04:52:37.680 UTC [1] LOG:  listening on IPv6 address "::", port 5432
db_1     | 2020-05-09 04:52:37.689 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1     | 2020-05-09 04:52:37.726 UTC [12] LOG:  database system was interrupted; last known up at 2020-05-09 04:50:50 UTC
db_1     | 2020-05-09 04:52:38.001 UTC [12] LOG:  database system was not properly shut down; automatic recovery in progress
db_1     | 2020-05-09 04:52:38.005 UTC [12] LOG:  redo starts at 0/16517C0
db_1     | 2020-05-09 04:52:38.005 UTC [12] LOG:  invalid record length at 0/16517F8: wanted 24, got 0
db_1     | 2020-05-09 04:52:38.005 UTC [12] LOG:  redo done at 0/16517C0
db_1     | 2020-05-09 04:52:38.033 UTC [1] LOG:  database system is ready to accept connections
agent_1  | 2020/05/09 04:52:38 INFO <command> --> Connecting postgres ...
agent_1  | 2020/05/09 04:52:38 INFO <command> Connected postgres
db_1     | 2020-05-09 04:52:40.725 UTC [26] FATAL:  role "ttracer" does not exist
db_1     | 2020-05-09 04:52:43.874 UTC [33] FATAL:  role "ttracer" does not exist

[kkkdb_1     | 2020-05-09 04:52:47.025 UTC [41] FATAL:  role "ttracer" does not exist
db_1     | 2020-05-09 04:52:50.187 UTC [48] FATAL:  role "ttracer" does not exist
db_1     | 2020-05-09 04:52:53.331 UTC [55] FATAL:  role "ttracer" does not exist

ああ、上がったけどdbのヘルスチェックが前の名前のままだったから、shawkに変える。

ここまでで1PRなげた。

db_1     |
db_1     | PostgreSQL Database directory appears to contain a database; Skipping initialization
db_1     |
db_1     | 2020-05-09 04:53:37.694 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
db_1     | 2020-05-09 04:53:37.695 UTC [1] LOG:  listening on IPv6 address "::", port 5432
db_1     | 2020-05-09 04:53:37.699 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1     | 2020-05-09 04:53:37.746 UTC [12] LOG:  database system was shut down at 2020-05-09 04:53:32 UTC
db_1     | 2020-05-09 04:53:37.760 UTC [1] LOG:  database system is ready to accept connections
agent_1  | 2020/05/09 04:53:38 INFO <command> --> Connecting postgres ...
agent_1  | 2020/05/09 04:53:38 INFO <command> Connected postgres

db_1     | 2020-05-09 04:54:08.426 UTC [19] ERROR:  relation "processes" does not exist at character 16
db_1     | 2020-05-09 04:54:08.426 UTC [19] STATEMENT:
db_1     |                      INSERT INTO processes (ipv4, pgid, pname, updated)
db_1     |                      VALUES ($1, $2, $3, CURRENT_TIMESTAMP)
db_1     |                      ON CONFLICT (ipv4, pgid, pname)
db_1     |                      DO UPDATE SET updated=CURRENT_TIMESTAMP
db_1     |                      RETURNING process_id
db_1     |
agent_1  | 2020/05/09 04:54:08 ERROR <agent/polling> query error:
agent_1  |     github.com/yuuki/shawk/db.(*DB).InsertOrUpdateHostFlows
agent_1  |         /go/src/github.com/yuuki/shawk/db/db.go:189

なるほどなぁ、スキーマが初期化されてなさそう。

多分このあたりを実行しないといけない。

    command: bash -c "/go/bin/shawk create-scheme && /go/bin/shawk probe"

ソフトウェアの性質上、docker-composeはシュッと試したいときに使うものだから雑にbashでやっつけた。

ホイで起動したから雑に試すためにdocker exec bin/bashしてnetcatいれちゃうぞ〜。

$ apt install netcat
$ nc -l -p 11111     # listenしておいて
$ nc localhost 11111 # 接続する
$ /go/bin/shawk look

ここで、接続情報出るんかなぁと思ってたけどそんなことなかった。

なんでやねーーんと思ってたら、

agent_1  | 2020/05/09 05:14:57 ERROR <agent/polling> readlink /proc/58/fd/0:
agent_1  |     github.com/yuuki/shawk/probe/netlink/netutil.BuildUserEntries
agent_1  |         /go/src/github.com/yuuki/shawk/probe/netlink/netutil/netutil_linux.go:349
agent_1  |   - readlink /proc/58/fd/0: permission denied

なるほどね。でもこれコンテナのprocだから特権いらなさそうだけどな。fd0だから標準入力見ようとしてんのかな。

あらためて、lookをip指定で見たらみれた。

root@615b76a8b754:/go/src/github.com/yuuki/shawk# /go/bin/shawk look  --ipv4 172.19.0.3
172.19.0.3:55562 ('', pgid=0)
└<-- 172.19.0.3:many ('nc', pgid=505)
172.19.0.3 ('', pgid=0)
└--> 172.19.0.2:5432 ('', pgid=0)
172.19.0.3 ('nc', pgid=505)
└--> 172.19.0.3:55562 ('', pgid=0)
root@615b76a8b754:/go/src/github.com/yuuki/shawk# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 05:12 ?        00:00:05 /go/bin/shawk probe
root        22     0  0 05:14 pts/0    00:00:00 /bin/bash
root        47     0  0 05:14 pts/1    00:00:00 /bin/bash
root       381     0  0 05:16 pts/2    00:00:00 /bin/bash
root       505    47  0 05:24 pts/1    00:00:00 nc -l -p 11111
root       507   381  0 05:24 pts/2    00:00:00 nc 172.19.0.3 11111
root       560    22  0 05:26 pts/0    00:00:00 ps -ef
root@615b76a8b754:/go/src/github.com/yuuki/shawk#

これ11111ポートの情報はでないんかな。情報の出し方的には 172.19.0.3:many の場所が 172.19.0.3:11111 で良さそうだけどなんでやろか。

root@615b76a8b754:/go/src/github.com/yuuki/shawk# /go/bin/shawk look  --ipv4 172.19.0.3
172.19.0.3:55562 ('', pgid=0)
└<-- 172.19.0.3:many ('nc', pgid=505)
172.19.0.3 ('', pgid=0)
└--> 172.19.0.2:5432 ('', pgid=0)
172.19.0.3 ('nc', pgid=507)
└--> 172.19.0.3:11111 ('', pgid=0)
root@615b76a8b754:/go/src/github.com/yuuki/shawk# /go/bin/shawk look  --ipv4 172.19.0.3
172.19.0.3:55562 ('', pgid=0)
└<-- 172.19.0.3:many ('nc', pgid=505)
172.19.0.3 ('', pgid=0)
└--> 172.19.0.2:5432 ('', pgid=0)
172.19.0.3 ('nc', pgid=505)
└--> 172.19.0.3:55562 ('', pgid=0)

コネクション自体は繋ぎっぱなしで、何回か実行してると結果が変わるっぽい。これはなんかポーリング間隔によって得られる情報が違うからなんだろう。openしか取ってないとするとあり得るから、ストリーミングモードでやると多分ちゃんと取れそう。

最後に

一通り動かしてみて、PRもさっきマージされてました。yuukiくんも書いてるようにパフォーマンスとのトレードオフになる部分はあれど、僕が思ってる用途や他の用途にも使えそうだった。それこそグラフ図にするとホスト間の依存を図示することもできるだろうし、CMDBがあるから基本ソフトウェアとして使い手のアイディア次第で可能性のあるソフトウェアだと思った。