NetFlow のデータを Fluentd・Prometheus・Grafanaで可視化する

NetFlowのコレクタとしてFluentdを利用し、Prometheus・Grafanaを利用し可視化を行った際のメモ
# モチベーション
- オープンソースのソフトウェアを利用してNetFlowのデータを可視化したい

ということで、ネットワークシュミレータ上で動作を確認をしてみました
# NetFlowとは
ざっくり
- ネットワークのトラフィックの情報を監視・分析するための技術
- 送信元IPアドレス、宛先IPアドレス、TCP/UDPポート番号(フローデータ)などの情報を収集
- ネットワーク機器からフロー情報をフローコレクターに送信し監視・分析することができる

# 構成とアウトプットのイメージ
- NetFlowの吐き出すネットワーク機器としてVyOSを利用
- ネットワークシュミレータ上にUbuntuを設置してFlowコレクタとして利用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/035249fa-ba61-85e9-5117-66e731b780db.png)


- 各ソフトウェアの役割は以下のイメージです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/da4be171-5319-7c8c-8f08-c21e93dea853.png)


- 今回には Grafanaで以下のような簡単なグラフで可視化することを目標にしてます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/89e1fe9c-ac37-afa9-cc62-1c9023789ad0.png)

# ①環境準備
## ①-1 VyOSの準備
- 以下のサイトを参考にVyOSのイメージ作成
  - https://www.eve-ng.net/index.php/documentation/howtos/howto-add-vyos-vyatta/

## ①-2 サーバ(Ubuntu)の準備
- 以下のサイトを参考にサーバのイメージ作成
  - https://www.eve-ng.net/index.php/documentation/howtos/howto-create-own-linux-host-image/
  - 「How to create own custom Linux host for EVE:」の部分からUbuntuをインストール
  - 今回は Ubuntuの22.04の Serverをインストール。インストールは Ubuntu Server (minimized) にして最小限の環境を構築
  - インストール中に聞かれるSSHサーバは設定
  - IPアドレスを以下のサイトを参考に設定
    - https://qiita.com/zen3/items/757f96cbe522a9ad397d
  - コンソールでログインできるように以下のサイトを参考に設定
    - https://qiita.com/wataash/items/b291cc0643d952d986d8 



## ①-3 Fluentdの準備
### Fluentdのインストール
- 事前に以下内容を設定
  - https://docs.fluentd.org/installation/before-install
- Fluentdのインストール
  - root ユーザで、以下を実施
```:Fluentdのインストール(Ubuntu 22.04 Jammy)
curl -fsSL https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-fluent-package5-lts.sh | sh

systemctl start fluentd.service

systemctl status fluentd.service
```
  - 以下のサイトを参考にしてます
      - https://docs.fluentd.org/installation/install-by-deb

### Fluentdのプラグインのインストール
Fluentdで、NetFlow取得したり、データを整形したり、Prometheusと連携するためにプラグインをインストールする
```:Fluentdの各プラグインのインストール
apt install make g++ ruby-dev ruby-bundler

/opt/fluent/bin/fluent-gem install fluent-plugin-netflow
/opt/fluent/bin/fluent-gem install fluent-plugin-rewrite-tag-filter
/opt/fluent/bin/fluent-gem install fluent-plugin-prometheus
```

## ①-4 Prometheusの準備
### Prometheusのインストール
- Prometheusのインストール
  - root ユーザで、以下を実施
```:Prometheusのインストール
apt -y install prometheus prometheus-node-exporter
systemctl enable prometheus prometheus-node-exporter

```
- 以下のサイトを参考にしてます
  - https://www.server-world.info/query?os=Ubuntu_22.04&p=prometheus&f=1

## ①-5 Grafanaの準備
### Grafanaのインストール
- Grafanaのインストール
  - root ユーザで、以下を実施
```:Grafanaのインストール
wget -q -O /usr/share/keyrings/grafana.key https://packages.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://packages.grafana.com/oss/deb stable main" | tee -a /etc/apt/sources.list.d/grafana.list
apt update
apt -y install grafana
```
- Grafanaの設定変更
  - ローカル環境なので https ではなく http でログインできるように変更
      - 「/etc/grafana/grafana.ini」内の「;protocol = http」を「protocol = http」に変更

```:Grafanaのインストール
root@ubuntsu-netflow:/etc/grafana# diff grafana.ini grafana.ini.org
32c32
< protocol = http
---
> ;protocol = http
root@ubuntsu-netflow:/etc/grafana#
```

- 以下のサイトを参考にしてます
  - https://www.server-world.info/query?os=Ubuntu_22.04&p=grafana


