読者です 読者をやめる 読者になる 読者になる

phpとか

自分用備忘録なので、自分が分かる程度にしか書いてません。

sshログインエラー & ログイン成功 通知

Linux シェルスクリプト

前にsshログインエラーの通知script組みましたが、よく考えたら、ログイン成功のほうがやばいですね
starfam.hatenablog.com

ということで、ログインに成功した場合も通知するように修正しました。

#!/bin/sh

#
# init
#

# common
DATE_OK=1
FLG=0
LOG=""
IP=""
OK_IP_ARR=("許可IP" "許可IP")

#
# get the last line of log for login error.
#

getLog(){
  # init
  LOG=""
  FLG=0
  GREP=""

  # grep
  for OK_IP in "${OK_IP_ARR[@]}"
  do
    GREP=${GREP}" | grep -v \"${OK_IP}\""
  done

  # log get
  LOG_GET_SC="cat /var/log/secure | grep \"$1\"${GREP} | tail -1 | awk '{print \$1\"__\"\$2\"__\"\$3\"__\"\$$2}'"

  # valid
  LOG=`eval ${LOG_GET_SC}`
  if test "$LOG" = ""; then
    FLG=1
  fi
}


#
# investigate the date
#

investigateDate(){
  MONTH_ARR=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
  ARR=(`echo ${LOG} | tr -s '__' ' '`)
  _MONTH=${ARR[0]}
  MONTH=1
  DATE=${ARR[1]}
  TIME=${ARR[2]}
  IP=${ARR[3]%:}
  DATETIME=""

  for ITEM in "${MONTH_ARR[@]}"
  do
    if [ ${ITEM} = ${_MONTH} ]; then
      break
    fi
    (( MONTH++ ))
  done

  DATETIME=`date "+%Y"`-`printf %02d ${MONTH}`"-${DATE} $TIME"
  TARGET_DATETIME=`date "+%Y-%m-%d %H:%M:%S" -d "5 minute ago"`

  if [ `date -d "${DATETIME}" "+%s"` -gt `date -d "${TARGET_DATETIME}" "+%s"` ];then
    DATE_OK=0
  fi
}


#
# report
#

report(){
  CHANNEL="#チャンネル名"
  USER="ユーザ名"
  BODY=$1
  URL="取得したslackのapi用URL"
  ICON=$2
  curl -X POST --data-urlencode "payload={\"channel\": \"${CHANNEL}\", \"username\": \"${USER}\", \"text\": \"${BODY}\", \"icon_emoji\": \"${ICON}\"}" ${URL}
}

#
#
#

main(){
  getLog "$1" $2

  if [ ${FLG} -lt 1 ]; then
    investigateDate
  fi

  if [ ${DATE_OK} -lt 1 ]; then
    report "$3 IP:$IP" $4
  fi
}

#
# errCheck
#

errCheck(){
  main "error\: Received" 10 "第三者がsshログインを試み、失敗しました。" ":lock:"
}


#
# successCheck
#
successCheck(){
  main "Accepted" 11 "第三者がsshログインしました。" ":unlock:"
}

errCheck
successCheck

コードの解説は下記を参考に。
starfam.hatenablog.com



注意点としては、以下のコード部分の「$$2」の箇所ですかね

LOG_GET_SC="cat /var/log/secure | grep \"$1\"${GREP} | tail -1 | awk '{print \$1\"__\"\$2\"__\"\$3\"__\"\$$2}'"

「$$2」やgrepに渡している${数字}と、printに渡してる${数字}は異なります
「$$2」やgrepに渡している${数字}は、getLog関数に渡している引数です。

↓の「"$1" $2」ですね。

getLog "$1" $2

もっと言えば↓の"Accepted" 11です。
なので、下記の場合、

「$$2」= $11

となります。

successCheck(){
  main "Accepted" 11 "第三者がsshログインしました。" ":unlock:"
}

というわけで、successCheck()から呼んだ場合の下記のコードの全体の意味としては、

LOG_GET_SC="cat /var/log/secure | grep \"$1\"${GREP} | tail -1 | awk '{print \$1\"__\"\$2\"__\"\$3\"__\"\$$2}'"

「cat /var/log/secure」の"Accepted"と"許可IP"(grep \"$1\"${GREP})が含まれる、最後の1行(tail -1)から、
1,2,3,11フィールド目の文字列(空白がデリミタみたいな感じ)を「__」で連結して(awk '{print \$1\"__\"\$2\"__\"\$3\"__\"\$$2}')
表示する

となります。結果としては、以下みたいな感じ

Nov__29__16:26:08__アクセス元IP

もともとの「/var/log/secure」の行はこれです

Nov 29 14:54:19 ip-自分のIP sshd[18558]: Accepted publickey for ユーザ名 from アクセス元IP port アクセス元ポート番号 ssh2: RSA ~~
※下記などの「"Accepted"」や「11」はご自身の環境に合わせて変更してください。
  • "Accepted":「/var/log/secure」のログイン成功した場合の行にあった記述
  • 11:「/var/log/secure」のログイン成功した場合の行の、IP記述されているフィールド(空白がデリミタみたいな感じ)
successCheck(){
  main "Accepted" 11 "第三者がsshログインしました。" ":unlock:"
}

slackでの通知に関して、下記の記事でもう少しだけ詳しく書いたので、ご覧ください。
starfam.hatenablog.com