スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Splunk その5

# バージョン 4.1.7 がリリースされたため、今回から使用している Splunk のバージョンが上がっています。

16. App とは

App の作成に入る前に、「そもそも App ってなに?」という方のために簡単に解説しておくと、Splunk の App というのは特定の用途向けにカスタマイズされたビューやデータ入力、各種 Web コンテンツのパッケージです。よく使われるものとして、例えば UNIX や Linux システムを管理するための Splunk for Unix and Linux(*NIX)、Windows システムを管理するための Splunk for Windows などがあります。

Splunk には初期状態で Search や Launcher などいくつかの App がインストールされていますが、そうした非常に汎用的、もしくは単機能の App では必要な機能要件を満たせない場合には、ユーザが自分で App を作成するか、Splunkbase という Web サイトから Splunk や 3rd Party ベンダー、あるいは個人が作成したものをダウンロードして使用することになります(Splunkbase で公開されている App は基本的に無償のものが多いですが、一部は有償です)。

17. App の作成

それでは、Splunk サーバ上のログファイルに書き込まれた ASA の Firewall ログを表示するための簡単な App を作成していきましょう。今回作成する App の機能要件は以下とします。

・検索条件の入力なしに Firewall ログの表示が可能
・ホスト名や送信元/宛先アドレス、ポート番号、インターフェース名によるフィルタが可能

※ ここで言っている Firewall ログの中身については、後ほど詳しく説明します。

① Syslog App を作成する

まずは管理メニューから「Apps」をクリックします。

splunk_setup_5-1.png

「新規Appの作成」ボタンをクリックします。

splunk_setup_5-2.png

新規追加画面で必要事項を入力し、「保存」ボタンをクリックします。

splunk_setup_5-3.png

Apps 画面に戻ったら、画面上部の「管理から再起動するには、ここをクリックしてください。」をクリックします。

splunk_setup_5-4.png

「Splunkの再起動」をクリックします。

splunk_setup_5-5.png

「OK」をクリックします。

splunk_setup_5-6.png

再起動完了後、Launcher もしくは画面右上の App メニューから、先ほど作成した Syslog App を選択します。

splunk_setup_5-7.png

Syslog App の初期画面として検索画面が表示されるので、試しにそのままリターンキーを押すか、テキストボックスの右側にある緑色の検索ボタンをクリックしてみましょう。

splunk_setup_5-7-1.png

※ ここでは検索条件を指定していないため、デフォルトのインデックスである main インデックスに格納されている全てのログが表示されています。また、表示形式は元のログをそのまま表示するイベントリスト形式になっています。

ここまでの操作で、App の雛形が出来ました。

② フィールド抽出

App を作成した後は、そこに載せるビューを作成していくことになるのですが、その前に今回管理対象となるログについて少し考えてみましょう。

まず、第一の要件である「検索条件の入力なしに Firewall ログの表示が可能」を実現するには、最初から Firewall ログのみを表示する検索条件を指定しておく必要があります。それでは、この検索条件は具体的にどのようなものになるでしょうか。

ここで言う Firewall ログとは、ASA の ACL によってトラフィックが許可もしくは拒否された時に出力されるもので、具体的には以下の 2 種類のログを指します。

Feb 13 00:11:27 asa local4.warn: <164>Jul 04 2011 19:24:26: %ASA-4-106023: Deny udp src inside:192.168.100.1/1900 dst identity:239.255.255.250/1900 by access-group "inside" [0xd820e56a, 0x0]

Feb 13 01:40:26 asa local4.info: <166>Jul 04 2011 20:53:23: %ASA-6-106100: access-list inside denied udp inside/192.168.100.1(1900) -> NP Identity Ifc/239.255.255.250(1900) hit-cnt 18 300-second interval [0xd820e56a, 0x0]

上段のログは、特別な設定をしなくてもアクションが拒否(deny)の ACE にマッチするトラフィックがあった時に常に出力されるもので、下段は許可・拒否に関わらず、ACL にログオプションを付けた際に出力されるログになります。なお、アクションが拒否の ACE にログオプションを指定した場合は、下段のフォーマットが優先となります。

