서버에 SSH로 접속할 때마다 실시간을 이메일 알림을 받는 보안 모니터링 시스템을 구현합니다.
NAT/게이트웨이 환경에서도 실제 외부 IP를 추적하여 보안을 강화합니다.
시스템 아키텍처
[SSH Client] → [Router/NAT] → [SSH Server] → [PAM] → [Alert Script] → [sSMTP] → [Gmail]
↓
[External IP Tracking]
프로세스 플로우

1. sSMTP 설치 및 설정
sudo apt update
sudo apt install ssmtp mailutils
- sSMTP 설정 (/etc/ssmtp/ssmtp.conf)
# 서버 호스트명
hostname=your-server-name
# Gmail SMTP 설정
root=your-email@gmail.com
mailhub=smtp.gmail.com:587
AuthUser=your-email@gmail.com
AuthPass=your-16-digit-app-password
UseSTARTTLS=YES
FromLineOverride=YES
- 발신자 설정 (/etc/ssmtp/revaliases)
root:your-email@gmail.com:smtp.gmail.com:587
username:your-email@gmail.com:smtp.gmail.com:587
보안 설정 필수
- Google 계정에서 2단계 인증 활성화
- 앱 비밀번호 생성 (https://myaccount.google.com/apppasswords)
- 생성된 16자리 비밀번호 사용
앱 비밀번호의 경우 생성후 다시 확인이 어려우니 저장해놓고 사용해야합니다.(외부 유출금지)
2. SSH 로그인 알림 스크립트 (외부 IP 추적 기능 포함)
/usr/local/bin/ssh-login-alert.sh
#!/bin/bash
# 실제 외부 IP 추출 함수
get_real_ip() {
local ip=""
# 1. auth.log에서 직접 추출 (가장 정확)
ip=$(grep "sshd.*Accepted.*$PAM_USER" /var/log/auth.log | \
tail -1 | \
sed -n 's/.*from \([0-9.]*\).*/\1/p')
# 2. IP가 없거나 내부 IP면 last -i 사용
if [ -z "$ip" ] || [[ "$ip" =~ ^(192\.168\.|10\.|172\.) ]]; then
ip=$(last -i -n 10 | grep "$PAM_USER" | \
grep -v "192.168\|10.\|172." | \
head -1 | awk '{print $3}')
fi
# 3. 그래도 없으면 현재 연결에서 추출
if [ -z "$ip" ] || [[ "$ip" =~ ^(192\.168\.|10\.|172\.) ]]; then
ip=$(ss -tn | grep ":22" | grep ESTAB | \
awk '{print $5}' | cut -d: -f1 | \
grep -v "192.168\|10.\|172." | head -1)
fi
# 4. 마지막으로 PAM_RHOST 사용
if [ -z "$ip" ]; then
ip="$PAM_RHOST"
fi
echo "$ip"
}
# 메인 실행 부분
if [ "$PAM_TYPE" = "open_session" ] && [ -n "$PAM_RHOST" ]; then
# IP 정보 수집
REAL_IP=$(get_real_ip)
GATEWAY_IP="$PAM_RHOST"
# IP 위치 정보 조회 (외부 IP인 경우)
if [[ ! "$REAL_IP" =~ ^(192\.168\.|10\.|172\.|127\.) ]]; then
IP_INFO=$(curl -s --max-time 3 "http://ip-api.com/json/$REAL_IP" 2>/dev/null)
CITY=$(echo "$IP_INFO" | grep -oP '"city":"\K[^"]+' || echo "Unknown")
COUNTRY=$(echo "$IP_INFO" | grep -oP '"country":"\K[^"]+' || echo "Unknown")
ISP=$(echo "$IP_INFO" | grep -oP '"isp":"\K[^"]+' || echo "Unknown")
LOCATION_INFO="$CITY, $COUNTRY (ISP: $ISP)"
else
LOCATION_INFO="Internal Network"
fi
# 메일 전송
{
echo "======================================"
echo "⚠️ SSH 로그인 감지"
echo "======================================"
echo "시간: $(date '+%Y-%m-%d %H:%M:%S')"
echo "서버: $(hostname)"
echo "사용자: $PAM_USER"
if [ "$REAL_IP" != "$GATEWAY_IP" ]; then
echo "외부 IP: $REAL_IP"
echo "게이트웨이: $GATEWAY_IP"
else
echo "접속 IP: $REAL_IP"
fi
echo "위치: $LOCATION_INFO"
echo "======================================"
echo ""
echo "현재 접속자:"
echo "$(w)"
} | mail -s "[SSH] $(hostname) - $PAM_USER from ${REAL_IP:-$GATEWAY_IP}" your-email@gmail.com
fi
실행 권한 설정
sudo chmod +x /usr/local/bin/ssh-login-alert.sh
3. PAM 설정
/etc/pam.d/sshd 수정
sudo nano /etc/pam.d/sshd
파일 끝에 추가:
# SSH Login Email Alert
session optional pam_exec.so /usr/local/bin/ssh-login-alert.sh
4. SSH 로깅 개선 (더 정확한 IP 추적을 위해) 후 sshd 재시작
sudo nano /etc/ssh/sshd_config
LogLevel VERBOSE
sudo systemctl restart sshd
PAM 환경변수
| 변수 | 설명 | 예시 |
| $PAM_TYPE | 이벤트 타입 | open_session, close_session |
| $PAM_USER | 로그인 사용자 | redhorse |
| $PAM_RHOST | 원격 호스트 IP | 192.168.0.1 |
| $PAM_TTY | 터미널 정보 | ssh |
IP-API 응답 파싱
{
"city": "Seoul",
"country": "South Korea",
"isp": "Korea Telecom"
}
테스트 및 검증
1. sSMTP 테스트
# 기본 테스트
echo "Test" | mail -s "Test Mail" your-email@gmail.com
# 디버그 모드
echo "Test" | ssmtp -vvv your-email@gmail.com

'ZeroBase > Infra' 카테고리의 다른 글
| Http -> Https Domain 변경 (0) | 2025.10.25 |
|---|