[DevOps][Linux] Shell Script를 이용하여 서버 접속 사용자 정보 디스코드에 보내기

2023. 8. 7. 12:18DevSecOps/Server

작성자[대표]주니

728x90
반응형

 

 

안녕하세요. 기깔나는 사람들에서 대표를 맡고있는 주니입니다.


현재 기깔나는 사람들에서 사용하는 서버에 사용자가 접속할 일이 많고, 이에 따라 보안을 위해 모니터링을 해야 하는데, 서버에 접속하여 로그 분석 하는 방법 외에는 현재 딱히 운영하고 있는 솔루션이 없는 상태에요.

모임에서 사용중인 디스코드에 서버에 접속시 Access(접속) ID, User(사용자) IP, Server Hostname(서버 호스트네임), Server IP(서버 IP) 정보를 받으면 보다 관리하기 편하겠다는 생각을 하게 되었고, 이를 구현해 보려고 해요.

대상 OS는 Ubuntu Linux 22.04 LTS 이고, Shell Script(쉘 스크립트)와 Discord Webhook(디스코드 웹훅)을 이용하여 구성해 보도록 할게요.




 

디스코드 웹훅 설정

최초 알림 받을 디스코드 채널을 준비하고, 해당 채널의 웹훅 URL을 따야 해요.

톱니바퀴 모양 클릭

 

웹후크 클릭



새 웹후크 만들기


위와 같이 웹훅을 만들고, 해당 웹훅 URL을 복사하여 저장해 줍니다.

 

 


리눅스 작업 - 쉘 스크립트 만들기

이번에는 사용자가 접속하면 원하는 정보를 파싱하여 웹훅을 보낼 수 있는 쉘 스크립트를 만들어 볼거에요.

해당 쉘 스크립트는 /etc/profile.d에 만들어 주는데, 최초 사용자가 로그인을 하게 되면 Login shell(로그인 쉘)로 동작하게 되요. 기본 로그인 쉘은 bash이고, 로그인 쉘로 동작할 때, profile을 읽게 되어 있어요.

/etc/profile /etc/profile.d Directory(디렉터리) 안에 존재하는 모든 쉘 스크립트를 실행해주는 친구에요.
/etc/profile.d vim, qt, lang, colors 등 다양한 설정이 sh File(쉘 파일) 형태로 존재하고, 최초 로그인 시 /etc/profile을 통해 실행되게 된답니다.

그래서 로그인을 하게 되면 /etc/profile을 먼저 읽고, 이 후 해당 계정의 홈 디렉터리의 ~./profile을 읽게 동작해요.

그래서 /etc/profile.d에 주니가 만든 쉘 스크립트를 넣게 하여 전역적으로 모든 사용자가 로그인을 하게 되면 동작할 수 있도록 하기 위해 해당 디렉터리에 쉘 스크립트를 저장하는 거에요.

#!/bin/bash

set -e

DISCORD_WEBHOOK_URL="디스코드 웹훅 URL"
USER_IP=$(echo $SSH_CONNECTION | cut -d " " -f 1)
USER=$(who | grep "$USER_IP" | awk '{print $1}' | sort | uniq)
HOSTNAME=$(hostname)
SERVER_IP=$(hostname -I | awk '{print $1}')
ACCESS_DATE=$(date +"%Y-%m-%d %T")
LOG_DIR="/var/log/discord/webhook/accessAlarm"
LOG_FILE="${LOG_DIR}/${ACCESS_DATE}_sshAccessAlarm.log"

if [ -d "$LOG_DIR" ];
then
         echo "[$ACCESS_DATE] Directory가 존재 합니다" >> "$LOG_FILE" 2>&1
else
         mkdir -p $LOG_DIR

         if [ $? != 0 ];
         then
                 echo "[$ACCESS_DATE] Log 저장을 위한 Directory 만들기 실패 하였습니다."
                 exit 1
         else
                 echo "[$ACCESS_DATE] Directory가 존재 하지 않아 생성 하였습니다." >> "$LOG_FILE" 2>&1
         fi
fi

echo "User 정보: $USER" >> "$LOG_FILE" 2>&1

if [ -n "$USER" ];
then
        TITLE="$ACCESS_DATE 사용자 SSH 접속 확인!"
        MESSAGE="SSH 접속 정보 알림 \n 접속자: $USER, 접속자 IP 주소: $USER_IP \n 접속 대상 서버: $HOSTNAME, 접속 대상 서버 IP: $SERVER_IP"

        echo "[$ACCESS_DATE] SSH 접속 정보 알림 메시지 만들기 성공하였어요." >> "$LOG_FILE" 2>&1