それぞれのログの種別をユニークに識別可能なキーワードとしては、syslogtag の「%ASA-4-106023」および「%ASA-6-106100」がありますが、4 や 6 といった中央の数字は Syslog の priority であり、ASA の設定によって変化する可能性があるため、実際の検索ワードは「%ASA-*-106023」および「%ASA-*-106100」(* は任意の文字列にマッチ)になります。

それでは、2 番目の要件はどうでしょうか。ログの出力形式を見てみると、「ホスト名や送信元/宛先アドレス、ポート番号、インターフェース名によるフィルタが可能」という要件については、検索条件を細かく指定するだけでは対応が難しいことがわかります。というのも、送信元と宛先の情報を区別するための情報は、メッセージ内での出現位置だけだからです。例えば検索条件としてポート番号を「(1900)」と指定しても、それが送信元ポートなのか、宛先ポートなのかを指定することはできません。

こうした状況に対処するため、Splunk は正規表現によるフィールド抽出の機能を提供しています。フィールド抽出とは、ログを意味のあるブロック単位に切り出してユーザが定義したフィールドに値を格納することで、切り出した値を検索条件に使用したり、テーブル形式で表示を行う際のカラムとして使用するための機能です。

例えば、下段のログは以下のようなフォーマットで構成されています。

[timestamp] [hostname] [facility].[priority]: <PRE>[timestamp]: [syslogtag]: access-list [acl-name] [action] [protocol] [source_if]/[source_address]([source_port]) -> [dest_if]/[dest_address]([dest_port]) hit-cnt [hit_count] [misc]

ここで、[syslogtag] の位置にある文字列を syslogtag というフィールドに格納することができれば、検索条件として「syslogtag=%ASA-*-106100」という指定が可能になるわけです。

今回の App のためにフィールド抽出を行うには、以下の 2 つのファイルを作成してエントリを追加します。

$SPLUNK_HOME/etc/apps/syslog/local/props.conf
[syslog]
REPORT-asa = asa-106023 asa-106100

$SPLUNK_HOME/etc/apps/syslog/local/transforms.conf
[asa-106100]
REGEX = \s(\w+)\.(\w+): \<\d+\>(\w{3} \d{2} \d{4} \d{2}:\d{2}:\d{2}): (%ASA-\d-106100): access-list (\S+) (\S+) (\S+) (\S+)/(\S+)\((\d+)\) -> (\S+)/(\S+)\((\d+)\) hit-cnt (\d)
FORMAT = facility::$1 priority::$2 timegenerated::$3 syslogtag::$4 acl::$5 action::$6 protocol::$7 src_if::$8 src_addr::$9 src_port::$10 dst_if::$11 dst_addr::$12 dst_port::$13 hit_count::$14

[asa-106023]
REGEX = \s(\w+)\.(\w+): \<\d+\>(\w{3} \d{2} \d{4} \d{2}:\d{2}:\d{2}): (%ASA-\d-106023): Deny (\S+) src (\S+):(\S+)/(\S+) dst (\S+):(\S+)/(\S+) by access-group "(\S+)"
FORMAT = facility::$1 priority::$2 timegenerated::$3 syslogtag::$4 action::denied protocol::$5 src_if::$6 src_addr::$7 src_port::$8 dst_if::$9 dst_addr::$10 dst_port::$11 acl::$12

上記 2 つのファイルで具体的に何をしているかについては、きちんと説明するとかなり長くなってしまうので、後日まとめて解説します。基本的には、transforms.conf で定義したフィールド抽出の定義を props.conf で source=syslog のイベントに対して適用するという動作になるのですが、この説明だけではイメージがつきにくいと思いますので、とりあえずここではそういう設定が必要なんだ、と思っていていただければ結構です。

③ ビューの作成

Splunk の用語で、ビューとは App を構成する一つ一つの画面を意味します。各ビューの実体は XML ファイルであり、ブラウザのアドレスバーに表示されているURL の末尾に「?showsource=1」を付け足すことでソースコードを参照することが可能です。例えば、Search App のダッシュボードの XML ソースは下記 URL から参照することが可能です。

http://<hostname>:8000/ja-JP/app/search/dashboard?showsource=1


上記 URL にアクセスすると、以下のようなソースが表示されます。

