【syslog入門 第5回】rsyslog 後編 ― テンプレート、フィルターと振り分け、送信元ごとのファイル、TLS、RELP、メール発報、レート制限

syslog入門 第5回 rsyslog 後編 SYSLOG サーバー

「受信したログを送信元ごとのファイルに分けたいんですが、ホスト名が機器によってばらばらで……」
「障害の時間帯のログだけ、なぜか抜けています」

第4回(前編)では、rsyslogの構成とキュー、受信・転送の設定を見ました。第5回(後編)では、受け取ったログをどんな形で、どこに書くか(テンプレート・振り分け)、どう守るか(TLS・RELP)、そしてログが突然消える原因(レート制限)を扱います。


テンプレート

組み込みテンプレート出力の形主な用途
RSYSLOG_TraditionalFileFormatSep 26 10:15:01 web01 sshd[812]: …(秒まで、年とタイムゾーンなし)RHEL の既定(ファイル)
RSYSLOG_FileFormat2026-09-26T10:15:01.123456+09:00 web01 sshd[812]: …omfile の本来の既定。集約先ではこちらを推奨
RSYSLOG_TraditionalForwardFormat<PRI> + RFC 3164 の形omfwd の既定
RSYSLOG_SyslogProtocol23Format<PRI>1 時刻 ホスト名 アプリ名 PROCID MSGID 構造化データ MSG +改行RFC 5424 で転送する
# 送信元のホスト名と日付でファイルを分ける(動的ファイル)
template(name="PerHostDaily" type="string"
         string="/var/log/remote/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%.log")
ruleset(name="remote") {
    action(type="omfile" dynaFile="PerHostDaily" template="RSYSLOG_FileFormat")
}
# RFC 5424 の形式で転送する
action(type="omfwd" target="192.0.2.50" port="514" protocol="tcp"
       template="RSYSLOG_SyslogProtocol23Format")
  • テンプレートには、ファイル名を決めるもの(dynaFile=)と、1行の形を決めるもの(template=)の2つの使い道がある
  • %HOSTNAME%はメッセージの中のホスト名で、送信元が自由に書ける(後の節)
  • type="list"で、項目を1つずつ並べる書き方もある。組み込みと同じ名前で定義するとエラーになる
  • 年とタイムゾーンのない形式は、集約先での突き合わせを難しくする(第7回、連載「NTP入門」)。集約先ではRSYSLOG_FileFormatを使う

フィルターの3つの書き方

書き方例向いている場面
セレクターmail.warning、*.info;mail.nonefacility と severity だけで分ける
プロパティベース:programname, isequal, “sshd”1つの項目を1つの条件で比べる
RainerScript の ifif $programname == “sshd” and $syslogseverity <= 4 then複数の条件、入れ子、正規表現。推奨
mail.warning                       action(type="omfile" file="/var/log/mail-warn.log")
:programname, isequal, "sshd"      action(type="omfile" file="/var/log/sshd.log")
:msg, contains, "I/O error"        action(type="omfile" file="/var/log/io-error.log")
if $programname == "sshd" and $syslogseverity <= 4 then {
    action(type="omfile" file="/var/log/sshd-warn.log")
}
if re_match($msg, "Failed password for .* from") then {
    action(type="omfile" file="/var/log/ssh-fail.log")
}
  • severityは数値が小さいほど重大で、$syslogseverity <= 4はwarning以上。数値で比べるときは引用符を付けない
  • $syslogseverity-textはinfoのような文字列なので、大小を比べられない
  • セレクターのmail.warningはwarning以上、mail.=warningはwarningだけ

送信元・文字列で振り分ける

ruleset(name="remote") {
    if $fromhost-ip == "192.0.2.21" or $fromhost-ip == "192.0.2.22" then {
        if $syslogseverity <= 6 then action(type="omfile" file="/var/log/remote/web.log")
        stop
    }
    if $syslogfacility-text == "mail" then {
        if $programname == "postfix" then action(type="omfile" file="/var/log/remote/postfix.log")
        else if $programname == "dovecot" then action(type="omfile" file="/var/log/remote/dovecot.log")
        else action(type="omfile" file="/var/log/remote/maillog")
        stop
    }
    action(type="omfile" file="/var/log/remote/others.log")
}
上から順に評価し、送信元が192.0.2.21/22ならseverity≤6をweb.logに書いてdebugは捨ててstop、facilityがmailならprogramnameでpostfix.log・dovecot.log・maillogに分けてstop、どれにも当たらなければothers.logに書くので、一致した段でstopして1件は1つのファイルにだけ入ることを示す図
  • 「送信元で分類」「文字列で分類」を1つのルールセットにまとめた例。上から順に評価される
  • stopは、そのメッセージの処理をそこで終える(旧形式の& ~に当たる)。書かないと下のothers.logにも書かれる
  • Webサーバー2台からのdebug(7)は捨て、info以上だけを残す。stopをifの外に置くことで、捨てる分も下へ流れない
  • postfixのタグpostfix/smtpd[1234]:の$programnameはpostfix(既定では/の前まで)
  • 比較の演算子:==・!=・contains・startswith・<=など。正規表現はre_match()