# ② NetFlowデータ取得と可視化
## ②-1 VyOSからNetFlowのFlowデータを送信する
### コンフィグ設定
- eth0 に PCと接続するIFとしてIP設定(IPv4/IPv6)
- eth3 は Flowコレクタとなるサーバに送信するIFとして設定
- NetFlowは eth0 のIFのトラフィックを監視して 「10.0.0.1」の FlowコレクへNetFlowデータを送信
```:VyOS設定内容
set interfaces ethernet eth0 address '192.168.1.254/24'
set interfaces ethernet eth0 address '2001:db8:1::254/64'

set interfaces ethernet eth3 address '10.0.0.254/24'

set system flow-accounting interface 'eth0'
set system flow-accounting netflow engine-id '0'
set system flow-accounting netflow server 10.0.0.1 port '4739'
set system flow-accounting netflow timeout expiry-interval '60'
set system flow-accounting netflow timeout max-active-life '60'
set system flow-accounting netflow version '9'

set system host-name 'vyos-netflow'
```

### NetFlowが動作しているか確認する
- フロー対象となるトラフィックを出すためPCからVyOSのIFにPINGを打ち続ける
- VyOSの eth3 をパケットキャプチャして定期的にFlowデータが送信されていることを確認する
- サーバ側はIPアドレスだけ事前に設定(VyOSからのFlowデータ送信前にARP解決ができずに終わってしまうため)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/2302ac51-0379-3836-b665-52fbf1694f27.png)

## ②-2 Fluentd でNetFlowのFlowデータを受信する
### コンフィグ設定
- 「/etc/fluent/fluentd.conf」を編集する
- 事前にオリジナルのデータをコピーしておく
    - cp -p /etc/fluent/fluentd.conf /etc/fluent/fluentd.conf.org
- 「/etc/fluent/fluentd.conf」を編集
```:fluentd.conf 設定内容
# NetFlowデータを取得
<source>
  @type netflow
  tag netflow.event
  port 4739
</source>

# デバッグ用に出力
<match **>
  @type stdout
</match>
```
- 設定内容を反映させるため fluentd をリスタート
    - systemctl restart fluentd.service
- PCとVyOS間でIPv4とIPv6でPINGを打ち続けて Flowデータをだす
- ログを tail　してFlowデータをFluentdで受信していることを確認する
    - tail -f /var/log/fluent/fluentd.log
    - IPv4とIPv6でそれぞれのテンプレートのフォーマットで受信を確認できます

```: fluentd.log でFlowデータ受信した内容
▼IPv4
2024-xx-xx 16:11:42.000000000 +0900 netflow.event: {"version":"9","flow_seq_num":"2","flowset_id":"1024","flowEndMilliseconds":"2024-xx-xxT07:11:42.132Z","flowStartMilliseconds":"2024-xx-xxT07:10:33.039Z","in_bytes":5880,"in_pkts":70,"ip_protocol_version":4,"input_snmp":2,"output_snmp":0,"direction":0,"flows":0,"ipv4_src_addr":"192.168.1.1","ipv4_dst_addr":"192.168.1.254","l4_src_port":0,"l4_dst_port":2048,"src_tos":0,"tcp_flags":0,"protocol":1,"in_src_mac":"00:50:79:66:68:b9","in_dst_mac":"50:1f:38:00:b7:00","src_vlan":0,"host":"10.0.0.254"}

▼IPv6
2024-xx-xx 16:11:58.000000000 +0900 netflow.event: {"version":"9","flow_seq_num":"3","flowset_id":"2048","flowEndMilliseconds":"2024-xx-xxT07:11:58.068Z","flowStartMilliseconds":"2024-xx-xxT07:10:48.722Z","in_bytes":7280,"in_pkts":70,"ip_protocol_version":6,"input_snmp":2,"output_snmp":0,"direction":0,"flows":0,"ipv6_src_addr":"2001:db8:1::1","ipv6_dst_addr":"2001:db8:1::254","src_tos":0,"l4_src_port":0,"l4_dst_port":0,"tcp_flags":0,"protocol":58,"in_src_mac":"00:50:79:66:68:b9","in_dst_mac":"50:1f:38:00:b7:00","src_vlan":0,"host":"10.0.0.254"}
```

## ②-3 Prometheus で Fluentd の NetFlowデータを取得する設定を行う
### Prometheus側の設定
- 「/etc/prometheus/prometheus.yml」を編集する
- 事前にオリジナルのデータをコピーしておく
    - cp -p /etc/prometheus/prometheus.yml /etc/prometheus/prometheus.yml.org
- 「/etc/prometheus/prometheus.ymlを編集

```:prometheus.yml 設定内容
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.

  external_labels:
      monitor: 'example'

alerting:
  alertmanagers:
  - static_configs:
    - targets: ['localhost:9093']

rule_files:

scrape_configs:
  - job_name: fluentd
    static_configs:
      - targets: ['localhost:24231']
```
- 設定内容を反映させるため Prometheus をリスタート
    - systemctl restart prometheus.service

### Fluentd側の設定
- 再度「/etc/fluent/fluentd.conf」を編集する
  - IPv4・IPv6で受信データ「in_bytes」をキーにする
  - 事前に取得したログからラベルを設定し、必要な物以外はコメントアウト
- 以下の内容に変更し設定内容を反映させるため fluentd をリスタート
  - systemctl restart fluentd.service