<view autoCancelInterval="90" isPersistable="true" isSticky="true" isVisible="true" objectMode="viewconf" onunloadCancelJobs="true" stylesheet="dashboard2.css" template="dashboard.html">
<label>Summary</label>
<module name="AccountBar" layoutPanel="appHeader"/>
<module name="AppBar" layoutPanel="navigationHeader"/>
<module name="Message" layoutPanel="messaging">
<param name="filter">*</param>
<param name="clearOnJobDispatch">False</param>
<param name="maxSize">1</param>
</module>
<module name="TitleBar" layoutPanel="viewHeader">
<param name="actionsMenuFilter">dashboard</param>
</module>
<module name="SearchBar" layoutPanel="splSearchControls-inline">
<param name="useOwnSubmitButton">False</param>
<param name="useTypeahead">true</param>
<param name="useAssistant">true</param>
<module name="TimeRangePicker">
<param name="searchWhenChanged">False</param>
<param name="selected">All time</param>
<module name="SubmitButton">
<param name="allowSoftSubmit">True</param>
<module name="ViewRedirector" layoutPanel="viewHeader">
<param name="viewTarget">flashtimeline</param>
</module>
</module>
</module>
</module>
<module name="HiddenSearch" layoutPanel="panel_row1_col1" group="Global summary" autoRun="true">
<param name="groupLabel">グローバルサマリー</param>
<param name="search">| metadata type=hosts</param>
<param name="maxCount">100000</param>
<module name="HiddenPostProcess">
<param name="search">| stats sum(totalCount)</param>
<module name="SingleValue">
<param name="beforeLabel">Events indexed</param>
<param name="format">number</param>
</module>
</module>
<module name="HiddenPostProcess">
<param name="search">| stats min(firstTime) as min | convert ctime(min)</param>
<module name="SingleValue">
<param name="beforeLabel">Earliest event</param>
<param name="format">unixtime</param>
</module>
</module>
<module name="HiddenPostProcess">
<param name="search">| stats max(lastTime) as max | convert ctime(max)</param>
<module name="SingleValue">
<param name="beforeLabel">Latest event</param>
<param name="format">unixtime</param>
</module>
</module>
</module>
<module name="StaticContentSample" layoutPanel="panel_row2_col1" group="All indexed data">
<param name="text">This lists all of the data you have loaded into your default indexes, based on data recency. <a href="/manager/search/datainputstats"> Add more data</a> via Manager.</param>
<param name="groupLabel">インデックスされたすべてのデータ</param>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1_grp1" autoRun="true">
<param name="search">| metadata type=sources | search totalCount>0</param>
<param name="maxCount">100000</param>
<module name="SimpleResultsHeader">
<param name="entityName">results</param>
<param name="headerFormat">Sources (%(count)s)</param>
</module>
</module>
<module name="Sorter" layoutPanel="panel_row2_col1_grp1">
<param name="fields">
<list>
<param name="value">source</param>
<param name="label">Source</param>
</list>
<list>
<param name="value">totalCount</param>
<param name="label">Total Count</param>
</list>
<list>
<param name="value">lastTime</param>
<param name="label">Last Updated</param>
</list>
</param>
<param name="sortDir">desc</param>
<param name="sortKey">lastTime</param>
<module name="Paginator">
<param name="count">10</param>
<param name="entityName">settings</param>
<param name="maxPages">10</param>
<module name="SearchLinkLister">
<param name="settingToCreate">list1</param>
<param name="search">| metadata type=sources | search totalCount>0</param>
<param name="searchFieldsToDisplay">
<list>
<param name="value">source</param>
<param name="label">source</param>
</list>
<list>
<param name="labelFormat">number</param>
<param name="label">totalCount</param>
</list>
</param>
<module name="ConvertToIntention">
<param name="settingToConvert">list1</param>
<param name="intention">
<param name="name">addterm</param>
<param name="arg">
<param name="source">$target$</param>
</param>
</param>
<module name="ViewRedirector">
<param name="uriParam.auto_pause">true</param>
<param name="viewTarget">flashtimeline</param>
</module>
</module>
</module>
</module>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1_grp2" autoRun="true">
<param name="search">| metadata type=sourcetypes | search totalCount>0</param>
<param name="maxCount">100000</param>
<module name="SimpleResultsHeader">
<param name="entityName">results</param>
<param name="headerFormat">Sourcetypes (%(count)s)</param>
</module>
</module>
<module name="Sorter" layoutPanel="panel_row2_col1_grp2">
<param name="fields">
<list>
<param name="value">sourcetype</param>
<param name="label">Sourcetype</param>
</list>
<list>
<param name="value">totalCount</param>
<param name="label">Total Count</param>
</list>
<list>
<param name="value">lastTime</param>
<param name="label">Last Updated</param>
</list>
</param>
<param name="sortDir">desc</param>
<param name="sortKey">lastTime</param>
<module name="Paginator">
<param name="count">10</param>
<param name="entityName">settings</param>
<param name="maxPages">10</param>
<module name="SearchLinkLister">
<param name="settingToCreate">list2</param>
<param name="search">| metadata type=sourcetypes | search totalCount>0</param>
<param name="searchFieldsToDisplay">
<list>
<param name="value">sourcetype</param>
<param name="label">sourcetype</param>
</list>
<list>
<param name="labelFormat">number</param>
<param name="label">totalCount</param>
</list>
</param>
<module name="ConvertToIntention">
<param name="settingToConvert">list2</param>
<param name="intention">
<param name="name">addterm</param>
<param name="arg">
<param name="sourcetype">$target$</param>
</param>
</param>
<module name="ViewRedirector">
<param name="uriParam.auto_pause">true</param>
<param name="viewTarget">flashtimeline</param>
</module>
</module>
</module>
</module>
</module>
<module name="HiddenSearch" layoutPanel="panel_row2_col1_grp3" autoRun="true">
<param name="search">| metadata type=hosts | search totalCount>0</param>
<param name="maxCount">100000</param>
<module name="SimpleResultsHeader">
<param name="entityName">results</param>
<param name="headerFormat">Hosts (%(count)s)</param>
</module>
</module>
<module name="Sorter" layoutPanel="panel_row2_col1_grp3">
<param name="fields">
<list>
<param name="value">host</param>
<param name="label">Host</param>
</list>
<list>
<param name="value">totalCount</param>
<param name="label">Total Count</param>
</list>
<list>
<param name="value">lastTime</param>
<param name="label">Last Updated</param>
</list>
</param>
<param name="sortDir">desc</param>
<param name="sortKey">lastTime</param>
<module name="Paginator">
<param name="count">10</param>
<param name="entityName">settings</param>
<param name="maxPages">10</param>
<module name="SearchLinkLister">
<param name="settingToCreate">list3</param>
<param name="search">| metadata type=hosts | search totalCount>0</param>
<param name="searchFieldsToDisplay">
<list>
<param name="value">host</param>
<param name="label">host</param>
</list>
<list>
<param name="labelFormat">number</param>
<param name="label">totalCount</param>
</list>
</param>
<module name="ConvertToIntention">
<param name="settingToConvert">list3</param>
<param name="intention">
<param name="name">addterm</param>
<param name="arg">
<param name="host">$target$</param>
</param>
</param>
<module name="ViewRedirector">
<param name="uriParam.auto_pause">true</param>
<param name="viewTarget">flashtimeline</param>
</module>
</module>
</module>
</module>
</module>
</view>