else
        TITLE="$ACCESS_DATE 사용자 SSH 접속 해제 확인!"
        MESSAGE="SSH 접속 해제 정보 알림 \n 사용자: $USER, 사용자 IP 주소: $USER_IP \n 접속 대상 서버: $HOSTNAME, 접속 대상 서버 IP: $SERVER_IP"

        echo "[$ACCESS_DATE] SSH 접속 해제 정보 알림 메시지 만들기 성공하였어요." >> "$LOG_FILE" 2>&1

fi

# curl을 이용하여 디스코드 웹훅 메시지 전송
curl -H "Content-Type: application/json" -d "{\"username\":\"내부 서버 접속 정보 알림봇\",\"embeds\":[{\"title\":\"$TITLE\",\"description\":\"$MESSAGE\"}]}" "$DISCORD_WEBHOOK_URL"

if [ $? != 0 ];
then
        echo "[$ACCESS_DATE]Discord로 SSH 접속 정보 알림 메시지 전송 실패하였어요." >> "$LOG_FILE" 2>&1

else
        echo "[$ACCESS_DATE]Discord로 SSH 접속 정보 알림 메시지 전송 성공하였어요." >> "$LOG_FILE" 2>&1

fi
반응형

 

/etc/profile.d/userAccessAlarm.sh 1 ~ 42번째 줄


3번째 줄에 위에서 디스코드 웹훅 URL을 얻은 것을 복사하여 넣어주었어요.
그리고, 접속 사용자 IP 주소를 파싱하기 위해 명령어를 사용해 주었는데, 여기서 $SSH_CONNECTION Unix 및 Unix-like 시스템에서 환경 변수로 사용되는 것으로 SSH 연결에 대한 정보를 제공해 주고 있어요. 이 변수는 SSH Session(세션)을 시작한 Client(클라이언트)  서버 간의 연결 정보를 포함하고 있어요.

주소 쉘 스크립트나 명령어에서 사용되고, SSH 연결의 클라이언트 IP 주소, 클라이언트 Port(포트), 서버 IP 주소, 서버 포트등의 정보를 담고 있어요.

해당 변수의 형식은 다음과 같아요.

클라이언트IP주소	클라이언트포트번호	서버IP주소	서버포트


그래서 awk를 통해 첫번째 열에 있는 클라이언트 IP주소 값을 USER_IP 변수에 담아 주었어요.

12 ~ 25번째 줄은 Log(로그)를 남기기 위해 로그 디렉터리가 존재하는지 확인하는 부분이에요.

이 부분에 대해서는 이 곳에 좀 더 자세히 정리해 두었어요.

 

[Shell Script] 서버 재부팅 시 Docker 안에 특정 Deamon 자동 기동되게 만들기

리눅스 커맨드라인 쉘 스크립트 바이블 COUPANG www.coupang.com "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다." 🚀 Docker 안의 Deamon 자동 기동되게 만들기

junyharang.tistory.com

 

31 ~ 42번째 줄까지는 접속 이용자 정보를 가지고, 디스코드 메시지로 보낼 문자열을 준비하는 부분이에요.

31번째 분기문을 통해 USER 변수에 값이 비어있는지를 확인해 주고, 비어있지 않다면 then 절을 통해 SSH 접속을 했다는 것에 대한 메시지를 만들고, 비어있다면 접속 해제를 했다는 것에 대한 메시지를 만들게 해 주었어요.

 

/etc/profile.d/userAccessAlarm.sh 46 ~ 56번째 줄

 

이 부분이 본격적으로 디스코드 웹훅을 이용해 메시지를 전달하는 부분이에요.

curl 명령어를 통해 HTTP로 준비된 메시지를 보낼 수 있도록 해 주었어요.

그런 뒤 49번째 줄에 명령어 성공 여부를 확인하고, 로그를 남길 수 있도록 해 주었어요.

 

 

 

 

 


SSH 접속

그럼 쉘 스크립트가 잘 작동하는지 확인해 볼게요.

SSH 접속




이렇게 위와 같이 메시지가 정상적으로 오는 것을 확인할 수 있어요.

 

 

================================ 수 정 사 항 ================================

위와 같이 사용하려고 하였지만, 문제가 발생하였어요.

특정 명령어를 입력하게 되면 SSH가 튕겨 버리는 현상이에요.

