🦆

CloudShell 上の DuckDB に VPC フローログを取り込んでみた

に公開

皆さんは、AWS の VPC フローログを取得していますでしょうか?
おそらく、取っている方が多いのかなと思っています。

以前、DuckDB に関する記事をいくつか書きました。
その中で以下の記事では、AWS の CloudShell に DuckDB を入れて、S3 の ALB のログを SQL ライクに参照する話を書きました。

https://zenn.dev/babyjob/articles/mackey0225-use-duckdb-in-cloudshell

今回はその VPC フローログ版になります。

本題の前の簡単な説明

VPC フローログとは

https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html

VPC フローログは、VPC のネットワークインターフェイスとの間で行き来する IP トラフィックに関する情報をキャプチャできるようにする機能です。

上記の通り、VPC フローログとは、AWS VPC 内の IP トラフィックのログとその取得する機能を指します。

例えば、ALB から EC2 への IP パケットの状況や、ECS のコンテナから別のコンテナへの通信などを捕捉して、正常に通信がされているかを確認することができます。

ログ自体は、CloudWatch Logs や S3、Data Firehose への発行が可能です。

今回は、S3 に発行されたログを CloudShell 上の DuckDB を使って整形します。

また、この記事では、VPC フローログの設定については割愛します。

DuckDB とは

DuckDB とは、オープンソースの組み込み型 OLAP (Online Analytical Processing) SQLデータベース管理システム(DBMS)です。

詳細は上にも挙げた過去記事にも書いたり、色んな方が詳しく説明されているので、そちらに委ねるとして、、、
個人的なオススメとしては、複雑な設定など無く、様々な環境で利用が簡単にできること です。

また、バージョン 1.2.1 から DuckDB UI という UI 機能が追加され、より便利になったと感じています。[1]

本題

実行にあたっての前提や準備

DuckDB について

使用する DuckDB のバージョンは 1.2.1 です。
https://github.com/duckdb/duckdb/releases/tag/v1.2.1

なので、CloudShell で使う際のコマンドは以下になります。

curl -LO https://github.com/duckdb/duckdb/releases/download/v1.2.1/duckdb_cli-linux-amd64.zip
unzip duckdb_cli-linux-amd64.zip
./duckdb

CloudShell を立ち上げて、上記のコマンドを入れると、DuckDB が立ち上がります。

CloudShell で DuckDB の導入🦆上のコマンド実施した結果🦆

VPC フローログについて

今回、VPC フローログはデフォルトの形式のものを使います。
具体的には、以下のドキュメントに書かれているバージョン 2 のもので、項目としては version から log-status の 14 項目を出力したものを対象にしています。

https://docs.aws.amazon.com/vpc/latest/userguide/flow-log-records.html#flow-logs-fields

また、冒頭にも挙げた通り、S3 に発行したものを使いますが、発行するログファイル形式は Text のものを使用します。
S3 への出力に関しては、Text 形式以外にも、Parquet 形式も出力可能です。

ちなみにですが、Parquet 形式であれば DuckDB でそのまま扱うことができます。

扱うログファイルのイメージは以下のとおりです。

フローログのファイルのイメージ
version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status
2 000000000000 eni-01234567890123456 10.0.0.1 10.0.0.2 443 443 6 1 123 1743476400 1743476700 ACCEPT OK
2 000000000000 eni-01234567890123456 10.0.0.3 10.0.0.1 443 443 6 12 12345 1743476400 1743476700 ACCEPT OK
2 000000000000 eni-01234567890123456 10.0.0.1 10.0.0.5 443 443 6 2 1234 1743476400 1743476700 ACCEPT OK
2 000000000000 eni-01234567890123456 10.0.0.4 10.0.0.1 443 443 6 23 12 1743476400 1743476700 ACCEPT OK
2 000000000000 eni-01234567890123456 10.0.0.1 10.0.0.3 443 443 6 38 1234 1743476400 1743476700 ACCEPT OK
2 000000000000 eni-01234567890123456 10.0.0.6 10.0.0.1 443 443 6 2 123 1743476400 1743476700 ACCEPT OK
2 000000000000 eni-01234567890123456 10.0.0.5 10.0.0.1 443 443 6 29 1234 1743476400 1743476700 ACCEPT OK

いざ実践!

S3 からログファイルの取得