ユーザが独自のビューを作成する際には、こうした XML コードを自分で書く必要があります。また、ビューを作成するための XML の書式には簡易 XML (Simple XML)と拡張 XML(Advanced XML)という 2 通りの書式があり、それぞれ以下のような特徴があります。

簡易 XML:
出来ることは限られるが、書式が単純。また一部については Splunk Web のダッシュボードの編集画面(UI ビルダー)からコード生成が可能。

拡張 XML:
全ての機能が利用可能だが、書式が複雑。上記 Search App の View も拡張書式で記述されています。


今回は基本となる簡易 XML を使用して App を作成していきます。

【ダッシュボードの作成】

まずはイベントを表示するだけのシンプルなダッシュボードを作成してみます。

Syslog App の管理メニューから、「ユーザーインターフェース」をクリックします。

splunk_setup_5-8.png

ビューの「新規追加」をクリックします。

splunk_setup_5-9.png

ビュー名に「asa-dashboard」、ビュー XML に以下の内容を貼り付けて、保存ボタンをクリックします。

<dashboard>
<label>ASA Dashboard</label>
<row>
<table>
<searchString>syslogtag="%ASA-*-106100" OR syslogtag="%ASA-*-106023"</searchString>
<title>Firewall Log</title>
<earliestTime></earliestTime>
<latestTime></latestTime>
<fields>timegenerated,host,priority,acl,action,protocol,src_if,src_addr,src_port,dst_if,dst_addr,dst_port,hit_count</fields>
<option name="count">25</option>
<option name="displayRowNumbers">false</option>
<option name="drilldown">all</option>
<option name="showPager">true</option>
</table>
</row>
</dashboard>

