Splunk Federated Search for S3 で大容量かつ低頻度なアクセスデータに対してコストを最小にSIEM機能を活用する
データ分析の効果を最大化し、データ分析を効率化するには、組織内に散在する様々なデータの管理を一元化し統合データ分析プラットフォームを利用することが重要です。
しかし、データ分析プラットフォームに無限にデータを取り込むことは難しく、多くのサービスは取り込みデータ量に対してライセンス費用の大きなウェイトを占めるため、大容量かつ低頻度なアクセスデータの取り込みは諦めるほかありませんでした。
一方、データを安価で手軽に保管するサービス Amazon S3 は AWS の代表的なサービスとして広く利用されています。
Splunk Federated Search for S3 は Amazon S3 内に保管されたデータを Splunk Cloud から直接クエリをかけて検索結果を得ることができるサービスです。
Splunk Federated Search for S3 を利用するための Amazon S3 へのデータの取り込みと、どの程度のパフォーマンスで分析することができるのかをポイントにして、確認していきたいと思います。
Ingest Actions で Amazon S3 にデータを転送する
Ingest Actions は Splunk Cloud または Splunk Enterprise に送信したストリーミングデータをSplunkのIndexerに取り込む前に、フィルタリングやマスク、別のストレージロケーションに転送することができます。
Ingest Actions は Amazon S3 への転送がサポートされているので、この機能を使って、着信するデータを Splunk に取り込まずに全て転送したいと思います。
この場合、取り込みインジェストのライセンスを消費することがないので、はじめはSplunkに取り込んでいたが頻繁に分析する必要がなくなったデータの格納先を変えたり、Amazon S3への大容量なデータの転送に Splunk のエージェント(Universal Forwarder)を活用することも可能です。
Ingest Actions の設定
では設定します。
ここでは、Universal ForwarderはSplunk Cloudへデータを送信するようにあらかじめ設定済みの環境から設定をはじめていきます。
Splunk CloudのWebポータルにログインします。
設定 > 取り込みアクション を選択します。
Destination > Create New Destination を選択します。
以下設定していきます。
Destination Title: 任意
S3 Bucket Name: プレフィックスが自動で付与されているので、好きな文字列を入れて、転送するAmazon S3バケット名を決めます。
S3 Folder: データを格納するバケットのパスを入力
Partitioning: データを格納するパケットのパスを日付またはソースタイプ名でパーティションとして作成することができます。今回はLegacyを選択しました。
Encryption: KMSやSSE-S3での暗号化を設定する場合は必須です
Generate Bucket Policy をクリックすると、クロスアカウントアクセスのためのバケットポリシーが表示されるので、コピーしておきます。
この値を、利用しているAWSのアカウントで設定しますが、まず先ほど決めたバケット名でS3バケットを作成します。
こちらですね。
AWSコンソールにログインしたら、まずSplunk Cloudがデプロイされているリージョンと同じことを確認してください。
Federated Search for S3 の制約に、Splunk Cloudのリージョンと、データを保管しているS3のリージョンが同じである必要があるため、ここで保管する先のS3が同じリージョンであることを確認しておきます。
S3名を入れてバケットを作成します。(その他特に設定する必要はありませんが、バケットの暗号化設定は任意で行ってください)
先ほどコピーしていたバケットポリシーを設定するので、アクセス許可の設定をします。
ポリシーを設定し、保存します。
再度、Splunk CloudのWebポータルに戻って、詳細設定のトグルを開き、フォーマットを Raw、圧縮を gzip で設定します。
バケットポリシーがきちんと設定されていれば、Test Connection で成功しますので、設定を保存します。
Rulesets > New Ruleset を選択します。
Sourcetype を転送したいログに合わせます。今回はapache accessログを想定しているため、「access_combined」を選択して、Sample を押すと、取れているデータが表示されます。
Add Ruleを選択します。
Route to destination を選択すると、Condition を None にして、設定した Amazon S3 を選択します。
これで、「access_combined」のソースタイプは全て Splunk Cloud には取り込まれずにS3に転送されるようになります。
ログが出力されるとほぼリアルタイムにS3バケットに日付のパスが生成され、オブジェクトが保存されだします。
きちんと圧縮もされています。
AWS Glue のテーブルを作成する
こちらのブログでも書きましたが、AWS Glue のテーブル作成を Athena で行っていきます。
今回は、Apache アクセスログ になるので、いわゆる非構造データを扱います。
Grokパターンを使って設定します。
取り扱うログは以下のようなログです。
160.156.197.88 - - [27/Jan/2025:05:34:10 +0000] "GET /item/giftcards/3030 HTTP/1.1" 200 131 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"
Grokパターンをテストする際には便利なツールとしてGrok Constructorなどがあるので、活用すると良いでしょう。
設定方法などはこちらなどを参考にしてください。
今回は以下のようなGrokパターンで設定します。
'^%{IPORHOST:client_ip} %{USER:client_id} %{USER:user_id} \\[%{HTTPDATE:request_received_time}\\] \"%{WORD:method} %{NOTSPACE:client_request} HTTP/%{NUMBER:http_version}\" %{NUMBER:server_status} %{NUMBER:returned_obj_size} \"%{DATA:http_referer}\" \"%{DATA:user_agent}\"$'
また、Splunk Federated Search for S3 はパーティションによるデータスキャン範囲の絞り込みをサポートしています。
手動によるパーティションと、Amazon Athena のパーティションプロジェクションによるパーティション管理を自動化ができます。
パーティションプロジェクションを利用するとより管理が楽になるので、こちらで設定します。
パーティションについては、Splunk Cloudのデータスキャンライセンスの削減と、検索時間のパフォーマンスに関わってくるので、以下を参考して理解しておくことをおすすめいたします。
最終的に以下のDDLコマンドを Athena で実行しました。
CREATE EXTERNAL TABLE dummy_apache_logs2 (
`client_ip` string,
`client_id` string,
`user_id` string,
`request_received_time` string,
`method` string,
`client_request` string,
`http_version` string,
`server_status` string,
`returned_obj_size` string,
`http_referer` string,
`user_agent` string
)
PARTITIONED BY (
`date` string
)
ROW FORMAT SERDE 'com.amazonaws.glue.serde.GrokSerDe'
WITH SERDEPROPERTIES ( 'input.format'='^%{IPORHOST:client_ip} %{USER:client_id} %{USER:user_id} \\[%{HTTPDATE:request_received_time}\\] \"%{WORD:method} %{NOTSPACE:client_request} HTTP/%{NUMBER:http_version}\" %{NUMBER:server_status} %{NUMBER:returned_obj_size} \"%{DATA:http_referer}\" \"%{DATA:user_agent}\"$' )
STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://<backet>/<path>/'
TBLPROPERTIES (
'projection.enabled'='true',
'projection.date.type' = 'date',
'projection.date.range' = '2025/01/20,Now',
'projection.date.format' = 'yyyy/MM/dd',
'projection.date.interval' = '1',
'projection.date.interval.unit' = 'DAYS',
'storage.location.template' = 's3://<backet>/<path>/${date}'
)
AWS Glue でも作ったテーブルのスキーマを確認することができるので、確認してみます。
それぞれのログのフィールドが定義できているのと、パーティションキーが設定されていることがわかります。
Splunk Federated Search for S3 の設定をする
最後にFederated Search for S3の設定をします。
設定 > 統合サーチ を選択します。
Federated Providers > Add federated provider を選択します。
AWSアカウント、Glue Database、Glue Table、データが格納されているS3ロケーションを設定します。
※S3ロケーションはバケット指定にして設定した時に、この後のSplunk Cloud側のパーミッションのアップデートで失敗してしまう事象となりました。パスも指定したところ、うまく設定ができたので、もしこの後のパーミッションアップデートで失敗する場合はこの辺りを確認してください。
Generate Policyをクリックすると、Glue テーブルにクロスアカウントでアクセスするための権限ポリシーが表示されるのでコピーします。
AWS Glueで設定します。
Catalog settings でポリシーをペーストして設定を保存します。
次にSplunk CloudのWebポータルに戻って、今度はバケットポリシーをコピーします。
Amazon S3で設定します。
対象のS3バケットのバケットポリシーを編集します。Ingest Actionsで設定した時のバケットポリシーと一部重複しているところがある場合は、差分を追加でポリシーに書き込む形がよいかと思います。
再度、Splunk Cloudの設定で同意にチェックして設定を保存します。
Update Amazon S3 permissions をクリックします。
続いて、インデックスの設定です。
Federated Indexes > Add federated index を選択します。
インデックス名をつけて、それぞれ選択します。
Time settings では、AWS Glueで定義したタイムスタンプをSplunk Cloudでも認識できるようにして、Splunk Cloudで検索時にタイムピッカーが使えるようにします。
AWS Glueのテーブルなどを確認して、タイムフィールドとして抽出したフィールド名を確認し、Time fieldに設定します。
Time format は Splunk Cloud で利用できるタイムフォーマット変数で認識させる必要があります。
今回の例だと 27/Jan/2025:05:34:10 +0000
のような形で、入ってくるので、こちらに併せて設定します。
Unix time field は Splunk Cloud で利用するどのフィールドとマッピングするかを指定するので、Splunk Cloudでデフォルトで使われる「_time」のままがいいです。
最後にパーティションタイムの設定です。
Federated Search for S3では、デフォルトだと Federated Providers で設定したS3ロケーションの全てのデータを対象にスキャンをかけて分析を行います。
上記のタイムフィールドだけ設定している場合も、同様、スキャン対象は全てのデータを対象にしてしまいます。
パーティションタイムAWS Glue(Amazon Athenaで定義したパーティションプロジェクション)で設定したパーティションに従って、スキャン対象を分割することができます。
Time field は Amazon Athenaで定義したパーティションフィールドです。
Time format は パーティションとして認識される文字列をSplunk Cloudのタイムフォーマット変数に併せて認識できるようにします。
今回の例だと 2025/01/27
のようになります。
Type は上記に併せて String が適切です。
S3 のデータを検索してみる
それでは、S3に保管している apache アクセスログを検索してみます。
パーティションによる検索範囲の絞り込みと、検索パフォーマンスがどの程度なのかの観点で確認します。
なお、ドキュメントを確認すると検索パフォーマンスの要因として以下を考慮することが記載されています。
- Amazon S3 のデータ量
- バケット内のオブジェクトの数
- S3バケットのリージョンとSplunk Stackの距離(Federated Search for S3 の制約に同じリージョンがあったはずだけど...
- サーチクエリの複雑性
- データ圧縮
ログファイルは apache-loggen という ruby 製のツールを使って、ダミーデータを生成して大量にログをS3に置いてみました。
また、Amazon Linux 2023 でデフォルトで利用できる systemd timer を使って継続してファイルを生成しました。
作成したログは以下です。
更新時間のタイムスタンプを見てほしいのですが、3日に分けて大きめのファイルをsystemd timer
を使って継続して生成し、Universal Forwarderから上記のIngest Actionsを経由して、Amazon S3にデータを置いています。
1/28日分は134GB
作っています。
$ ls -lh apachelogs/dummy_access*.log
-rw-r--r--. 1 ec2-user ec2-user 5.0G Jan 27 13:11 apachelogs/dummy_access.log
-rw-r--r--. 1 ec2-user ec2-user 134G Jan 28 12:23 apachelogs/dummy_access_1.log
-rw-r--r--. 1 ec2-user ec2-user 3.0M Jan 29 01:05 apachelogs/dummy_access_2.log
S3で確認すると、全部で3.9GB
で上がっています。(gzipで圧縮されているのでだいぶ小さくなっています。)
また、S3のパスは2025/01/
の下に3つのパスがつくられています。
1/27日分は、オブジェクト数が567
で475MB
です。
データサイズが大きかった1/28日分は、オブジェクト数が2,695
で3.4GB
です。
データサイズが小さかった1/29日分は、オブジェクト数が5
で1.7MB
です。
Splunk Federated Search for S3 を使って検索してみます。
まず、タイムピッカーを使って2025/01/27
のデータに絞って検索します。
パーティションで使っている「date」フィールドでグループ化して、2025/1/27のデータが返ってくることを確認します。
※また、Federated Search fdr S3 ではフェイルセーフとして、デフォルトだと 100,000 行分の結果となるスキャンのみに制限されています。
結果が返ってきました。
出力結果は 2025/1/27 のデータで返ってきますが、スキャン対象となっているデータはどうか、検索にかかった時間はどれだけかを確認します。
Job > Inpsect Job で検索パフォーマンスの詳細を見ます。
searchTelemetry の federated_search_for_amazon_s3 の値を開きます。
スキャンしたデータのバイト数: 498,104,463 Bytes / 1024 / 1024 = 475MB
スキャン実行にかかった時間: 29.038秒
元の生データだと5GB分のデータになりますが、しばらく待たされている感覚はあります。この程度であれば一息ついて、検索をかける感覚でクエリを投げれる感じですが、サクサクとはいきません。
次に2025/01/28
のデータをやってみます。
結果が返ってきました。
同じくパフォーマンスを確認していきます。
スキャンしたデータのバイト数: 3,672,113,631 Bytes / 1024 /1024 /1024 = 3.4GB
スキャン実行にかかった時間: 51.904秒
元の生データだと134GB分のデータになります。結構待たされます。先程のデータ量の20倍ですが、20倍の時間を待たされるというわけではなさそうです。
連続してクエリを発行したい場合は、時間がかかります。ある程度検索クエリでどんな結果が返ってくるかを想定した上で実行する方がよいです。
次に2025/01/29
のデータをやってみます。
結果が返ってきました。
同じくパフォーマンスを確認していきます。
スキャンしたデータのバイト数: 1,804,174 Bytes / 1024 /1024 = 1.72MB
スキャン実行にかかった時間: 2.352秒
元の生データは5MB程度です。さすがにこの程度のデータ量であれば全く問題ないレスポンスです。
まとめ
以上、Ingest Actions を活用してデータを Amazon S3 に取り込み、パーティショニングによるデータスキャンの絞り込みと検索パフォーマンスを確認しました。
結論からすると、パフォーマンス観点・ライセンスい利用量に関わるスキャンデータ容量を減らす観点でパーティショニングは必須です。
Ingest Actions のS3パスのオートジェネレーション機能が年月日(yyyy/MM/dd)まで対応しているのですが、これに加え時間も対応してくれるとさらに絞り込み効率が良くなるので、ぜひ対応してほしいなと思いました。
また、今回gzipで圧縮してS3にデータを保管していますが、検索パフォーマンスにおいては非圧縮のデータの方がレスポンスが良さそうです。その分、データ容量自体は増えることになるので、どちらがパフォーマンス的には良いのか一度確認してみたいなと思いました。