せっかくなのでログ解析

タイトル負けしてます。解析なんてしてません。はい。ごめんなさい。

ということで、毎度のおまじない。

この記事は忘備録です。ド素人が思い付きでやっつけ仕事で行ったので、何が起こっても責任は取りませんので悪しからず。

さて、先日パスワードが漏れてるぞーとwordpressに注意されたので、せっかくならログ解析モドキでもしてみようと思いました。なのでその忘備録です。

到着地点:dockerの吐き出したログから怪しげなモノを拾い出し、Discordに通知を送る。

ではまず、docker のログを拾い集めるところから。

$/usr/local/bin/docker-log-discord.sh

#!/bin/bash

WEBHOOK_URL="https://discord.com/api/webhooks/aaaaa/xxxxx"
ALERT_LOG="/tmp/docker-alerts.log"


echo "[DEBUG] $(date): docker-log-discord.sh started" >> /var/log/docker-log-discord.log

echo "==== $(date) ====" > $ALERT_LOG

for c in $(docker ps --format "{{.Names}}"); do
    echo "### $c" >> $ALERT_LOG
    docker logs --since 6m "$c" 2>&1 \
      | grep -vE "(tt-rss|Channel)" \
      | grep -Ei "(failed|unauthorized|forbidden|denied|attack|intrusion| 403 | 401 )" >> $ALERT_LOG
done

# Pythonにログ送信を任せる
/usr/bin/python3 /usr/local/bin/docker-log-discord.py

docker logsから6分間のログを引っ張る。:–since 6m

これが一時間引っ張りたいなら1hとすればいい。

いろんなdockerが動いているので、forループで名前の数だけ繰り返す:–format “{{.Names}}”

この状態では全部のログが集まってるはずなので、この中から拾いたいところだけをピックアップする。まずはいらない部分を消す:grep -vE

次に必要な部分をチョイスする:grep -Ei

さて、これで見たいログだけが残ったことになる。これを、DiscordのWeb hookが受け取れるjson形式に整形して投げ渡す。この部分はPythonに任せる。

では、そのPythonに取り掛かる。

$ cat /usr/local/bin/docker-log-discord.py
#!/usr/bin/env python3

import requests
import os
import hashlib

WEBHOOK_URL = "https://discord.com/api/webhooks/aaaaa/xxxxx"
ALERT_LOG = "/tmp/docker-alerts.log"
HASH_RECORD_FILE = "/var/lib/docker-log-alert/docker-alerts-hash.txt"

# 過去に送ったログのハッシュを読み込み
sent_hashes = set()
os.makedirs(os.path.dirname(HASH_RECORD_FILE), exist_ok=True)

if os.path.exists(HASH_RECORD_FILE):
    with open(HASH_RECORD_FILE, "r") as f:
        sent_hashes = set(line.strip() for line in f.readlines())

if os.path.exists(ALERT_LOG) and os.path.getsize(ALERT_LOG) > 0:
    with open(ALERT_LOG, "r") as f:
        lines = f.readlines()

    current_container = None

    for line in lines:
        line = line.strip()
        if not line:
            continue

        if line.startswith("===="):
            continue  # 日付行はスキップ
        if line.startswith("### "):
            current_container = line.replace("###", "").strip()
            continue

        # ハッシュを計算
        log_hash = hashlib.sha256(line.encode("utf-8")).hexdigest()

        # 既に送信済みならスキップ
        if log_hash in sent_hashes:
            continue

        # メッセージ送信
        log_snippet = line[:1900]
        container_label = f"[`{current_container}`]" if current_container else "[unknown]"

        payload = {
            "content": f"🚨 **Dockerログアラート** {container_label} 🚨\n```log\n{log_snippet}\n```"
        }

        headers = {
            "Content-Type": "application/json"
        }

        response = requests.post(WEBHOOK_URL, json=payload, headers=headers)

        if response.status_code == 204:
            print(f"[OK] {container_label} -> {line}")
            sent_hashes.add(log_hash)  # 成功したら記録
        else:
            print(f"[ERROR] Discord通知失敗: {response.status_code}")

    # 成功したハッシュをファイルに保存
    with open(HASH_RECORD_FILE, "w") as f:
        for h in sent_hashes:
            f.write(h + "\n")
else:
    print("ログが空なので送信しませんでした。")

さて、ここで一つお知らせが。

Pythonなんて全く知りません。これっぽっちも触ったことありません。ちょっとは勉強してみようかなーと半年くらい前に思っただけです。

なので、chatGPTにポイっと丸投げしたら、上記が返ってきました。すごいね。

ということで、完成。

これを、5分おきにcronで実行すればOK.

$docker-log-discord

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

*/5 * * * *     root     /usr/local/bin/docker-log-discord.sh >> /var/log/docker-log-discord.log 2>&1

おわり。

カテゴリー: Linux、サーバー, PC関連 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA