Dockerとrsyslogとfluentdでログ収集をする

#はじめに
ネットワーク機器のログをrsyslogで受けて、fluentdに送ってごにょごにょするための環境をDockerで構築してみました。
最終的にはファイアウォールのトラフィックログを分析する基盤を構築してみたいのですが、とりあえず今回は、各ネットワーク機器のログを機種ごとにファイルに出力することを目標にします。

#前提条件
以下の環境で検証しています。

- NTT PC コミュニケーションズ「Indigo」上の、KVM Instance 1 CPU 1 GB - Ubuntu 18.04


#環境構築

## ファイル構造
今回作成するのは、以下のファイルになります。

- ./rsyslog/Dockerfile
- ./rsyslog/files/etc/rsyslog.conf
- ./fluentd/Dockerfile
- ./fluentd/files/etc/fluentd.conf
- ./docker-compose.yml


##rsyslog
### Dockerfile
alpineのイメージを利用して、rsyslogのイメージを作成します。
rsyslogd.confについては、ローカル上のファイルをマウントできるように

```Dockerfile
FROM alpine:latest
ENV RSYSLOG_CONF=/etc/rsyslog.conf
EXPOSE 514
VOLUME /etc/rsyslog.conf
RUN apk update && apk add rsyslog
CMD /usr/sbin/rsyslogd -n -f $RSYSLOG_CONF
```

### rsyslog.conf
どこからかファイルを持ってきて、編集します。

```rsyslog.conf
module(load="imtcp")
input(type="imtcp" port="514")
module(load="imudp")
input(type="imudp" port="514")

# Send log messages to Fluentd
*.* @fluentd:5140
```

この場合だとログをすべてfluentdに転送していますが、特定の機器のログだけを転送する場合、

```
if $fromhost-ip == "192.168.100.110" or
   $fromhost-ip == "192.168.100.111" then @fluentd:5140
& stop
```

のようにすればOKです。

##fluentd
### Dockerfile
[公式のイメージ](https://hub.docker.com/r/fluent/fluentd/)が提供されているのですが、[rewrite-tag-filter](https://docs.fluentd.org/output/rewrite_tag_filter)プラグインを追加で突っ込んでおきます。

```Dockerfile
FROM fluent/fluentd
RUN gem install fluent-plugin-rewrite-tag-filter
```

### fluentd.conf
以下の例では、rewrite-tag-filterプラグインを使って、ネットワーク機器のアドレスによってログの出力先を変更しています。

```fluentd.conf
<source>
  @type syslog
  port 5140
  bind 0.0.0.0
  tag rsyslog
  <parse>
    @type syslog
    message_format auto
  </parse>
</source>

<match rsyslog.**>
  @type rewrite_tag_filter
  <rule>
    key host
    pattern /^192\.168\.100\.1$/
    tag syslog.fw.fortigate
  </rule>
  <rule>
    key host
    pattern /^192\.168\.100\.110$/
    tag syslog.sw.cisco
  </rule>
  <rule>
    key host
    pattern /^192\.168\.100\.111$/
    tag syslog.sw.cisco
  </rule>
  <rule>
    key host
    pattern /.+/
    tag syslog.all
  </rule>
</match>

<match syslog.fw.fortigate>
  @type file
  path /fluentd/log/fortigate
  compress gzip
</match>

<match syslog.sw.cisco>
  @type file
  path /fluentd/log/cisco
  compress gzip
</match>

<match syslog.all>
  @type file
  path /fluentd/log/syslog
  compress gzip
</match>
```

## Docker
### docker-compose.yml
rsyslogdとfluentdのコンテナをcomposeしてしまいます。

```docker-compose.yml
version: '3'

services:

        rsyslogd:
                build: ./rsyslogd
                image: rsyslog-img
                container_name: rsyslogd
                volumes:
                        - ./rsyslogd/files/etc/:/rsyslogd/etc/
                environment:
                        RSYSLOG_CONF: /rsyslogd/etc/rsyslog.conf
                restart: always
                ports:
                        - 514:514
                        - 514:514/udp
                depends_on:
                        - fluentd
        fluentd:
                build: ./fluentd
                image: fluentd-img
                container_name: fluentd
                volumes:
                        - /root/docker/mngenv/fluentd/files/etc/:/fluentd/etc
                        - fluentd-vol:/fluentd/log
                restart: always

volumes:
        fluentd-vol:
```


## 起動
docker-composeで起動します。

```shell
# docker-compose up -d
```

これで起動したはずですので、さっそくネットワーク機器からログを転送してみます。

ログを出力するために、ネットワーク機器の適当なインタフェイスを`shutdown`して`no shutdown`してみます。

```
switch#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
switch(config)#int gi 0/6
switch(config-if)#shutdown
switch(config-if)#no shutdown
```

これでログが出力されているはずですので、fluentdのコンテナに入って確認してみます。

```shell
# docker exec -it fluentd /bin/ash
# cd /fluentd/log/cisco
/fluentd/log/cisco # ls
buffer.b5aab3c405bfd4823674a3126514cf944.log
buffer.b5aab3c405bfd4823674a3126514cf944.log.meta
/fluentd/log/cisco # cat buffer.b5aab3c405bfd4823674a3126514cf944.log
2020-07-18T09:19:08+00:00       syslog.sw.cisco {"host":"192.168.100.110","ident":"1293","message":"Jul 18 09:19:07.876: %SYS-5-CONFIG_I: Configured from console by vty0 (192.168.100.7)"}
2020-07-18T09:19:23+00:00       syslog.sw.cisco {"host":"192.168.100.110","ident":"1294","message":"Jul 18 09:19:23.485: %LINK-5-CHANGED: Interface GigabitEthernet0/6, changed state to administratively down"}
2020-07-18T09:19:23+00:00       syslog.sw.cisco {"host":"192.168.100.110","ident":"1295","message":"Jul 18 09:19:24.487: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/6, changed state to down"}
2020-07-18T09:19:27+00:00       syslog.sw.cisco {"host":"192.168.100.110","ident":"1296","message":"Jul 18 09:19:26.794: %LINK-3-UPDOWN: Interface GigabitEthernet0/6, changed state to down"}
2020-07-18T09:19:29+00:00       syslog.sw.cisco {"host":"192.168.100.110","ident":"1297","message":"Jul 18 09:19:29.258: %LINK-3-UPDOWN: Interface GigabitEthernet0/6, changed state to up"}
2020-07-18T09:19:29+00:00       syslog.sw.cisco {"host":"192.168.100.110","ident":"1298","message":"Jul 18 09:19:30.259: %LINEPROTO-5-UPDOWN: Line protocol on Interface GigabitEthernet0/6, changed state to up"}
```

おー、ちゃんとログが出力されていますね。


##さいごに
とりあえず、これでrsyslogからのfluentdでログが出力されるようになりました。
ここまで環境ができればfluentdの設定次第で、ログ分析基盤の構築ができるようになりますが、それはまたの機会に。