送信元ごとのファイルに保存する

冒頭の「ホスト名がばらばら」は、どのプロパティを使うかの問題です。

プロパティ値の出どころ注意
%HOSTNAME%メッセージの中のホスト名送信元が自由に書ける(偽れる)。ホスト名を入れない機器もある
%FROMHOST%直接の送信元の IP アドレスを逆引きした名前逆引きの待ち時間。中継を挟むと中継の名前になる
%FROMHOST-IP%直接の送信元の IP アドレス確実だが、中継を挟むと中継の IP になる
template(name="PerHostFile" type="string"
         string="/var/log/remote/%FROMHOST-IP%/%$YEAR%%$MONTH%%$DAY%.log")
ruleset(name="remote") {
    action(type="omfile" dynaFile="PerHostFile"
           dirCreateMode="0750" fileCreateMode="0640"
           dynaFileCacheSize="200")
}
module(load="imudp")
input(type="imudp" port="514" ruleset="remote")
  • 中継を挟まないなら、%FROMHOST-IP%が確実
  • dynaFileCacheSize(開いておくファイルの数、既定10)が送信元の数より少ないと、開閉を繰り返して遅くなる
  • 日付入りのファイルはlogrotateでは消えないため、古いファイルを消す仕組みを別に用意する(第7回)

TLSの設定(受信側)

# ログサーバー logsv01(rsyslog-gnutls が必要)
global(
    DefaultNetstreamDriverCAFile="/etc/pki/rsyslog/ca.pem"
    DefaultNetstreamDriverCertFile="/etc/pki/rsyslog/logsv01-cert.pem"
    DefaultNetstreamDriverKeyFile="/etc/pki/rsyslog/logsv01-key.pem"
)
module(load="imtcp"
       StreamDriver.Name="gtls"                # OpenSSL を使うなら "ossl"
       StreamDriver.Mode="1"                   # 1 = TLS だけを受け付ける
       StreamDriver.AuthMode="x509/name"       # 相手の証明書の名前を確かめる
       PermittedPeer=["*.corp.example.jp"])
input(type="imtcp" port="6514" ruleset="remote")
証明書を持たない不明なPCはPermittedPeerに合わず拒否され、証明書のCN/SANがweb01.corp.example.jpのweb01はCAで検証し名前を照合して受け付けられ、ログサーバーlogsv01の6514/TCP(TLS)の入口にはCA証明書(ca.pem、送信元の証明書を確かめる)、サーバー証明書(logsv01-cert.pem)、rootだけが読める秘密鍵(logsv01-key.pem)を置くことを示す図
  • 用意するもの:ログサーバーの証明書と秘密鍵、送信元の証明書を確かめるためのCA証明書。社内CAで発行するのが一般的(連載「証明書入門」第6回・第9回)。秘密鍵はrootだけが読めるようにする
  • 暗号化の仕組み(ドライバー)は、gtls(GnuTLS、rsyslog-gnutls)かossl(OpenSSL、rsyslog-openssl)を選ぶ
  • x509/nameとPermittedPeerで、許可した名前の証明書を持つ送信元だけを受け付ける(送信元にも証明書が要る=相互認証。連載「証明書入門」第7回)
  • module()に書いたTLSの設定は、すべてのimtcpの入力に効く。平文の514とTLSの6514を1台で受けるときは、TLSの項目(StreamDriver.Modeなど)をinput()側に書く(8.2310以降)
  • ポートは6514/tcp(RFC 5425)。firewalldとSELinuxは第4回

TLSの設定(送信側)と認証モード

# 送信側 web01
global(
    DefaultNetstreamDriverCAFile="/etc/pki/rsyslog/ca.pem"
    DefaultNetstreamDriverCertFile="/etc/pki/rsyslog/web01-cert.pem"
    DefaultNetstreamDriverKeyFile="/etc/pki/rsyslog/web01-key.pem"
)
action(type="omfwd" target="logsv01.corp.example.jp" port="6514" protocol="tcp"
       StreamDriver="gtls" StreamDriverMode="1"
       StreamDriverAuthMode="x509/name"
       StreamDriverPermittedPeers="logsv01.corp.example.jp"
       template="RSYSLOG_SyslogProtocol23Format"
       queue.type="LinkedList" queue.filename="fwd_tls"
       queue.maxDiskSpace="1g" queue.saveOnShutdown="on"
       action.resumeRetryCount="-1")
認証モード確かめること使いどころ
anon何も確かめない(暗号化だけ)検証用。なりすましを防げない
x509/certvalid信頼する CA が発行した有効な証明書か社内 CA の証明書なら誰でもよい場合
x509/name上に加え、証明書の名前(SAN・CN)が許可した名前か推奨。許可する名前を PermittedPeer で指定
x509/fingerprint証明書のフィンガープリントが一致するかCA を使わない少数の構成

接続はopenssl s_client -connect logsv01.corp.example.jp:6514 -CAfile ca.pem -cert web01-cert.pem -key web01-key.pemで確かめます(連載「証明書入門」第7回)。Windowsでは、Test-NetConnectionと、連載「証明書入門」第7回のPowerShellの方法を使います。TLSが防ぐのは盗聴となりすましで、到達の保証ではありません(次の節)。


RELP(到達を保証する)

# 受信側 logsv01(rsyslog-relp が必要)
module(load="imrelp")
input(type="imrelp" port="20514" ruleset="remote" tls="on"
      tls.caCert="/etc/pki/rsyslog/ca.pem"
      tls.myCert="/etc/pki/rsyslog/logsv01-cert.pem"
      tls.myPrivKey="/etc/pki/rsyslog/logsv01-key.pem"
      tls.authMode="name" tls.permittedPeer=["*.corp.example.jp"])
# 送信側 web01
module(load="omrelp")
action(type="omrelp" target="logsv01.corp.example.jp" port="20514" tls="on"
       tls.caCert="/etc/pki/rsyslog/ca.pem"
       tls.myCert="/etc/pki/rsyslog/web01-cert.pem"
       tls.myPrivKey="/etc/pki/rsyslog/web01-key.pem"
       tls.authMode="name" tls.permittedPeer=["logsv01.corp.example.jp"]
       queue.type="LinkedList" queue.filename="fwd_relp" action.resumeRetryCount="-1")
TCPではlogsv01が落ちると送信バッファーにあった102・103が失われるのに対し、RELPでは101・102にrsp(受け取った)が返り、応答の無い103を再接続後に再送することと、TCPのACKはOSが返し、RELPはrsyslogが受け取ってから返すことを示す図
  • RELP(Reliable Event Logging Protocol)は、rsyslogの開発元が作ったプロトコル(RFCではない)。受信側がアプリケーションの層で受け取りを応答し、応答の無い分を再送する
  • TCPだけでは、切断の瞬間に送信バッファーにあった分が失われうる。RELPはこれを防ぐ(再送により、まれに重複はありうる)
  • RELP自体は暗号化しない。tls="on"でRELP over TLSにする。到達保証はRELP、暗号化はTLS(第2回)
  • 標準のポート番号は無い。20514は、RHELのSELinuxでsyslogd_port_tに含まれる(第4回)
  • 送信側と受信側の両方が対応している必要がある(rsyslog同士、vCenterなど。第6回)。送信側のキューは第4回と同じく付ける

メール発報(ommail)

module(load="ommail")
template(name="mailSubject" type="string" string="[syslog] disk error on %hostname%")
template(name="mailBody" type="string"
         string="RSYSLOG Alert\r\nhost: %hostname%\r\nmsg: %msg%")
if $msg contains "I/O error" then {
    action(type="ommail" server="mail.corp.example.jp" port="25"
           mailFrom="rsyslog@logsv01.corp.example.jp"
           mailTo=["infra-alert@corp.example.jp"]
           subject.template="mailSubject"
           template="mailBody"
           action.execOnlyOnceEveryInterval="21600")
}
同じ障害で何百件も届くI/O errorのログを、logsv01のif $msg contains "I/O error"で一致させてommailに渡し、6時間に1通まで(21600秒)に抑えて中継SMTPサーバーmail.corp.example.jp(25/tcp)経由で担当者のメールボックスinfra-alert@corp.example.jpに1通だけ届けることを示す図
  • 本文のテンプレートはtemplate=で指定する。body.templateというパラメーターは無く、-N1でエラーになる
  • action.execOnlyOnceEveryInterval="21600":6時間に1通まで。同じ障害で大量のメールが届くのを防ぐ
  • ommailはSMTP認証とTLSに対応しない。社内の中継用SMTPサーバー(25/tcp)に渡す(連載「メール入門」第8回)
  • 条件は文字列の一致なので、メッセージの文言が変わると検知できない。本格的な監視は、監視システムやSIEMで行う(第8回)

