Microsoft 社는 2022년 6월 15일 Internet Explorer 11의 지원을 종료했습니다.

서버 호스팅 Linux 의 보안 설정

제목

서버 호스팅 Linux 의 보안 설정

이 글의 마지막 편에서는 iptables 를 이용해서, 필수적인 port 를 제외한 나머지 포트를 막을 것이다.

하지만 iptables 는 iptables 이고, ssh 는 최소한의 보안 설정을 한다.

1. sshd 설정

  1. root 는 원격에서 ssh 로그인을 할 수 없다.
  2. 원격에서 ssh 로 로그인 할 수 있는 아이디 1개 뿐이고, 나머지는 ssh 접속을 할 수 없다.

설정파일은 /etc/ssh/sshd_config 이다.

PermitRootLogin no
AllowUsers guser

원격에서 로그인 할 수 있는 아이디는 guser 1개이다.

검색을 해보고, 있으면 주석을 풀고, 없으면 추가하는 방법으로 변경한다.

guser 를 제외한 다른 아이디는 sftp 도 사용할 수 없다.

이렇게 하면 vi 나 다른 서버용 Text 파일 편집기를 사용해야 하는데, 불편함은 누구에게나 마찬가지이다.

guser 계정에 파일을 임시로 올린 다음, terminal 에서 파일을 복사하는 방식을 권한다.

2. 로그인 하면 이메일 발송하도록 설정

여기서 소개한 방법은 사람이 PuTTY 따위로 로그인한 경우에만 유효하다.

PAM 을 이용하는 것이 아니다.

guser 계정의 .profile 혹은 .bash_profile 파일에 다음의 내용을 추가한다.

if [ -f ~/.bash_login ]; then
. ~/.bash_login
fi

다음과 같이 .bash_login 파일을 편집한다(없으면 새로 만든다).

보내는 이메일 주소와 받는 이메일 주소도 변경해야 한다.

(최신의) curl 이나 sendmail 과 같은 MTA 중 1개는 있어야 한다.

2.1. curl 을 이용하는 방법

이 방법은 (이메일 발송을 지원하는) 최신 버전의 curl 과 MX 호스트를 찾을 수 있게 dig 혹은 host 혹은 nslookup 중 1개가 있어야 한다.

최신의 리눅스 배포판이라면 (이메일 발송을 지원하는) 최신 버전의 curl 이 설치되어 있을 가능성이 높다.

