미니 프로젝트
[Ansible 프로젝트] 리눅스 서버 취약점 점검 도구
종바깅
2021. 5. 7. 17:09
IaC 미니프로젝트 - Ansible
미니프로젝트 주제
- 주요정보통신기반시설_기술적_취약점_분석_평가_방법_상세가이드 중 UNIX/LINUX 항목에 대한 취약점 점검 도구
- 범위: 주요정보통신기반시설_기술적_취약점_분석_평가_방법_상세가이드 문서 내 UNIX 서버 항목 중 중요도 '상'에 해당하는 항목 중 10개 선정
목표
- 중요도 '상' 항목 총 43개 중 10개를 임의로 선정 (작성하기 편한 것으로)
- 동작방식
- 각 취약점 진단항목 별 점검을 수행할 수 있는 스크립트 작성
- 취약점 항목 하나당 하나의 스크립트 파일로 작성
- ex) u01.sh, u02.sh, u03.sh
- 또는 진단 항목 중 ansible playbook을 작성하여 진단가능한 항목에 대하여 검토
- 스크립트는 ansible을 통해 점검대상 호스트에 배포하여 실행하고, 결과 취합 또한 ansible을 통해 이루어지도록 작성
- 스크립트 실행 시 진단 항목별 점검방식에 따라 점검을 수행하여 결과는 양호/취약으로 판단하도록 작성
- 스크립트의 실행결과는 각 호스트의 /tmp/경로에 '취약점항목:취약여부' 형태로 저장된 후 취합되도록
inventory
[webservers]
managed1.example.local
[dbservers]
managed2.example.local
[allservers:children]
webservers
dbservers
ansible.cfg
[defaults]
inventory = ./inventory
remote_user = user
ask_pass = false
[privilege_escalation]
become = false
become_method = sudo
become_user = root
become_ask_pass = false
스크립트 목록
u01.sh : root 계정 원격 접속 제한 스크립트
u02.sh : 패스워드 복잡성 설정
u03.sh : 계정 잠금 임계값 설정
u04.sh : 패스워드 파일 보호
u06.sh : 파일 및 디렉터리 소유자 설정
u07.sh : /etc/passwd 파일 소유자 및 권한 설정
u08.sh : /etc/shadow 파일 소유자 및 권한 설정
u09.sh : /etc/hosts 파일 소유자 및 권한 설정
u12.sh : /etc/services 파일 소유자 및 권한 설정
u26.sh : automountd 제거 스크립트
- u01.sh
#!/bin/bash
REPORT=/tmp/report.txt
grep -r '^PermitRootLogin no' /etc/ssh/sshd_config >> /dev/null
if [[ "$?" -eq 0 ]]
then
if [ -f "$REPORT" ] ; then
echo -e "U01\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U01\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U01\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U01\tFAIL\n" >> /tmp/report.txt
fi
fi
- u02.sh
#!/bin/bash
REPORT=/tmp/report.txt
MIN=`awk -F" " '$1 ~ /^minlen/ {print $3}' /etc/security/pwquality.conf`
LCD=`awk -F" " '$1 ~ /^lcredit/ {print $3}' /etc/security/pwquality.conf`
UCD=`awk -F" " '$1 ~ /^ucredit/ {print $3}' /etc/security/pwquality.conf`
DCD=`awk -F" " '$1 ~ /^dcredit/ {print $3}' /etc/security/pwquality.conf`
OCD=`awk -F" " '$1 ~ /^ocredit/ {print $3}' /etc/security/pwquality.conf`
if [[ $MIN -gt 8 ]] &&[ $LCD -eq 1 ] && [ $UCD -eq -1 ] && [ $DCD -eq -1 ] && [ $OCD -eq -1 ]
then
if [ -f "$REPORT" ] ; then
echo -e "U02\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U02\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U02\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U02\tFAIL\n" >> /tmp/report.txt
fi
fi
- u03.sh
#!/bin/bash
REPORT=/tmp/report.txt
FILE1=/etc/pam.d/system-auth
PAM_MODULE=pam_tally.so
LINE1=`cat $FILE1 | egrep -v '(^#|^$)' | grep $PAM_MODULE`
if [ $? -ne 0 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U03\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U03\tFAIL\n" >> /tmp/report.txt
fi
else
LINE2=`echo $LINE1 | cut -d ' ' -f 4-`
for VAR in `echo $LINE2`
do
FIRST=`echo $VAR | awk '{print $1}'`
CHECK1=`echo $FIRST | awk -F= '{print $1}'`
CHECK2=`echo $FIRST | awk -F= '{print $2}'`
case $CHECK1 in
deny) if [ $CHECK -lt 5 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U03\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U03\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U03\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U03\tFAIL\n" >> /tmp/report.txt
fi
fi ;;
*) ;;
esac
shift
done
fi
- u04.sh
#!/bin/bash
REPORT=/tmp/report.txt
FILE1=/etc/passwd
FILE2=/etc/shadow
if [ -f $FILE1 -a -f $FILE2 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U04\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U04\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U04\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U04\tFAIL\n" >> /tmp/report.txt
fi
fi
- u06.sh
#!/bin/bash
REPORT=/tmp/report.txt
nouser_list=`find / -xdev -nouser -print 2>/dev/null > /nouserlist.txt`
nogroup_list=`find / -xdev -nogroup -print 2>/dev/null > /nogrouplist.txt`
if [ -s "/nouserlist.txt" -a -s "/nogrouplist.txt" ]; then
if [ -f "$REPORT" ] ; then
echo -e "U06\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U06\tFAIL\n" >> /tmp/report.txt
fi
elif [ -s "/nouserlist.txt" -a ! -s "/nogrouplist.txt" ]; then
if [ -f "$REPORT" ] ; then
echo -e "U06\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U06\tFAIL\n" >> /tmp/report.txt
fi
elif [ ! -s "/nouserlist.txt" -a -s "/nogrouplist.txt" ]; then
if [ -f "$REPORT" ] ; then
echo -e "U06\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U06\tFAIL\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U06\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U06\tGOOD\n" >> /tmp/report.txt
fi
fi
- u07.sh
#!/bin/bash
REPORT=/tmp/report.txt
find /etc/passwd -perm 644 > /dev/null 2>&1
if [ $? -eq 0 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U07\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U07\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U07\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U07\tFAIL\n" >> /tmp/report.txt
fi
fi
- u08.sh
#!/bin/bash
REPORT=/tmp/report.txt
find /etc/shadow -perm 400 > /dev/null 2>&1
if [ $? -eq 0 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U07\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U07\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U07\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U07\tFAIL\n" >> /tmp/report.txt
fi
fi
- u09.sh
#!/bin/bash
REPORT=/tmp/report.txt
FILE=/etc/hosts
TMP1=`ls -l $FILE | awk '{print $3}'`
if [ $TMP1 == 'root' ] ; then
find /etc/hosts -perm 600 > /dev/null 2>&1
if [ $? -eq 0 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U09\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U09\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U09\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U09\tFAIL\n" >> /tmp/report.txt
fi
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U09\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U09\tFAIL\n" >> /tmp/report.txt
fi
fi
- u12.sh
#!/bin/bash
REPORT=/tmp/report.txt
FILE=/etc/services
TMP1=`ls -l $FILE | awk '{print $3}'`
if [ $TMP1 == 'root' ] || [ $TMP1 == 'bin' ] || [ $TMP1 == 'sys' ]; then
find /etc/services -perm 644 > /dev/null 2>&1
if [ $? -eq 0 ] ; then
if [ -f "$REPORT" ] ; then
echo -e "U12\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U12\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U12\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U12\tFAIL\n" >> /tmp/report.txt
fi
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U12\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U12\tFAIL\n" >> /tmp/report.txt
fi
fi
- u26.sh
#!/bin/bash
REPORT=/tmp/report.txt
systemctl status autofs.service >> afs.txt
CHK=`awk -F" " '$1 ~ /Active/ {print $2}' afs.txt`
if [ "$CHK"="inactive" ]
then
if [ -f "$REPORT" ] ; then
echo -e "U26\tGOOD\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U26\tGOOD\n" >> /tmp/report.txt
fi
else
if [ -f "$REPORT" ] ; then
echo -e "U26\tFAIL\n" >> /tmp/report.txt
else
echo -e " RESULT\n============\nITEM\tRSLT\n============\n" >> /tmp/report.txt
echo -e "U26\tFAIL\n" >> /tmp/report.txt
fi
fi
rm afs.txt
playbook
---
- name: execute a script
hosts: allservers
tasks:
- name: copy_file # 호스트에서 노드로 파일복사
copy: src={{ item }} dest=/home/user mode=0777
loop:
- u01.sh
- u02.sh
- u03.sh
- u04.sh
- u06.sh
- u07.sh
- u08.sh
- u09.sh
- u12.sh
- u26.sh
- name: run_script # 스크립트 파일 실행
command: sh /home/user/{{ item }}
loop:
- u01.sh
- u02.sh
- u03.sh
- u04.sh
- u06.sh
- u07.sh
- u08.sh
- u09.sh
- u12.sh
- u26.sh
- name: delete_script
file:
path: /home/user/{{ item }}
state: absent
loop:
- u01.sh
- u02.sh
- u03.sh
- u04.sh
- u06.sh
- u07.sh
- u08.sh
- u09.sh
- u12.sh
- u26.sh
플레이북 실행결과
- 스크립트 복사
- 스크립트 실행
- 스크립트 파일 제거
호스트에서 report 확인
결론
CentOS7 환경에서 스크립트와 ansible을 기반으로 기술적 취약점 진단을 정해진 호스트에 배포하고 실행하는 일련의 작업들을 수행하였다. 이 프로젝트를 통해 보안을 위해 점검해야 할 부분이 어떤 것들이 있는지 조금은 이해할 수 있었다, 또한 점검하는 스크립트를 작성하고 ansible 플레이북을 작성하는 과정에서 쉘 프로그래밍과 ansible 활용에도 익숙해진 것 같다.