レート制限 ― ログが突然消える原因

冒頭の「障害の時間帯のログだけ抜ける」の、よくある原因です。

どこで既定の上限捨てたときの記録
journald(サービスごと)30秒に 10,000件Suppressed N messages from …
imjournal(journal → rsyslog)600秒に 20,000件imjournal: N messages lost due to rate-limiting (20000 allowed within 600 seconds)
imuxsock(/dev/log)既定は無効(有効時の既定 200件)… begin to drop messages due to rate-limiting
imudp・imtcp の入力既定は無効—
# RHEL の /etc/rsyslog.conf にある imjournal の行を書き換える(2回目の module() は書かない)
module(load="imjournal" StateFile="imjournal.state" UsePid="system"
       Ratelimit.Interval="600" Ratelimit.Burst="50000")
$ sudo journalctl --since today | grep -E "Suppressed|rate-limiting"
大量に出すサービスのログが、journald(30秒に1万件)とimjournal(600秒に2万件)のレート制限を超えると捨てられ、SuppressedやN messages lost due to rate-limitingの記録がjournalctlに残り、集約先からはその時間だけログが無いようにしか見えないことと、記録を探す、出している側を疑う、必要なら上限を上げるという対処の順番を示す図

大量のログを出すサービスがあると、上限を超えた分は黙って捨てられ、集約先では「その時間だけログが無い」ように見えます。まず記録を探し、上限を上げる前に、出している側(デバッグ出力の出しっぱなしなど)を疑います。0にすると制限を外せますが、暴走したアプリケーションにディスクとCPUを奪われるため勧めません。


考えてみよう

  1. 自分の環境の転送設定で、ログサーバーが1時間止まったらログはどうなりますか。UDP、TCP(キューなし)、TCP+ディスクへの退避、RELPで比べてください。
  2. 受信したログを送信元ごとのファイルに分けるとき、%HOSTNAME%と%FROMHOST-IP%のどちらを使いますか。中継サーバーを挟む場合はどうしますか。
  3. 「ログを暗号化したい」「1件も落とさず届けたい」と言われたら、それぞれ何を設定しますか。両方のときはどうしますか。

ヒント:第4回のDirectとアクションキュー、欠損させない仕組みの限界、この記事のプロパティの表、TLSの認証モード、RELPの図が手がかりです。


まとめ

  • テンプレートはファイル名(dynaFile)と1行の形(template)。集約先はRSYSLOG_FileFormat、転送はRFC 5424
  • フィルターはRainerScriptのifが推奨。数値は$syslogseverity <= 4、stopで重複を防ぐ
  • 送信元ごとのファイルは%FROMHOST-IP%が確実。dynaFileCacheSizeと古いファイルの削除も
  • TLSはx509/name+PermittedPeerで相互認証。暗号化するが、到達は保証しない
  • 到達保証はRELP(RFCではない)。暗号化も要るならRELP over TLS
  • ommailは間隔を空けて1通に。本格的な監視はSIEMで
  • 「その時間だけ無い」はレート制限を疑い、記録を探してから出している側を直す

次回は、Windows・ネットワーク機器・ESXiなど、Linux以外のログをどう集めるかを扱います。


連載「syslog入門」全11回

全回の目次と、読む順番・目的別の読み方は、syslog入門の入口のページにまとめています。

  1. ログとは・なぜ集めるか
  2. syslogの基本
  3. Linuxのログの仕組み
  4. rsyslog 前編
  5. rsyslog 後編(この記事)
  6. Windows・ネットワーク機器のログ
  7. ログ集約基盤の設計
  8. 分析と監視・SIEM
  9. クラウドのログ
  10. syslogのトラブルシュート
  11. ログ管理の設計演習
seichan

プロフィール詳細は「プロフィール」をご覧ください。
AWS Certified Solutions Architect – Professional (https://www.credly.com/badges/fd8feb88-6f1f-42ff-a94b-445bb6661cb8/public_url)
Nutanix Certified Professional - Multicloud Infrastructure 6 (https://www.credly.com/badges/5c081bef-a425-42e4-809c-85138e676630/public_url)
Palo Alto Networks System Engineer (PSE) - Hardware Firewall Professional (https://www.credly.com/badges/69dc3880-4a51-47eb-8843-47ba6ea7d013/public_url)

seichanをフォローする
SYSLOG サーバー
シェアする
seichanをフォローする

コメント

タイトルとURLをコピーしました