특히 도커 관련 명령어를 사용하게 되면 SSH가 튕겨 버리는 바람에 다른 방법을 찾게 되어 다시 수정 합니다.


#!/bin/bash

set -e

DISCORD_WEBHOOK_URL="{Discord Web Hook URL}"
USER_IP=$PAM_RHOST
USER=$PAM_USER
HOSTNAME=$(hostname)
SERVER_IP=$(hostname -I | awk '{print $1}')
ACCESS_DATE=$(date +"%Y-%m-%d %T")
LOG_DIR="/var/log/discord/webhook/accessAlarm"
LOG_FILE="${LOG_DIR}/${ACCESS_DATE}_sshAccessAlarm.log"

if [ -d "$LOG_DIR" ];
then
         echo "[$ACCESS_DATE] Directory가 존재 합니다" >> "$LOG_FILE" 2>&1
else
         mkdir -p $LOG_DIR

         if [ $? != 0 ];
         then
                 echo "[$ACCESS_DATE] Log 저장을 위한 Directory 만들기 실패 하였습니다."
                 exit 1
         else
                 echo "[$ACCESS_DATE] Directory가 존재 하지 않아 생성 하였습니다." >> "$LOG_FILE" 2>&1
         fi
fi

# 사용자가 SSH 접속 
if [ "$PAM_TYPE" != "close_session" ];
then
        TITLE="$ACCESS_DATE 사용자 SSH 접속 확인!"
        MESSAGE="SSH 접속 정보 알림 \n 접속자: $USER, 접속자 IP 주소: $USER_IP \n 접속 대상 서버: $HOSTNAME, 접속 대상 서버 IP: $SERVER_IP"
        COLOR=16711680 # 빨간색

        echo "[$ACCESS_DATE] SSH 접속 정보 알림 메시지 만들기 성공하였어요." >> "$LOG_FILE" 2>&1
fi

# 사용자가 SSH 접속 해제 시
if [ "$PAM_TYPE" == "close_session" ];
then
        TITLE="$ACCESS_DATE 사용자 SSH 접속 해제 확인!"
        MESSAGE="SSH 접속 해제 정보 알림 \n 사용자: $USER, 사용자 IP 주소: $USER_IP \n 접속 대상 서버: $HOSTNAME, 접속 대상 서버 IP: $SERVER_IP"
        COLOR=65280 # 형광 녹색
        
        echo "[$ACCESS_DATE] SSH 접속 해제 정보 알림 메시지 만들기 성공하였어요." >> "$LOG_FILE" 2>&1

fi

# curl을 이용하여 디스코드 웹훅 메시지 전송
curl -H "Content-Type: application/json" -d "{\"username\":\"내부 서버 접속 정보 알림봇\",\"embeds\":[{\"title\":\"$TITLE\",\"description\":\"$MESSAGE\",\"color\":$COLOR}]}" "$DISCORD_WEBHOOK_URL"

if [ $? != 0 ];
then
        echo "[$ACCESS_DATE]Discord로 SSH 접속 정보 알림 메시지 전송 실패하였어요." >> "$LOG_FILE" 2>&1

else
        echo "[$ACCESS_DATE]Discord로 SSH 접속 정보 알림 메시지 전송 성공하였어요." >> "$LOG_FILE" 2>&1

fi


최초 쉘 스크립트는 위와 같이 변경이 되었어요.

즉, PAM을 이용하여 Discord Web Hook을 전송할 수 있게 해 주었어요.

위 쉘 스크립트를 /etc/ssh 디렉터리에 위치한 뒤 아래 명령어를 입력해 줍니다.

# 쉘 스크립트 실행 권한 부여
chmod +x /etc/ssh/userAccessDiscordAlarm.sh

# /etc/pam.d/sshd에 쉘 스크립트 관련 설정
echo "session optional pam_exec.so seteuid /etc/ssh/userAccessDiscordAlarm.sh" >> /etc/pam.d/sshd

 

 


위와 같이 정상적으로 알림이 오는걸 확인할 수 있어요.

 

 

 


 

 

 

리눅스 커맨드라인 쉘 스크립트 바이블

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

 

 

 

 

 

SLACK으로 SSH 로그인 알림 확인 | CoolioSo!

서버를 운영하면서 가장 무서운 일은 허가되지 않은 인원이 운영하는 서버에 몰래 접근하여 어떠한 작업을 한다는 것이다. 아무리 보안에 신경을 쓴다고 해도 보안 문제는 쉽게 해결이 되지 않

www.coolio.so

 

 

 

 

 

 

 

 

 

728x90
반응형