▶︎ 개요
현재 개발 서버를 pve로 운영 중인데
해당 서버의 경우 나뿐만 아니라 다른 사용자들도 접속할 일이 꽤 많다.
이에 따라 어떤 사용자가 접속하는지 서버에 들어가 주기적으로 모니터링을 해봐야 한다.
서버에 모니터링 솔루션을 도입하지 않았기 때문에 일일이 로그 분석을 하는 방법 외에는 딱히 방법이 없다.
그래서 생각해 본 방법 중에 하나가 서버에 사용자가 접속하게 되면 Access ID, User IP를 추출한 후, 디스코드 webhook을 사용하여 알림을 보내면 일일이 서버에 접속하여 로그를 확인할 필요가 없어질 것 같아서 셸 스크립트(Shell Script)로 한 번 구현해보기로 했다.
▶︎ 운영 환경
- OS: Proxmox VE
- VM OS: Ubuntu 22.04
- Shell Script
▶︎ 디스코드 웹훅
‣ webhook URL 추출
알림받을 디스코드 채널을 준비하고, 해당 채널의 웹훅 URL을 가져와야 한다.
채널 설정 -> 연동 -> 새 웹후크 만들기
위처럼 webhook을 새로 만들어주고 해당 웹훅 URL을 복사하여 어딘가에 저장하도록 하자.
▶︎ 스크립트 작성
사용자가 서버에 접속하면 원하는 정보를 파싱하여 웹훅을 보내는 셸 스크립트를 만들어보도록 하자.
해당 셸 스크립트의 경우 /etc/profile.d
디렉토리 하위에 만들어줄거다.
최초 사용자가 로그인을 하게 되면 **Login Shell(로그인 셸)**로 동작하게 되는데
이 때 기본 로그인 셸은 bash이고, 로그인 셸로 동작할 때 profile을 읽도록 되어있다.
/etc/profile
은 /etc/profile.d
하위에 존재하는 모든 셸 스크립트를 실행해주는 역할을 한다고 보면된다.
/etc/profile.d
는 vim, qt, lang, color 등의 다양한 설정들이 sh File(셸 파일) 형태로 존재하게 되고, 최초 로그인 시 /etc/profile
을 통해 실행되게 만든다.
그래서 로그인을 하게 되면 /etc/profile
을 먼저 읽고, 그 이후 해당 계정의 홈 디렉토리에 존재하는 ~/.profile
을 읽도록 동작한다!
그래서 이번에 작성할 셸 스크립트 또한 /etc/profile.d
디렉토리 하위에 생성할 것이다.
이유는 위에서 설명했듯이 전역적으로 모든 사용자가 로그인을 하게 되면 해당 스크립트가 동작할 수 있도록 하기 위해서!
‣ 코드
/etc/ssh/userAccess.sh
#!/usr/bin/bash
set -e
# ------------------
# SSH Access Web Hook notification
# Written by: Jaehyo (yshrim12@naver.com)
# ------------------
ACCESS_DATE=$(date +"%Y-%m-%d %T")
LOG_ACCESS_DATE=$(date +"%Y%m%d_%H%M")
LOG_DIR="/var/log/discord/webhook"
LOG_FILE="${LOG_ACCESS_DATE}_sshAccess.log"
ENV_FILE="/home/dev/discord/.discord.env"
DISCORD_WEBHOOK_URI="$(awk -F '=' '{print $2}' $ENV_FILE)"
SSH_USER_IP="$PAM_RHOST"
SSH_USER="$PAM_USER"
SSH_USERNAME="$(grep $USER /etc/passwd | awk '{print $5}' )"
HOST=$HOSTNAME
SERVER_IP=$(hostname -I | awk '{print $1}')
SERVER_OS=$(cat /etc/os-release | grep "PRETTY_NAME" | cut -d '"' -f2)
exec 3>> "$LOG_FILE"
function checkLogDir() {
if [[ ! -d $LOG_DIR ]]; then
echo "Creating ${LOG_DIR} ..." >&3
mkdir -p "${LOG_DIR}"
if [[ $? != 0 ]]; then
echo "[$ACCESS_DATE] $LOG_DIR 디렉토리를 생성할 수 없었습니다" >&3
exit 1
else
exec 3>> "$LOG_FILE"
echo "[$ACCESS_DATE] $LOG_DIR 디렉토리를 성공적으로 생성하였습니다" >&3
fi
else
echo "[$ACCESS_DATE] $LOG_DIR 디렉토리가 이미 존재합니다" >&3
fi
echo "#=============== [$ACCESS_DATE] SSH 접속 정보 알림 스크립트 시작 ... #===============" >&3
checkUserProcess
}
function checkUserProcess() {
# 사용자가 SSH 접속
if [[ "$PAM_TYPE" != "close_session" ]]; then
TITLE="[$ACCESS_DATE] 사용자 SSH 접속 확인"
MESSAGE="SSH 접속 정보 알림\n접속자: $SSH_USER\n접속자 IP: $SSH_USER_IP\n접속 서버 : $HOST\n접속 서버 IP : $SERVER_IP"
echo "[$ACCESS_DATE] SSH 접속 정보 알림 메시지 만들기 성공" >&3
COLOR=16711680 # 빨간색
fi
# 사용자가 SSH 접속 해제 시
if [[ "$PAM_TYPE" == "close_session" ]]; then
TITLE="[$ACCESS_DATE] 사용자 SSH 접속 해제 확인!"
MESSAGE="SSH 접속 해제 정보 알림\n접속자: $SSH_USER\n접속자 IP: $SSH_USER_IP\n접속 서버 : $HOST\n접속 서버 IP : $SERVER_IP"
echo "[$ACCESS_DATE] SSH 접속 해제 정보 알림 메시지 만들기 성공" >&3
COLOR=65280 # 형광 녹색
fi
sendDiscordWebhook
}
function sendDiscordWebhook() {
echo "[$ACCESS_DATE] Discord로 SSH 접속 정보 알림 메시지 전송" >&3
curl -H "Content-Type: application/json" -d "{
\"embeds\":[{
\"title\":\"$TITLE\",
\"description\":\"$MESSAGE\",
\"color\":$COLOR}]
}" "$DISCORD_WEBHOOK_URI"
if [[ $? != 0 ]]; then
echo "[$ACCESS_DATE] [error] Discord 알림 전송 실패!" >&3
else
echo "[$ACCESS_DATE] [error] Discord 알림 전송 성공!" >&3
fi
}
checkLogDir
echo "[$ACCESS_DATE] === SSH 접속 or 해제 사용자 정보 ===" >&3
echo "[$ACCESS_DATE] === 접속 계정: $SSH_USER" >&3
echo "[$ACCESS_DATE] === 접속 계정 IP: $SSH_USER_IP" >&3
echo "[$ACCESS_DATE] === SSH 접속 or 해제 서버 정보 ===" >&3
echo "[$ACCESS_DATE] === 접속 서버: $HOST" >&3
echo "[$ACCESS_DATE] === 접속 서버 IP: $SERVER_IP" >&3
echo "@Author: Jaehyo\(yshrim12@naver.com\)" >&3
echo "#=============== [$ACCESS_DATE] SSH 접속 정보 알림 스크립트 종료 ... #===============" >&3
cat "$LOG_FILE" >| "$LOG_DIR/$LOG_FILE"
rm -rf "$LOG_FILE"
PAM
을 이용하여Discord
에Web hook
을 전송할 수 있도록 하였음DISCORD_WEBHOOK_URI
에는.discord.env
라는 파일에서 URI를 파싱하여 가져왔음- 접속 사용자 IP 주소를 파싱하기 위해 명령어를 사용하였음
SSH_CONNECTION
: Unix 및 Unix-like 시스템에서 환경 변수로 사용되는 것으로 SSH 연결에 대한 정보를 제공.- 해당 변수는 SSH Session을 시작한 Client 및 서버 간의 연결 정보를 포함함
‣ 확인
셸 스크립트가 잘 작동하는지 확인해보자.
먼저 위 셸 스크립트를 /etc/ssh
경로에 위치시켜준 뒤 아래 명령어를 입력해주도록 하자.
# 스크립트에 실행 권한 부여
chmod +x /etc/ssh/userAccess.sh
# /etc/pam.d/sshd에 셸 스크립트 관련 설정
sudo sh -c 'echo "session optional pam_exec.so seteuid /etc/ssh/userAccess.sh" >> /etc/pam.d/sshd'
‣ SSH 접속
위처럼 서버 접속/종료 시 알림이 오는 것을 확인할 수 있다.