<details><summary>fluentd.conf 設定内容</summary>
<div>

```:fluentd.conf 設定内容
#-----------------------
# Prometheus用
#-----------------------

<source>
  @type prometheus
  @id in_prometheus
  bind "0.0.0.0"
  port 24231
  metrics_path "/metrics"
</source>

#-----------------------
# NetFlow用
#-----------------------

# NetFlowデータを取得
<source>
  @type netflow
  tag netflow.event
  port 4739
</source>

## デバッグ用に出力
#<match **>
#  @type stdout
#</match>

# IPv4とIPv6にデータ分ける
<match netflow.event>
  @type copy
  <store>
    @type rewrite_tag_filter
    <rule>
      key ipv4_src_addr
      pattern /(.*)/
      tag netflow.ipv4
    </rule>
  </store>
  <store>
    @type rewrite_tag_filter
    <rule>
      key ipv6_src_addr
      pattern /(.*)/
      tag netflow.ipv6
    </rule>
  </store>
</match>

# IPv4用にPrometheusに出力するデータを決める、受信バイト数(in_bytes)をkeyにする、不要なラベルはコメントアウト
<filter netflow.ipv4>
  @type prometheus
  <metric>
    name netflow_ipv4_in_byte
    desc NetFlow IPv4 Traffic input byte
    type counter
    key in_bytes
    <labels>
      #version ${version}
      #flow_seq_num ${flow_seq_num}
      #flowset_id ${flowset_id}
      #flowEndMilliseconds ${flowEndMilliseconds}
      #flowStartMilliseconds ${flowStartMilliseconds}
      #in_pkts ${in_pkts}
      #ip_protocol_version ${ip_protocol_version}
      input_snmp ${input_snmp}
      #output_snmp ${output_snmp}
      #direction ${direction}
      #flows ${flows}
      ipv4_src_addr ${ipv4_src_addr}
      ipv4_dst_addr ${ipv4_dst_addr}
      l4_src_port ${l4_src_port}
      l4_dst_port ${l4_dst_port}
      #src_tos ${src_tos}
      #tcp_flags ${tcp_flags}
      protocol ${protocol}
      #in_src_mac ${in_src_mac}
      #in_dst_mac ${in_dst_mac}
      #src_vlan ${src_vlan}
      hostip ${host}
    </labels>
  </metric>
</filter>

<match netflow.ipv4>
  #@type stdout
  @type null
</match>


# IPv6用にPrometheusに出力するデータを決める、受信バイト数(in_bytes)をkeyにする、不要なラベルはコメントアウト
<filter netflow.ipv6>
  @type prometheus
  <metric>
    name netflow_ipv6_in_byte
    desc NetFlow IPv6 Traffic input byte
    type counter
    key in_bytes
    <labels>
      #version ${version}
      #flow_seq_num ${flow_seq_num}
      #flowset_id ${flowset_id}
      #flowEndMilliseconds ${flowEndMilliseconds}
      #flowStartMilliseconds ${flowStartMilliseconds}
      #in_pkts ${in_pkts}
      #ip_protocol_version ${ip_protocol_version}
      input_snmp ${input_snmp}
      #output_snmp ${output_snmp}
      #direction ${direction}
      #flows ${flows}
      ipv6_src_addr ${ipv6_src_addr}
      ipv6_dst_addr ${ipv6_dst_addr}
      #src_tos ${src_tos}
      l4_src_port ${l4_src_port}
      l4_dst_port ${l4_dst_port}
      #tcp_flags ${tcp_flags}
      protocol ${protocol}
      #in_src_mac ${in_src_mac}
      #in_dst_mac ${in_dst_mac}
      #src_vlan ${src_vlan}
      hostip ${host}
    </labels>
  </metric>
</filter>

<match netflow.ipv6>
  #@type stdout
  @type null
</match>


```
</div></details>


## ②-4 Prometheus で確認を行う
- ブラウザで「http://[サーバのアドレス]:9090/」にログインして Prometheusの管理画面を開く
- 「Graph」を選択し、Fluentdで設定した NetFlowのIPv4とIPv6が選択できることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/3e5a7682-09da-2f2a-0d02-1530a776d1ec.png)

- 「Graph」で定期的に取得したデータからグラフ表示されることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/9e614c96-09d1-8f60-69ea-7bdc032fad2b.png)


## ②-5 Grafana で Prometheus のデータを表示する
- ブラウザで「http://[サーバのアドレス]:3000/」にログインして Grafana の管理画面を開く
    - 初期ユーザとパスワードはともに「admin」です
- Grafana と Prometheus の連携は他のサイトでもたくさん紹介されているため省略します。。。
- 最終的には以下のようなグラフ表示が出せます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/0e3f98ab-e274-e5e4-3f3f-48e6f8979e83.png)

# 最後に
Fluentd・Prometheus・Grafanaを利用してNetFlowデータの可視化まで確認できました
オープンソースのソフトウェアでここまでできるのはすごい
次は Telemetryもやってみたい