#! /usr/bin/env bash
SENDER="보내는 이메일 주소"
RECIPIENT="받는 이메일 주소"
if [ -n "$SSH_CONNECTION" -a "$SHLVL" = "1" ]; then
remote=$(echo "$SSH_CONNECTION" | awk '{ print $1 }')
user=$(id -un)
host="$(hostname)"
subject="SSH Login: $user from $remote on $host"
message="
Date : $(date +'%Y-%m-%d %H:%M:%S')
SHLVL : $SHLVL
SSH_CONNECTION : $SSH_CONNECTION
"
HOST=${RECIPIENT##*@}
MXFOUND=N
MXHOST=""
Result=$( dig ${HOST} mx +short 2> /dev/null | head -1 )
RETVAL=$?
if [[ $RETVAL -eq 0 ]]; then
if [ "$Result" != "" ];then
MXHOST=$( echo ${Result} | awk '{ print $NF }' )
MXHOST=${MXHOST%.}
fi
MXFOUND=Y
fi
if [[ "$MXHOST" == "" && "$MXFOUND" != "Y" ]]; then
Result=$( host -t mx ${HOST} 2> /dev/null | grep mail | head -1 )
RETVAL=$?
if [[ $RETVAL -eq 0 ]]; then
if [ "$Result" != "" ];then
MXHOST=$( echo ${Result} | awk '{ print $NF }' )
MXHOST=${MXHOST%.}
fi
MXFOUND=Y
fi
fi
if [[ "$MXHOST" == "" && "$MXFOUND" != "Y" ]]; then
Result=$( nslookup -type=mx ${HOST} 2> /dev/null | grep "mail exchanger" | head -1 )
RETVAL=$?
if [[ $RETVAL -eq 0 ]]; then
if [ "$Result" != "" ];then
MXHOST=$( echo ${Result} | awk '{ print $NF }' )
MXHOST=${MXHOST%.}
fi
MXFOUND=Y
fi
fi
if [[ "$MXHOST" == "" && "$MXFOUND" == "Y" ]]; then
MXHOST=${HOST}
fi
if [ "$MXHOST" == "" ];then
echo "dig|host|nslookup command not exists!"
return 100
else
curl -s --ssl \
--url "smtp://${MXHOST}" \
--mail-from ${SENDER} \
--mail-rcpt ${RECIPIENT} \
--upload-file - << EOF
From: <${SENDER}>
To: <${RECIPIENT}>
Subject: ${subject}
${message}
EOF
fi
fi
unset SENDER
unset RECIPIENT
unset remote
unset user
unset host
unset subject
unset message
unset HOST
unset MXFOUND
unset MXHOST
unset Result
unset RETVAL

소스코드가 길어진 이유는 curl 의 --url 파라미터에 공급할 mail exchanger 주소를 찾는 것 때문이다.

sendmail 등 MTA 를 이용하는 방법은 mail exchanger 주소를 찾는 부분이 생략된다.

2.2. sendmail 등 MTA 를 이용하는 방법

sendmail 경로를 변경해야 하고, sendmail 이 없다면, 주석으로 막힌 mailx 를 사용할 수 있다.

postfix 나 exim 같은 것들이면 스크립트를 변경해야 한다.

오래된 리눅스 배포판은 (함께 지워지는 의존성 있는 패키지가 너무 많아서) MTA 를 지울수가 없었으므로 무엇인가 있을 가능성이 높다.

SENDER="보내는 이메일 주소"
RECIPIENT="받는 이메일 주소"
if [ -n "$SSH_CONNECTION" -a "$SHLVL" = "1" ]; then
remote=$(echo "$SSH_CONNECTION" | awk '{ print $1 }')
user=$(id -un)
host="$(hostname)"
subject="SSH Login: $user from $remote on $host"
message="
Date : $(date +'%Y-%m-%d %H:%M:%S')
SHLVL : $SHLVL
SSH_CONNECTION : $SSH_CONNECTION
"
echo "Subject:$subject $message" | /usr/sbin/sendmail -f $SENDER $RECIPIENT
# echo "$message" | mailx -r "$SENDER" -s "$subject" "$RECIPIENT"
fi
unset SENDER
unset RECIPIENT
unset remote
unset user
unset host
unset subject
unset message

3. iptables 설정

공인 IP 는 무작위적인 침입 시도에 시달린다. 침입자 내지 공격자는 대상을 특정하지 않고, 무차별적으로 공격을 시도한다.

이런 류의 공격에 대응하는 최소한의 방책은 차단을 원칙으로 하고, 필수적인 것들을 예외적으로 허용하는 정책을 사용해야 한다.

80 = http, 443 = https, 25 = smtp 정도를 제외한 모든 포트를 막는다.

22 = ssh 를 포함해서 관리 목적으로 허용되어야 하는 포트는 ip 주소나 mac address 를 지정해서 제한적으로 열어준다.

client 가 유동 ip 를 사용하고 있다면, 반드시 mac address 를 지정해서, client 의 ip 가 변경되는 경우를 대비해야 한다.

00:00:00:00:00:00 와 0.0.0.0 을 포함해서 "80 25 443" 와 "22 995 465 5432 8005 8009 8080" 는 적당히 변경해서 사용한다.

#!/bin/bash
# iptable 설정을 모두 지우고, 모든 연결을 허용한다.
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
# localhost 연결을 허용한다.
iptables -A INPUT -i lo -j ACCEPT
# 기존 연결의 일부 내지 기존의 연결과 관련된(파생된) 연결은 허용한다.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 서비스를 위한 포트의 연결은 허용한다(80 = http, 443 = https, 25 = smtp)
for PORT in 80 25 443
do
iptables -A INPUT -p tcp -m tcp --dport $PORT -j ACCEPT
done
# 특정 PC에 대해서는 정해진 포토의 연결을 허용한다
# (22 = ssh, 995 = pop3s, 465 = smtps, 5432 = postgresql, 8005 8009 8080 = tomcat)
for PORT in 22 995 465 5432 8005 8009 8080
do
# mac address 를 지정해서 연결을 허용한다(00:00:00:00:00:00).
# mac address 는 유출되면 안된다.
iptables -I INPUT -p tcp --dport $PORT -m mac --mac-source 00:00:00:00:00:00 -j ACCEPT
# ip를 지정해서 연결을 허용한다(0.0.0.0).
# ip 는 유출되면 안된다.
iptables -A INPUT -p tcp -s 0.0.0.0 --dport $PORT -j ACCEPT
done
# 위에서 기술된 것 이외의 INPUT, FORWARD 요청은 거절하고, 모든 OUTPUT 연결을 허용한다.
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

이런 류의 것들을 실행 할 때는 신중을 기해야 한다.

마지막 3개의 명령 보다 앞에서 에러가 발생하게 되면, 22 = ssh 가 막혀버리는 불행이 닥칠 수 있다.

  1. 무조건 copy & paste 를 하면 안된다.
  2. 최소한 00:00:00:00:00:00 와 0.0.0.0 는 적절히 변경해야 한다.
  3. 먼저 마지막 3줄을 지우고 실행시켜서, 에러가 나지 않는 것을 확인한 다음에 전체를 실행한다.
  4. 끝나고 나서, 터미널을 종료하지 않은 상태에서, 새로운 터미널을 열어본다.
  5. 최종적으로 서비스가 정상적으로 동작하는지 점검한다.
제목

첨부파일