TECH PLAY

Kibana

イベント

該当するコンテンツが見つかりませんでした

マガジン

該当するコンテンツが見つかりませんでした

技術ブログ

サイオステクノロジー株式会社 Saman これから5回に分けて、Elastic Securityを使ったセキュリティ監視の基礎を、手を動かしながら学んでいきます。第1回はデータの取り込みと、Discover・Securityの両方で見えるようにするまでの環境構築です。 今後の予定 本シリーズでは、以下の流れでステップアップしていきます。 第2回:KQLでログを読み、最初の検知ルールを作る 第3回:Timelineで攻撃の全体像を追う 第4回:EQL / ES|QLで攻撃を自動検出・集計する 第5回:ノイズを減らし、運用できるルールにする 本ブログでは、ローカル環境に構築した Elastic Stack v9.3 を使用して、実際に手を動かしながら検証・解説を行っています。 Elastic Stack はオープンソースとして利用可能であり、クラウド版(Elastic Cloud)も無料トライアルで試すことができます。 Elastic Stack(ダウンロード) https://www.elastic.co/jp/downloads/ Elastic Cloud(無料トライアル) https://www.elastic.co/jp/cloud/cloud-trial-overview 目次 この記事を読むと何ができるか まず覚えておく5つの用語 演習データについて Step 1:ファイルをアップロードする Step 2:インデックス名を確認する Step 3:マッピングを設定する Step 4:Security画面でもデータを見えるようにする Step 5:時間範囲の調整 取り込みの確認 よくあるつまずきポイント この章のまとめ 第1回チェックリスト この記事を読むと何ができるか サンプルデータ82件をElasticsearchに正しく取り込める Discoverでイベントを確認できる Elastic Securityの画面でも同じデータが見える状態になる まず覚えておく5つの用語 このシリーズ全体で繰り返し登場します。最初に整理しておきます。 イベント :1件のログです。「ログイン成功」「プロセス起動」「外部への通信」など、「何かが起きた記録」です。このガイドでは 82件のイベントを使います。 ルール :イベントを条件で監視し、怪しいものを自動で見つけるための設定です。「ログイン失敗が起きたら知らせる」という定義がルールです。 アラート :ルールの条件に一致した結果です。イベントは「原材料」、アラートは「調査が必要かもしれない、という通知」です。アラートが出たからといって、必ずしもインシデントではありません。 Timeline :複数のイベントを時系列で並べながら、攻撃の流れを追う調査画面です。第3章で詳しく使います。 Case :調査メモ、担当者のアサイン、証拠をひとまとめにする入れ物です。チームで調査内容を共有するために使います。 演習データについて 今回使うサンプルデータ security_sample_v2.ndjson の概要です。 項目 値 形式 NDJSON(1行1イベント) 件数 82件 時間範囲 2025-03-18 09:45:00 〜 10:30:00(UTC) 取り込み先インデックス名 training-security-logs このデータはElastic Securityの学習用に設計されたサンプルです。完全な本番用ECSデータではありませんが、Discover・検知ルール・Timelineの練習には十分使えます。 ECS(Elastic Common Schema)とは 異なるログソース間でフィールド名を統一するための共通ルールです。WindowsイベントログでもLinux syslogでも、「ログイン失敗」は event.outcome: "failure" と書く、という約束事です。この共通化によって、複数製品のログを横断して検索・分析できるようになります。 Step 1:ファイルをアップロードする KibanaのIntegrationメニューから「Upload file」を開きます。画面遷移はバージョン差が出ることがあるので、迷ったら Global Search で検索して開いてください。 またはKibanaのホーム画面から「Upload a file」を選んでもかまいません。 security_sample_v2.ndjson を画面にドラッグ&ドロップします。Kibanaがファイルを自動解析します(数秒かかります)。 インデックス名を logs-training-security に指定します。 Step 2:インデックス名を確認する 「Advanced options」を展開し、「Create data view」にチェックが入っていることを確認します。このチェックが入っていると、取り込みと同時にDiscover用のデータビューが自動で作成されます。 training-security-logs ⚠️ このインデックス名は正確に入力してください 第2回以降の手順でこの名前を前提にしています。別の名前で取り込むと、後の手順がすべて動作しません。 Step 3:マッピングを設定する 「Mappings」欄に次のJSONを入力します。マッピングとは「このフィールドを日付として扱う」「これをIPアドレスとして扱う」という型の定義です。省略すると集計や範囲検索が正しく動かなくなります。 { "properties": { "@timestamp": { "type": "date" }, "agent.type": { "type": "keyword" }, "ecs.version": { "type": "keyword" }, "event.kind": { "type": "keyword" }, "event.type": { "type": "keyword" }, "event.category": { "type": "keyword" }, "event.action": { "type": "keyword" }, "event.outcome": { "type": "keyword" }, "source.ip": { "type": "ip" }, "destination.ip": { "type": "ip" }, "destination.port": { "type": "integer" }, "network.bytes": { "type": "long" }, "network.transport": { "type": "keyword" }, "network.protocol": { "type": "keyword" }, "user.name": { "type": "keyword" }, "host.name": { "type": "keyword" }, "process.name": { "type": "keyword" }, "process.pid": { "type": "integer" }, "process.command_line": { "type": "wildcard" }, "process.parent.name": { "type": "keyword" }, "dns.question.name": { "type": "keyword" }, "rule.name": { "type": "keyword" } } } マッピングが重要な理由: @timestamp が date 型でないと、時間範囲で絞り込めない network.bytes が long 型でないと、合計・最大値の集計ができない source.ip が ip 型でないと、CIDRなどのIP範囲検索が使えない 設定を確認したら「Import」をクリックします。「Import complete」と表示されれば成功です。 Step 4:Security画面でもデータを見えるようにする Data Viewを作っただけでは、SecurityアプリはこのインデックスをElastic Securityが使うインデックス一覧に含みません。 securitySolution:defaultIndex という設定にインデックス名を追加する必要があります。 Stack Management → Advanced Settings → securitySolution:defaultIndex 現在の値の末尾に training-security-logs を追加して「Save changes」をクリックし、ページをリロードします。 なぜこの設定が必要か Elastic Securityはデフォルトで logs-* 、 metrics-* などの決まったパターンのインデックスしか見ません。 training-security-logs はそのパターンに含まれないため、明示的に追加する必要があります。本番環境でも、カスタムインデックスを使う場合は同じ手順が必要になります。 ⚠️ バージョンについての注意 securitySolution:defaultIndex の設定箇所はElasticのバージョンによって異なる場合があります。公式ドキュメントも合わせて確認してください。 Step 5:時間範囲の調整 このサンプルデータは 2025-03-18 のタイムスタンプを持っています。Kibanaのデフォルト表示は「直近15分」や「Today」なので、そのままではデータが空に見えることがあります。取り込み失敗ではなく、単に時間範囲が合っていないだけです。 方法 操作 ざっくり確認したい 画面右上の時間範囲ピッカーで「Last 2 years」を選択 正確に指定したい 「Absolute」で開始 2025-03-18 09:45:00 、終了 2025-03-18 10:30:00 を入力 UTC と日本時間(JST)のズレに注意 サンプルデータのタイムスタンプはUTCで記録されています。Kibanaの表示はブラウザのタイムゾーン(日本環境ではJST = UTC+9)で表示されるため、画面上では 18:45〜19:30 のように見えます。このシリーズでは時刻をUTCで記述します。画面上の表示が9時間ずれていても異常ではありません。 取り込みの確認 取り込みが完了したら、次の3つで正しく入ったか確認します。 確認1:件数確認 Dev Tools(Console)で実行します。 GET training-security-logs/_count 期待値: 82 確認2:時間範囲確認 POST _query { "query": """ FROM training-security-logs | STATS total = COUNT(*), earliest = MIN(@timestamp), latest = MAX(@timestamp) """ } 期待値: total = 82 earliest = 2025-03-18T09:45:00.000Z latest = 2025-03-18T10:30:00.000Z 確認3:数値フィールドの型確認 POST _query { "query": """ FROM training-security-logs | WHERE network.bytes IS NOT NULL | STATS max_bytes = MAX(network.bytes), sum_bytes = SUM(network.bytes) """ } 期待値: max_bytes = 120000000 (120MB) この値が返ってくれば、 network.bytes が数値型として正しく取り込まれています。文字列型で取り込まれていると、この集計はエラーになります。 確認4:データ種別確認 POST _query { "query": """ FROM training-security-logs | STATS count = COUNT(*) BY agent.type | SORT count DESC """ } 期待値: winlogbeat = 53 packetbeat = 29 よくあるつまずきポイント 取り込んだはずなのにDiscoverに何も表示されない場合は、次を順番に確認してください。 時間範囲が「Last 15 minutes」になっていないか :「Last 2 years」に変更する Data Viewが training-security-logs になっているか :左上のドロップダウンで確認 インデックス名にタイポがないか : training-security-log (sなし)は別のインデックス Discoverでは見えるのにSecurityでは見えない場合は、Step 4の securitySolution:defaultIndex の設定を再確認してください。 この章のまとめ やったこと なぜ必要か インデックス名を training-security-logs に指定 後の章の全手順がこの名前を前提にしているため マッピングに型を明示 時間検索・数値集計・IP検索を正しく動かすため securitySolution:defaultIndex に追加 Security画面でこのデータを使えるようにするため 時間範囲を調整 2025-03-18の過去データを画面に表示するため 第1回チェックリスト [ ] GET training-security-logs/_count が 82 を返す [ ] Discoverで training-security-logs データビューを開き、イベントが見える [ ] Security → Rules 画面を開いたときにエラーが出ていない 次回は: KQLでログの中身を読みながら、最初の検知ルールを正しい条件で作ります。 event.outcome:"failure" だけでは何が起きるか、第2回で確認します。 The post Elastic Securityで始める検知エンジニアリング — 環境構築とログの取り込み(第1回) first appeared on Elastic Portal .
Elastic Inference Service (EIS) を使った「ベクトル検索」と「生成AIによる回答(RAG)」について、全2回にわたって解説します。 第1回となる今回は「準備編」として、環境構築からクラウド連携までを詳しく説明します。 目次 Elastic Inference Service (EIS) とは? 本連載で実現できること システム構成イメージ 動作確認環境 サンプルコード ベクトル検索のための準備作業 1. 環境変数の準備 2. コンテナの起動 3. Elastic Cloud 連携 (Cloud Connect) 3.1. Self-Managed Kibana へのログイン 3.2. Cloud Connect 画面への移動 3.3. Elastic Cloud へのログインと接続 次回予告 Elastic Inference Service (EIS) とは? Elastic Inference Service (EIS) は、Elastic Cloud 上で推論モデルをホスト・運用するためのマネージドサービスです。 従来、Self-Managed(オンプレミスや独自インスタンス)の Elasticsearch でベクトル検索やAI回答を行うには、自前で推論用ノードを構築・管理する必要がありました。EIS を活用することで、インフラ管理の手間を抑えつつ、強力なベクトル検索機能を Self-Managed 環境に組み込むことが可能になります。 公式ドキュメント: Elastic Inference Service (EIS) | Elastic Docs 本連載で実現できること 今回と次回の記事を通して、以下の機能を実装します。 Embedding: 外部モデルによるベクトル生成およびベクトル検索 Rerank: セマンティック・リランクによる検索精度の向上 Completion: LLM(OpenAI等)を利用した RAG(生成AI回答)の実現 システム構成イメージ 今回の構成は、Self-Managed 側のリソースを抑えつつ、計算負荷の高い推論処理を Elastic Cloud に委託するハイブリッドな構成です。 [Self-Managed Elasticsearch] <--- Elastic Cloud Connect ---> [Elastic Cloud (EIS)] Self-Managed 側に重いモデルをデプロイする必要がないため、既存環境への導入ハードルが低いのが特徴です。 [!CAUTION] 課金に関する注意 モデルの使用量に応じて、Elastic Cloud の利用料が発生します。検証の際は、トークン消費量やモデルの起動時間に十分ご注意ください。 動作確認環境 記事の執筆にあたり、以下の環境で動作を確認しています。 Elastic Cloud: Enterprise License Self-Managed Elasticsearch: v9.3.2 (Trial License) OS/Tool: Windows版 Rancher Desktop v1.20.1 利用モデル: Jina-embeddings-v5-text-nano Jina-reranker-v3 OpenAI-gpt-oss-120b-completion サンプルコード 本記事で使用するスクリプトや設定ファイルは、以下の GitHub リポジトリで公開しています。 GitHub:  SIOS-Technology-Inc/elastic-blogs/2026-03-eis ベクトル検索のための準備作業 ※作業には、ログイン可能な Elastic Cloud アカウントがあらかじめ必要です。 1. 環境変数の準備 リポジトリ内の  .env.sample  をコピーして .env を作成し、各項目を環境に合わせて編集します。 cp .env.sample .env 主な設定項目: ELASTIC_PASSWORD: Elasticsearch の elastic ユーザ用パスワード SAVEDOBJECTS_ENCRYPTIONKEY: 32文字以上のランダムな文字列(Kibana用) ES01_MEM_LIMIT: es01 コンテナに割り当てるメモリサイズ KIBANA_MEM_LIMIT: kibana コンテナに割り当てるメモリサイズ 2. コンテナの起動 Rancher Desktop 等の Docker ランタイムが起動していることを確認します。 docker-compose.yml  ファイル、および、  Dockerfile-es01  ファイルがあるディレクトリ上で以下のコマンドを実行します。 docker-compose up -d --build ※初回起動時はプラグインのインストールが走るため、完了まで数分かかります。 ※本構成は検証用のため、シングルノード構成となっています。 3. Elastic Cloud 連携 (Cloud Connect) 3.1. Self-Managed Kibana へのログイン ブラウザで  http://localhost:5601  にアクセスします。 User: elastic Password: .env で設定した ELASTIC_PASSWORD 3.2. Cloud Connect 画面への移動 Home > Management > Cloud Connect を選択します。 3.3. Elastic Cloud へのログインと接続 画面の指示に従い、Elastic Cloud へログインします。 Elastic Cloud にログイン後、Cloud Connect API Key を発行・コピーします。 取得したキーを Self-Managed 側の Kibana 画面に貼り付け、[Connect] をクリックします。 ステータスが正常になれば、Self-Managed 環境と Elastic Cloud の連携は完了です! 次回予告 今回は、Cloud Connect を利用して Self-Managed Elasticsearch と Elastic Cloud を橋渡しする手順を解説しました。 次回(実践編)は、いよいよ EIS を通じてモデルを呼び出し、「ベクトル検索」と「生成AIによる回答(RAG)」を実際に動かしてみます。お楽しみに! The post Elastic Inference Service (EIS) を使った「ベクトル検索」および「生成AIによる回答(RAG)」(準備編) first appeared on Elastic Portal .
SIOS Technology, Inc. Saman 目次 はじめに:この記事で解決できること 問題の本質:フルスキャン前提の設計 解決策の発想:Elasticsearch Transformsとは何か Transformの構造を理解する サンプルデータで効果を検証する 実験①:高cardinalityキーでの集約(clientip × 1時間) 実験②:低cardinalityキーでの集約(response × 1時間) Transformが生む2種類の圧縮 ① 縦方向の圧縮(行を減らす) ② 横方向の圧縮(列を減らす) 実行手順 まとめと設計指針 はじめに:この記事で解決できること 数十億件規模のElasticsearchで、ダッシュボード表示のたびに数十秒待つ、そんな問題を抱えているなら、原因はクエリではなく 設計 にあるかもしれません。 本記事では、SIOS Technologyのサマンが実務で直面した問題とその解決策として、 Elasticsearch Transforms を使った事前計算パターンを説明します。サンプルデータを使った実験結果も含め、実際に得られる効果を再現できる手順を紹介します。 問題の本質:フルスキャン前提の設計 以前担当したプロジェクトでは、Kibanaダッシュボードを開くたびにタイムアウトが発生していました。最初はクエリチューニングやノード増強を検討しましたが、根本原因は runtime fieldを使ったフルスキャン前提の設計 にありました。 実装していたES|QLクエリはこのようなものです。 FROM <巨大インデックス> | EVAL metric = GREATEST(fieldA, fieldB) | STATS MAX(metric) BY group_id 理論上は正しいクエリです。しかし数十億件に対してこれを毎回実行すると、全期間スキャン→全行で演算→高cardinalityフィールドで集約という処理をダッシュボード表示のたびに繰り返すことになります。 「これはクエリの問題ではなく、設計の問題だ」 と気づいたことが解決の出発点でした。 解決策の発想:Elasticsearch Transformsとは何か Elasticsearch Transformsは、生データを別インデックスに事前集計して保存する機能です。 生データインデックス → Transform → サマリーインデックス ダッシュボードやアラートは軽量なサマリーインデックスだけを参照するため、検索のたびに重い計算を繰り返す必要がなくなります。 重要な点として、**Transformは「クエリを速くするツール」ではなく「データ構造を再設計するツール」**です。効果の大小は、 group_by の設計——何をキーにまとめるか——に直接依存します。 Transformの構造を理解する 実験の前に、Transformがどういう構造を持つかを把握しておきましょう。 PUT _transform/<name> { "source": { ... }, "pivot": { ... }, "dest": { ... }, "settings": { ... } } source :読み込むインデックスを指定します。クエリフィルターを加えることで、不要なデータを事前に除外できます。 "source": { "index": "kibana_sample_data_logs", "query": { "range": { "@timestamp": { "gte": "now-90d" } } } } pivot :最も重要なブロックです。group_byでどの粒度にまとめるかを、aggregationsで何を計算するかを定義します。設計ミスはほぼここで起きます。 "pivot": { "group_by": { "timestamp_hour": { "date_histogram": { "field": "@timestamp", "calendar_interval": "1h" } }, "response": { "terms": { "field": "response.keyword" } } }, "aggregations": { "request_count": { "value_count": { "field": "bytes" } }, "total_bytes": { "sum": { "field": "bytes" } } } } dest :出力先インデックスを指定します。以後のダッシュボードやアラートはこのインデックスだけを参照します。 settings :大規模環境では必須の安全装置です。max_page_search_sizeは一度に処理するドキュメント数を制御し、メモリ枯渇を防ぎます。値はクラスタのヒープメモリに応じて調整が必要です(デフォルトは500。余裕がなければ100〜200程度から始めるのが無難です)。 "settings": { "max_page_search_size": 100 } サンプルデータで効果を検証する ここからはElasticでデフォルトで入っているkibana_sample_data_logs(約14,000件、約8.4MB)を使って、group_by設計の違いがどれほど結果に影響するかを確認します。 実験①:高cardinalityキーでの集約(clientip × 1時間) clientipはほぼリクエストごとに異なるIPアドレスです。これを1時間単位と組み合わせてgroup_byに使うと、グループがほとんど1件ずつになり、まとめる対象がありません。 PUT _transform/sample-ip-hourly-v1 { "source": { "index": "kibana_sample_data_logs" }, "pivot": { "group_by": { "timestamp_hour": { "date_histogram": { "field": "@timestamp", "calendar_interval": "1h" } }, "clientip": { "terms": { "field": "clientip" } } }, "aggregations": { "total_bytes": { "sum": { "field": "bytes" } }, "request_count": { "value_count": { "field": "bytes" } }, "error_count": { "filter": { "term": { "response.keyword": "404" } } }, "error_rate": { "bucket_script": { "buckets_path": { "errors": "error_count._count", "total": "request_count" }, "script": "params.total > 0 ? (params.errors / params.total) * 100 : 0" } } } }, "dest": { "index": "summary-ip-hourly" } } POST _transform/sample-ip-hourly-v1/_start 結果: ドキュメント数:13,844件(元データとほぼ同数) サイズ:約2.7MB Transformは実行されていますが、圧縮効果はほぼゼロです。 cardinalityが高いキーは、まとめるべき単位として機能しません。 実験②:低cardinalityキーでの集約(response × 1時間) response(HTTPステータスコード)は200、404、503など数種類しかありません。これを1時間単位でまとめると、同じ時間帯の同じレスポンスコードが大量にひとつのドキュメントに集約されます。 PUT _transform/sample-response-hourly-v1 { "source": { "index": "kibana_sample_data_logs" }, "pivot": { "group_by": { "timestamp_hour": { "date_histogram": { "field": "@timestamp", "calendar_interval": "1h" } }, "response": { "terms": { "field": "response.keyword" } } }, "aggregations": { "request_count": { "value_count": { "field": "bytes" } }, "total_bytes": { "sum": { "field": "bytes" } }, "error_flag_count": { "filter": { "range": { "response.keyword": { "gte": "400" } } } }, "error_rate": { "bucket_script": { "buckets_path": { "errors": "error_flag_count._count", "total": "request_count" }, "script": "params.total > 0 ? (params.errors / params.total) * 100 : 0" } } } }, "dest": { "index": "summary-response-hourly" } } POST _transform/sample-response-hourly-v1/_start 結果: ドキュメント数:2,005件( 約85%削減 ) サイズ:約405KB( 約95%削減 ) サイズを確認するには、summary-response-hourly/*stats を実行し、レスポンス内の “store” フィールドにある “size_in_bytes” の値を確認できます。 この劇的な差はどこから来るのでしょうか。 Transformが生む2種類の圧縮 Transformが実現する圧縮は、実は2方向で同時にやります。 ① 縦方向の圧縮(行を減らす) 元ログ: 時刻 response bytes 10:01 200 1000 10:05 200 2000 10:10 200 1500 10:15 404 300 10:20 404 500 5行あります。 これを 1時間 × response でまとめると: 時間 response total_bytes 10:00 200 4500 10:00 404 800 5行 → 2行 これが縦方向の圧縮です。 同じカテゴリが繰り返し出るほど効果は大きくなります。 ② 横方向の圧縮(列を減らす) 元ログには多くのフィールドがあります。 message agent geo request referer tags …… でも、集約に必要なのは: 時間 response bytes だけ。 Transform後のインデックスには、不要なフィールドは存在しません。 つまり、列が消える。 今回サイズが95%削減された理由はここにあります。 実行手順 # 1. Transformを作成 PUT _transform/summary-response-hourly { ... } # 2. 実行前にプレビューで確認(大規模環境では必須) POST _transform/summary-response-hourly/_preview # 3. 起動 POST _transform/summary-response-hourly/_start # 4. 状態確認 GET _transform/summary-response-hourly/_stats # 5. 必要に応じて停止・削除 POST _transform/summary-response-hourly/_stop DELETE _transform/summary-response-hourly まとめと設計指針 Transformsを導入する前に、以下の問いに答えてみてください。 この計算は、本当に検索時にやる必要がありますか? 答えがNoであれば、Transformは有効な選択肢です。設計時には以下の点に注意してください。 group_byのcardinalityを下げる ことが効果の前提条件。高cardinalityキーは原則として避ける 必要なフィールドだけを残す 設計にすることで、横方向の圧縮も最大化できる _preview で必ず事前検証 してから本番適用する max_page_search_sizeはクラスタのリソースに合わせて調整する スケールが大きくなるほどTransformの効果は大きくなります。数億・数十億件規模の時系列データを扱っているなら、「事前計算+サマリーインデックス」という設計パターンは真っ先に検討すべき選択肢です。 The post Elasticsearch Transforms入門ガイド|重い集計クエリを事前計算で解決する方法 first appeared on Elastic Portal .

動画

該当するコンテンツが見つかりませんでした

書籍