splunk_setup_5-10.png

ダッシュボードが作成されたことを確認し、画面左上の「Syslog App に戻る」をクリックします。

splunk_setup_5-11.png

画面上部のナビゲーションメニューから、「Dashboards > ASA Dashboard」をクリックします。

splunk_setup_5-12.png

ASA Dashboard の画面で、Firewall ログの一覧が表形式で表示されることを確認します。

splunk_setup_5-13.png

以上でダッシュボードの作成は完了です。なお、今回はイベントリストを表示していますが、ダッシュボードの用途としては、どちらかというとグラフやタイムチャートの表示が主になると思います(過去 1 時間の CPU / メモリ使用率と重要イベント、といった形でイベントリストが使われることはもちろんありますが)。

というのも、大量のイベントを表示してもダッシュボードではそれを絞り込む手段がないためで、そうした場合には次に説明するフォーム検索を使用するのが一般的です。

【フォーム検索の作成】

ダッシュボードでは、あらかじめ指定された検索条件に適合するログの一覧を表示することができますが、ユーザが同じ画面から検索条件を変更することはできません。

先ほど作成したダッシュボードの例で言うと、「192.168.0.1」という送信元アドレスからのトラフィックに関するログのみが見たい場合、全てのログの中からページを切り替えて src_addr が 192.168.0.1 になっているものを探し出す必要があります。

これに対して、フォーム検索ビューでは、ベースとなる検索条件式に対してテキストボックスやプルダウンメニュー、チェックボックスなどの形で追加の検索条件を指定することができます。

ここでは、先ほど作成したダッシュボードをベースとして、検索条件を指定するためのテキストボックスを追加したフォームを作成してみましょう。

まず、先ほどと同じ手順で「asa-form」という名前のビューを作成します。ビュー XML には、以下の内容を貼り付けます。

<form>
<label>ASA Form</label>
<fieldset>
<input type="text" token="searchword">
<label>Search Word</label>
<default>*</default>
</input>
</fieldset>

<row>
<table>
<searchString>$searchword$ syslogtag="%ASA-*-106100" OR syslogtag="%ASA-*-106023"</searchString>
<title>Firewall Log</title>
<fields>timegenerated,host,priority,acl,action,protocol,src_if,src_addr,src_port,dst_if,dst_addr,dst_port,hit_count</fields>
<option name="count">25</option>
<option name="displayRowNumbers">false</option>
<option name="drilldown">all</option>
<option name="showPager">true</option>
</table>
</row>
</form>

splunk_setup_5-14.png

画面上部のナビゲーションメニューから、「ビュー > ASA Form」をクリックします。

splunk_setup_5-15.png

フォーム検索画面が表示されたら、まずはテキストボックスに何も入力せずに検索ボタンをクリックし、全ての Firewall ログが表示されることを確認します。

splunk_setup_5-17.png

次に、テキストボックスに「protocol=icmp」と入力して検索ボタンをクリックし、ICMP のエントリのみが表示されることを確認します。

splunk_setup_5-18.png

以上でフォーム検索ビューの作成は完了です。

今回はひとまずここまでにして、今回作成したビューを使った簡易 XML の構文の説明を次回以降で行っていきます。
スポンサーサイト

テーマ : おすすめソフトウェア
ジャンル : コンピュータ

プロフィール

米麹

筆者: 米麹
某社に勤務する SE です。
ここでは本職とは関係のない趣味的な検証情報などを書いていきます。

注意事項とお願い
記事の内容は掲載時点のもので、現在は異なる可能性があります。情報に誤りや不適切な事項があった場合には、コメントやメールフォームでご指摘下さい。
また、本サイトの情報を利用することによって生じたいかなる損害についても、筆者は責任を負いかねますのでご了承下さい。
カレンダー
01 | 2011/02 | 03
- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 - - - - -
最新記事
月別アーカイブ
カテゴリ
全記事表示リンク

全ての記事を表示する

検索フォーム
メールフォーム

名前:
メール:
件名:
本文:

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。