CloudShell にログファイルをダウンロードするには、AWS CLI の aws s3 cp を使用します。
あくまでも例ですが、以下のようなコマンドになります。[2]

aws s3 cp のイメージ
aws s3 cp s3://<S3_BUCKET>/AWSLogs/<ACCOUNT_ID>/vpcflowlogs/<REGION>/YYYY/MM/DD/ ./ --recursive

取得したログを CloudShell でテーブル化

CloudShell で先程導入した DuckDB を立ち上げて、以下の SQL を実行します。

テーブル化するための SQL
CREATE TABLE vpc_flow_logs AS
    SELECT 
        "version",
        "account-id",
        "interface-id",
        "srcaddr",
        "dstaddr",
        "srcport",
        "dstport",
        "protocol",
        "packets",
        "bytes",
        -- (1)start と end は UNIX 時間なので、9時間足す。
        to_timestamp("start") + INTERVAL 9 HOUR AS start_jst, 
        to_timestamp("end") + INTERVAL 9 HOUR AS end_jst,
        "action",
        "log-status"
    FROM read_csv(
        './*.gz', -- (2)ワイルドカードが使える
        columns={
            'version': 'VARCHAR',
            'account-id': 'VARCHAR',
            'interface-id': 'VARCHAR',
            'srcaddr': 'VARCHAR',
            'dstaddr': 'VARCHAR',
            'srcport': 'VARCHAR',  -- (3)致し方なく VARCHAR で定義
            'dstport': 'VARCHAR',  -- (3)致し方なく VARCHAR で定義
            'protocol': 'VARCHAR', -- (3)致し方なく VARCHAR で定義
            'packets': 'VARCHAR',  -- (3)致し方なく VARCHAR で定義
            'bytes': 'VARCHAR',    -- (3)致し方なく VARCHAR で定義
            'start': 'BIGINT',
            'end': 'BIGINT',
            'action': 'VARCHAR',
            'log-status': 'VARCHAR'
        },
        delim=' ',
        quote='"',
        escape='"',
        header=True,
        auto_detect=False
    );

細かいですが、上記の SQL に関しての補足説明です。

補足説明(1) データの整形も可能

UNIX 時間だと、人間が扱うには難しいので、to_timestamp 関数を使って変換しています。
加えて、タイムゾーンの考慮も含めて、9時間を足して、日本時間にしています。

補足説明(2) ファイルの指定でワイルドカードが使える

上記のファイルの指定でワイルドカードが使えるので、すべてのファイルパスを記載せずに S3 から取得したすべてのログファイルを1つのテーブルにすることが可能です。
(トータルで100万行ぐらいであれば、数秒でテーブル化できます。)

補足説明(3) 数値のデータ型でもパケットが無い場合は - となる

これは、VPC フローログの仕様の話ですが、
本来はポートやバイト数などは数値なので、INTEGERBIGINT にしたいところですが、該当時間間隔内にログがないと - となるため、致し方なく VARCHAR にしています。[3]

テーブル化した中身の確認

テーブル化すると、中身の確認ができます。

DuckDB では、FROM-first syntax があり、以下の SQL で全件の参照ができます。(表示できる件数の上限はありますが。。。)

FROM-first syntax での SELECT 文
FROM vpc_flow_logs; -- SELECT * FROM vpc_flow_logs; と同じ。

ここまで、問題なく行けば、あとは 煮るなり、焼くなり、二宮和なり です。

IP アドレスでフィルタリングしたり、CSV に書き出したり、確認したいことに応じて SQL ライクに操作ができます!٩(๑>∀<๑)۶

まとめ

今回、DuckDB を CloudShell 上で使うことで Athena の簡易的な代替にすることができるので、運用開始当初のスモールスタートであれば、使い勝手のいい選択肢だと感じました。
また、この記事では紹介していないですが、DuckDB は Parquet 形式も扱うことができるので、今後はそのケースもどこかでやってみたいと思いました。

脚注
  1. これについても、簡単に紹介したいなー。たとえ何番煎じだとしても。。。 ↩︎

  2. --recursive オプションを付けて、該当の日付をまるごと取ってきていますが、必要に応じて変えてください。 ↩︎

  3. 誰かいい方法あれば教えて! ↩︎

BABY JOB  テックブログ

Discussion