SSH のアクセスログを洗ってみる
SSH ポート空けてると、不正にログインしようとするやつはいるもの。
また、アカウントが盗まれて変な所から ssh されることもあり得る。
そんなこんなで、/var/log/auth* なログファイルをパースしてディレクトリに振り分ける処理をざっくり書く。
わざとシーケンシャルに書いてみた ubuntu のログで多分パースできるはず。
import java.io.{PrintWriter, File}
import org.slf4j.LoggerFactory
import scala.io.Source
object AuthLogUtil {
val sshLogPattern = """^([A-Z][a-z]{2}\s+\d\s\d{2}:\d{2}:\d{2}) ([a-z]+) sshd\[\d+\]: (.+)$""".r
val acceptPattern = """^Accepted .+? for ([_a-zA-Z0-9\- ]+?) from ([0-9.]+).*""".r
val invalidPattern = """^Failed .+? for ([_a-zA-Z0-9\- ]+?) from ([0-9.]+).*""".r
val distDir = "./replaces"
val sourceDir = "./sources"
val valid = "valid"
val invalid = "invalid"
def makePath(path:String*):String = {
path.mkString(File.separator)
}
def using[T <: {def close()}, R](src:T)(func:T => R):R = {
try {
func(src)
} finally {
src.close()
}
}
}
class AuthLogUtil {
import AuthLogUtil._
val log = LoggerFactory.getLogger(getClass)
def isSSHLog(str:String):Boolean = {
sshLogPattern.findFirstIn(str) match {
case Some(_) => true
case _ => false
}
}
def acceptLog(user:String, ip:String, dateTime:String, host:String) {
val path = makePath(distDir, valid, user.replaceAll(" ", "_"), ip)
val dir = new File(path)
// ディレクトリなければ作る
if(!dir.exists()) dir.mkdirs()
// ファイルに書き込む
val filePath = path + File.separator + "auth.log"
using(new PrintWriter(filePath)) { fileWriter =>
fileWriter.println("%s %s %s(%s)".format(dateTime, host, user, ip))
}
}
def invalidLog(user:String, ip:String, dateTime:String, host:String) {
val path = makePath(distDir, invalid, user.replaceAll(" ", "_"), ip)
val dir = new File(path)
// ディレクトリなければ作る
if(!dir.exists()) dir.mkdirs()
// ファイルに書き込む
val filePath = path + File.separator + "auth.log"
using(new PrintWriter(filePath)) { fileWriter =>
fileWriter.println("%s %s %s(%s)".format(dateTime, host, user, ip))
}
}
def parse(logLine:String) {
logLine match {
// sshd っぽいログだけ処理
case sshLogPattern(dateTime, host, message) => {
message match {
// accept 系ログだけ処理
case acceptPattern(user, ip) => acceptLog(user, ip, dateTime, host)
// invalid 系ログだけ処理
case invalidPattern(user, ip) => invalidLog(user, ip, dateTime, host)
// それ以外のログ
case other => log.warn("Not a Accept or Invalid : " + logLine)
}
}
// 一致しないものは処理しない
case _ =>
}
}
}
object LogRelocator extends App {
import AuthLogUtil.{sourceDir, using}
val log = LoggerFactory.getLogger(getClass)
// 先ずは対象ファイルを列挙
val sources = new File(sourceDir)
// logLine 処理クラス
val executer = new AuthLogUtil
// ファイルを1個づつ処理
sources.list().foreach(fileName => {
log.info("Execute file : %s".format(fileName))
// ファイルをオープン
using(Source.fromFile(sourceDir + File.separator + fileName)) { source =>
// 1行づつ処理
source.getLines().foreach(executer.parse)
}
})
}時間がかかってくれることを期待したのだけれど、自宅サーバ(しかもポート変えてると)不正ログインないなーというか、ファイルサイズが小さくて数百ミリ秒で終わってしまう。
どうすべ。。。。