rsyslogでのキューを使った確実な送受信

# はじめに
　この記事は、[rsyslogでのTLS(SSL)によるセキュアな送受信](https://qiita.com/saeki4n/items/b30e619d9371f7808657) の関連記事になります。

　前回、[rsyslogでのTLS(SSL)によるセキュアな送受信（暗号化かつ認証あり）](https://qiita.com/saeki4n/items/f7de2c948316c0d021dd)にて、syslog通信を端末認証かつ暗号化してセキュアな通信をすることができました。
　情報セキュリティの３大要素CIAに照らし合わせてみると、暗号化で『機密性（Confidentiality）』が確保できて、端末認証で『完全性（Integrity）』が確保できました。
　しかし『可用性（Availability）』の対策が出来ていません。クライアント側が送信した時にサーバー側がダウンしていたら情報が失われてしまう状況です。
　そこでキューを用いて、サーバー側がダウンしていたとしても、復旧するまで繰り返し接続を行うようにしていきます。

　検証環境は引き続き CentOS8 と Ubuntu(18.04)です。
　syslog送信側（クライアント）：CentOS(rsyslog version 8.37.0), IP=192.168.0.15
　syslog受信側（サーバー）：Ubuntu(rsyslog version 8.32.0), IP=192.168.0.13

#rsyslogで利用できるキューの種類
　rsyslogで使用できるキューのモードは次の通りです。


| キューの種類     | モード名(Type) | 概要    |
|:----------------|:------------------|:------------------|
| ダイレクトキュー |Direct    |キューを使用しないモード（デフォルト）|
| ディスクキュー   |Disk      | ハードディスクにキューを作成する。大量キューを保存できるが処理は遅い。|
| インメモリキュー | FixedArray|  メモリにキューを作成する。事前に固定量を確保。高速に動作する。|
| インメモリキュー | LinkedList | メモリにキューを作成する。動的にメモリを確保する。FixedArrayに比べると劣るが高速に動作する。どれぐらい量が不明な場合はこちら。 |

参考：
Understanding rsyslog Queues
https://www.rsyslog.com/doc/v8-stable/concepts/queues.html

「LinkedListモードを使用することをお勧めします」とあるので、こちらを使って行こうと思います。

# rsyslogの設定

　キューを使用するためには送信するクライアント側の設定が必要になります。

## クライアント側のrsyslogの設定
　使用するキューの設定を actionに加えていきます。
　またこれまでは全ログが転送となっていましたが、検証がややこしくなるので、任意のログのみを転送するように切り替えます。今回は Facility が local0 のログを転送対象とします。

```
local0.* action(type="omfwd"
                protocol="tcp" port="514"
                Target="192.168.0.13"
                StreamDriver="gtls"
                StreamDriverMode="1"
                StreamDriverAuthMode="x509/name"
                StreamDriverPermittedPeers="server.example.jp"
                queue.filename="example_data"
                queue.maxdiskspace="1g"
                queue.saveonshutdown="on"
                queue.type="LinkedList"
                action.resumeRetryCount="-1"
)

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/aadb9d66-9c95-cd09-4b4b-52940fd23247.png)

**追加した設定の詳細**

 - local0.* : Facility がlocal0、Severityは全てを転送する
 - queue.filename="example_data" : キューファイル名。接頭語がexample_dataというファイルが作成される。インメモリキューの場合に設定するとディスク支援キューとなる。
 - queue.maxdiskspace="1g" : ディスク支援キューの最大ディスクスペースを設定する
 - queue.saveonshutdown="on" : シャットダウン時にデータを保存する。モードがディスクまたはディスク支援キューでないとダメ
 - queue.type="LinkedList" : キューモードはLinkedListを指定
 - action.resumeRetryCount="-1" : サーバーが無応答の場合のリトライ回数。マイナス1の場合は無制限にリトライし続ける

※ディスク支援キュー：インメモリキューが何らかの理由（例：キューがいっぱいになる。シャットダウンになる等）で使用不可になった場合にディスクキューが有効になる機能

---
　この設定で再起動を行い、問題が発生していないか確認しておきます。

```
$ sudo systemctl restart rsyslog.service
$ sudo systemctl status rsyslog.service
```

# 正常時の挙動
　まずは正常状態でクライアントログが転送されるかの確認を行います。
　今回、転送ログは Facility制限を行ったので、logger のオプション -p (--priority)で優先度を指定する必要があります。

```
$ logger -p local0.info "HelloServer"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/e62defe4-1bc3-976a-ab2d-dd76d50c8505.png)

　サーバー側でログ転送ができていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/a50f83e5-f30a-0a8b-11c1-e67db2ec8399.png)

# サーバー側が停止していた時の挙動
　ここでサーバー側の rsyslogの機能を停止させます。確実性を期すためにサーバー自体をシャットダウンしてもいいかもしれません。
　今回は rsyslogサービスの停止でいこうと思います。すると警告が出てしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/bfb769cd-fcaf-647d-5711-a80d8aaef985.png)
　「停止しようとしたけど、syslog.socket のせいで出来なかった」ってことでしょうか。
　よく分かってはいませんが、Ubuntuの場合はsyslog.socketを落としてから、rsyslog.serviceを落とす必要があるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/d7fa2167-6462-8253-3b13-578a9090792d.png)

　ステータスが停止していることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/55416d90-2498-fede-f332-f9a05c435d14.png)

　この状態で 再度ログを転送させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/720ad395-add9-9093-8911-7c372450b5d0.png)
　するとクライアント側のrsyslogサービスのエラーが確認できます。サーバー側のサービスが停止しているので当然ですね。

```:クライアント側のサービス確認
$ sudo systemctl status rsyslog.service
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/ab964f57-ddfd-bfef-fc34-3998dd57f7f4.png)

　ここで停止していたサーバー側のrsyslogのサービスを再開します。するとサービス停止していた時のログが、再度クライアントから送られてきており、無事に受信できていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/0e577fb1-316b-3ed2-032e-c1ff77c79512.png)

#サーバー側の停止時にクライアント側も停止した時の挙動
　ここではサーバー側が停止していた時に、同時にクライアント側も停止した時の挙動を確認していきます。
　先のと同様にサーバー側のrsyslogのサービスを停止している状態で、クライアント側からログを転送します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/d2a3c005-b44b-9d17-32ec-1e8d5f8796a2.png)
　同じくクライアント端末の方ではエラーが発生しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/e2a24f4b-ef27-5dc5-7726-9d8f81cfc524.png)

## クライアント端末の再起動の挙動
　この状態で、クライアント端末を再起動します。何らかのインシデントが発生したという想定です。
　再起動後、`/var/lib/rsyslog/` の中身を確認すると、`example_data` から始まるファイルが2つできており、ディスク支援機能が上手く働いていることが確認できます。中身は送ろうとしてSyslog情報のようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/a394571b-03fd-e933-c898-59170b142aa1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/36813ed1-5477-4f57-5a11-20ebf961ed93.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/b1dc2c01-df74-e3c6-403e-eacb14fe7cfa.png)

　ここで確認している`/var/lib/rsyslog/` はConfigファイルの WorkDirectory で設定されている箇所になります。そのためCentOSでは先のPathでしたが、Ubuntuでは異なっており、確認したところ`/var/spool/rsyslog/` でした。ディストリビューションによって異なるみたいですので適宜確認してください。

・CentOSの場合：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/38a70fc9-27b7-e2aa-2d1f-f32e7933f42e.png)
・Ubuntuの場合:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/63b8c16b-373f-0214-e33a-1353024409bf.png)

　ここでサーバー側のrsyslogを開始します。サーバー側も復旧したという想定です。
　サーバー側のログを確認すると、クライアント側がサーバーダウン時に転送しようとしたログ情報が正しく受信できていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/699ae22f-3c48-6305-9102-63efe9496612.png)

## クライアント端末のrsyslogサービス再起動時の挙動
　次にクライアント端末の再起動ではなく、rsyslogサービスを再起動した時の挙動を見ていきます。
　`systemctl restart rsyslog.service` ですが、この操作には少し時間がかかるようです。おそらくファイル保存をしているためでしょう。

```:クライアント側のサービス再起動
$ sudo systemctl restart rsyslog.service
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/33637cce-e912-1188-55f5-870e238db117.png)

　この状態で、`/var/lib/rsyslog/` の中身を確認すると、`example_data` から始まるファイルがありますが、クライアント再起動時と違って、.qiファイルはできていません。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/855ef866-01dd-b2ca-0a98-79403765a4d9.png)
　
　ここでサーバー側のrsyslogを再開します。
　ところがいくら待ってもログ転送が行われません。クライアント側のrsyslogをステータスを見ても、再送信が発生しているようには見えません。
　念のため別のログ転送を試みてみたところ、それは無事にサーバー側に届くことが確認できました。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/e5aa3afe-95a0-caa5-c37c-fe7fcf97af34.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430322/f60bbc7f-ea25-86a3-6d19-ff9839fcbf2e.png)

　クライアント側のrsyslogサービス再起動の場合はログの再送信は発生しないようです。ただしディスク保存はされているので、そこからリカバリできそうです。
　ログの再送信が発生しないのは、.qi がファイルが無いためと考えられます。その推測が正しい場合、サービス再起動時でも.qiを作成する設定がどこかにあるような気がします。[^1]
[^1]: queue.saveonshutdown でシャットダウン時の保存ができているのでqueue.saveonrestart みたいな。
　
　なお、**この状態で 再度 rsyslogサービスを再起動すると、保存されているログデータ(example_data.00000001)は消えてしまう**ので注意してください。

# まとめ
- キューを使用することで、サーバー側とクライアント側のどちらか、または両方で障害が発生した場合の対応が可能です。
- サーバー側の停止時にクライアント端末で再起動が発生しても、サーバー側が復旧すれば、サーバー停止時のログの転送が可能です。
- 一方で、同じ設定では、サーバー側が停止時にクライアント側のrsyslogサービスの再起動が発生すると、サーバー側が復旧しても、rsyslogサービス再起動前のログ転送は行われません。ただしディスク保存はされています。
- サービス再起動時にもログ転送が復旧できればいいのですが、現状その設定を見つけられていません。[^1]

# 参考
- [RSyslog Documentation Understanding rsyslog Queues](https://www.rsyslog.com/doc/v8-stable/concepts/queues.html)
- [RSyslog Documentation Actions](https://www.rsyslog.com/doc/master/configuration/actions.html)
- [23.4. RSYSLOG でのキュー (QUEUE) を使った操作](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/s1-working_with_queues_in_rsyslog)
- [Rsyslog : リモートホストにログを転送する](https://www.server-world.info/query?os=CentOS_8&p=rsyslog&f=2)