실습> 원격 백업 시스템 구축하기 (semi project : 02.13 ~ 02.22)

SW·2023년 2월 15일
0

rsync + ssh + 공개키 + crond를 이용

Admin Client: 200.200.200.1
Real Server: 200.200.200.3
Remote Backup Server: 200.200.200.4

                  Remote
Real server       Backup server
+----------+      +----------+
|      +-----------          |
|  S1  |   |      |    S2    |
|      +---------->          |
+----------+      +----------+
    .3                .4

        200.200.200.0/24

위에서의 단점 BackupServer가 root로 접근이 가능하면 문제가 되므로 PermitRootLogin 은 3개의 값을 지정할 수 있다.
yes : root 접근허용 가능
no : root 접근허용 금지
forced-commands-only : 공개키의 명령만 실행하겠다는 의미
root로 ssh로 접근은 금지하되 특정 명령어는 가능하게 할때 사용한다.

-- 순서 --
step 1. 방화벽 설정
step 2. 공개키, 개인키 생성
step 3. /root/bin/validate-rsync 생성
step 4. 백업서버에서 rsync 로 백업
step 5. 백업스크립트 작성
step 6. ssh-agent 실행
step 7. crond 등록
step 8. ssh-agent 실행
step 9. 백업스크립트 수정
step 10. 백업 테스트
step 11. 시간 복원
-- 순서 --

######################
step 1. 방화벽 설정
######################
관리자 IP주소와 원격 백업 서버의 IP주소만 SSH를 접근할 수 있도록 방화벽을 설정한다.

RealServer ~# systemctl stop firewalld
RealServer ~# systemctl disable firewalld
RealServer ~# yum -y install iptables-services
RealServer ~# vi /etc/sysconfig/iptables
# Generated by iptables-save v1.4.21 on Wed Feb 15 10:07:14 2023
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [16:1256]
-A INPUT -m state --state INVALID -m comment --comment "깨진 패킷 로그 기록" -j LOG --log-prefix "DROP INVALID " --log-tcp-options --log-ip-options
-A INPUT -m state --state INVALID -m comment --comment "깨진 패킷 차단" -j DROP
-A INPUT -m state --state RELATED,ESTABLISHED -m comment --comment "이미 연결된 패킷 허용" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -m comment --comment "WEB: http" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -m state --state NEW -m comment --comment "WEB: https" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 53 -m state --state NEW -m comment --comment "DNS Zone Transfer" -j ACCEPT
-A INPUT -p udp -m udp --dport 53 -m state --state NEW -m comment --comment "DNS Query" -j ACCEPT
-A INPUT -p tcp -m tcp -m multiport --dports 8009,8005 -m state --state NEW -m comment --comment TOMCAT -j ACCEPT
-A INPUT -p tcp -m tcp --dport 25 -m state --state NEW -m comment --comment "MAIL: smtp" -j ACCEPT
-A INPUT -s 200.200.200.1/32 -p tcp -m tcp --dport 22 -m state --state NEW -m comment --comment "Admin IP" -j ACCEPT
-A INPUT -s 200.200.200.4/32 -p tcp -m tcp --dport 22 -m state --state NEW -m comment --comment "Remote Backup Server" -j ACCEPT
-A INPUT -i lo -j ACCEPT
COMMIT
# Completed on Wed Feb 15 10:07:14 2023

RealServer ~# iptables-restore /etc/sysconfig/iptables


RealServer ~# iptables -nvL
Chain INPUT (policy DROP 13 packets, 2524 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID /* 깨진 패킷 로그 기록 */ LOG flags 6 level 4 prefix "DROP INVALID "
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            state INVALID /* 깨진 패킷 차단 */
30807 2476K ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED /* 이미 연결된 패킷 허용 */
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 state NEW /* WEB: http */
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:443 state NEW /* WEB: https */
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53 state NEW /* DNS Zone Transfer */
   39  2526 ACCEPT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53 state NEW /* DNS Query */
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp multiport dports 8009,8005 state NEW /* TOMCAT */
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:25 state NEW /* MAIL: smtp */
    0     0 ACCEPT     tcp  --  *      *       200.200.200.1        0.0.0.0/0            tcp dpt:22 state NEW /* Admin IP */
   24  1440 ACCEPT     tcp  --  *      *       200.200.200.4        0.0.0.0/0            tcp dpt:22 state NEW /* Remote Backup Server */
    1    60 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 28491 packets, 420M bytes)
 pkts bytes target     prot opt in     out     source               destination

###############################
step 2. 공개키, 개인키 생성
###############################
ssh-keygen 명령어를 이용해서 공개키와 개인키 쌍을 생성한다.
키의 암호문은 암호문은 테스트이므로 P@ssw0rd로 설정한다.
BackupServer ~# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): <-- 여기서는 그냥 엔터
Enter passphrase (empty for no passphrase): <-- 암호문 P@ssw0rd 입력
Enter same passphrase again: <-- 암호문 P@ssw0rd 입력
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:yiT9Mh/MRuyrLXUwf57veBww6fFtrDlqV1gxMlCocpk root@web1.linuxmaster.net
The key's randomart image is:

+---[RSA 2048]----+
|           .+.   |
|           . o o |
|          +  .o o|
|     . ooE  =   .|
|    . o S+ . = = |
|     + B. o o + =|
|      =.B. o o * |
|      .* o  +.B  |
|      .o+  .o*o. |
+----[SHA256]-----+
BackupServer ~# ll .ssh
합계 12
-rw-------. 1 root root 1766  2월 15 10:12 id_rsa     <-- 개인키
-rw-r--r--. 1 root root  401  2월 15 10:12 id_rsa.pub <-- 공개키
-rw-r--r--. 1 root root  175  2월 15 10:00 known_hosts

RealServer에서 /root/.ssh 디렉터리를 생성한다.
생성하기 위해서는 ssh localhost로 접속하고 Ctrl + C를 눌러서 종료한다.
RealServer ~# ssh localhost
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:sNNXOE97kZTiu5BwsqYZmmlRl47O/13+DwzpI6qd21c.
ECDSA key fingerprint is MD5:b1:8b:b7:62:61:26:a7:7d:60:86:ac:40:bb:82:d0:42.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
root@localhost's password:  <-- yes
^C  <-- yes 누르고 Ctrl + C 를 입력해서 종료한다.

# ls -l .ssh/
합계 4
-rw-r--r--. 1 root root 171  2월 15 10:38 known_hosts

암호문이 있는 공개키를 Real Server에 복사한다.
복사할 때 파일명을 /root/.ssh/authorized_keys 으로 복사해야 한다.
BackupServer ~# scp .ssh/id_rsa.pub 200.200.200.3:.ssh/authorized_keys
root@200.200.200.3's password:   <-- root의 암호를 입력한다.
id_rsa.pub                                         100%  407   128.7KB/s   00:00 

BackupServer에서 원격 복사가 완료된 후 authorized_keys 파일을 확인하면 파일이 잘 복사된 것을 확인할 수 있다.
RealServer ~# # ls -l .ssh/
합계 8
-rw-r--r--. 1 root root 401  2월 15 10:40 authorized_keys  <-- 복사된 공개키 파일
-rw-r--r--. 1 root root 171  2월 15 10:38 known_hosts

공개키 복사가 완료되면 root로 로그인하지 못하도록 설정파일을 수정하고 sshd를 재시작한다.
PermitRootLogin yes -> PermitRootLogin forced-commands-only
RealServer ~# vi /etc/ssh/sshd_config 
PermitRootLogin forced-commands-only

RealServer ~# systemctl reload sshd

authorized_keys 파일을 열어서 ssh-rsa 앞에
from="200.200.200.4",command="/root/bin/validate-rsync" 를 추가한다.
RealServer ~# vi .ssh/authorized_keys 
from="200.200.200.4",command="/root/bin/validate-rsync" ssh-rsa AAAAB3NzaC1yc2EAAAA(생략 ...)

##########################################
step 3. /root/bin/validate-rsync 생성
##########################################
/root/bin 디렉터리를 생성하고 그 디렉터리에 validate-rsync 파일을 생성한다.

RealServer ~# mkdir bin; cd bin
RealServer bin# vi validate-rsync
#!/bin/sh
case "$SSH_ORIGINAL_COMMAND" in
          *\&*) echo "Rejected" ;;
          *\(*) echo "Rejected" ;;
          *\{*) echo "Rejected" ;;
          *\;*) echo "Rejected" ;;
          *\<*) echo "Rejected" ;;
          *\`*) echo "Rejected" ;;
          rsync\ --server*) $SSH_ORIGINAL_COMMAND ;;
          *) echo "Rejected" ;;
esac

RealServer bin# chmod 755 validate-rsync 

######################################
step 4. 백업서버에서 rsync 로 백업
######################################
BackupServer에서 /backup 디렉터리를 생성한다.
BackupServer ~# mkdir -m 700 /backup

백업을 하기 위해서 Real Server와 Backup Server에 rsync 패키지를 설치한다.
RealServer ~# yum -y install rsync
BackupServer ~# yum -y install rsync

Real Server에 있는 /etc 디렉터리를 간단하게 백업테스트를 진행하고 백업 성공여부는 /etc 디렉터리가 복사되면 잘 백업된 것이다.
백업이 진행되는 과정을 확인하고자 한다면 -az 를 -avz로 옵션을 지정한다.
BackupServer ~# rsync -az -e ssh 200.200.200.3:/etc /backup
Enter passphrase for key '/root/.ssh/id_rsa': <-- 암호문 P@ssw0rd를 입력한다.

BackupServer ~# tree -L 1 /backup/
/backup/
└── etc

1 directory, 0 files

##############################
step 5. 백업스크립트 작성
##############################

BackupServer ~# mkdir bin
BackupServer ~# install /dev/null bin/rsyncBackup.sh 
BackupServer ~# vi bin/rsyncBackup.sh 
#!/bin/sh
# 파일명: rsyncBackup.sh
# 프로그램 설명: rsync 서버 백업 스크립트
# 작성자: 리눅스마스터넷
# 버전: 2023021501

today=$(date +%Y%m%d)
rsyncServer="200.200.200.3"
backupDir="/var/log /etc /home"

# 날짜 디렉터리가 존재하지 않으면 생성한다.
if [ ! -d /backup/$today ]; then
    mkdir -m 700 /backup/$today
fi

# rsync server 로 접속해서 백업한다.
for dir in $backupDir
do
   echo ">>> $dir Directory Backup <<<"
   if [ -x /usr/bin/rsync ]; then
       rsync -az -e ssh $rsyncServer:$dir /backup/$today
   fi
done


원격 백업이 잘되는지 테스트를 한다.
BackupServer ~# rm -rf /backup/*
BackupServer ~# rsyncBackup.sh 
>>> /var/log Directory Backup <<<
Enter passphrase for key '/root/.ssh/id_rsa':  <-- P@ssw0rd  입력한다.
>>> /etc Directory Backup <<<
Enter passphrase for key '/root/.ssh/id_rsa':  <-- P@ssw0rd  입력한다. 
>>> /home Directory Backup <<<
Enter passphrase for key '/root/.ssh/id_rsa':  <-- P@ssw0rd 를 입력한다. 

BackupServer ~# tree -L 2 /backup
/backup
└── 20220420
    ├── etc
    ├── home
    └── log

4 directories, 0 files

##########################
step 6. ssh-agent 실행
##########################

새벽에 원격으로 백업을 받기 위해서는 사람이 암호문을 입력할 수 없기 때문에 암호문을 자동으로 입력할 수 있도록 설정한다. 
이를 위해서 ssh-agent를 실행한다. 참고로 ssh-agent는 한번만 실행한다.
ssh-agent를 실행하면 변화되는 내용 두 가지는 아래와 같다.
첫 번째 : 소켓 파일이 생성된다. (/tmp/ssh-CB95iHUyMZry/agent.2031)
-참고로 실행될 때 마다 랜덤으로 파일이 생성되면 PID 번호도 달라진다.
두 번째 : 프로세스가 실행된다. (ssh-agent)
BackupServer ~# ssh-agent 
SSH_AUTH_SOCK=/tmp/ssh-xlPP2qAR7w10/agent.1708; export SSH_AUTH_SOCK;
SSH_AGENT_PID=1709; export SSH_AGENT_PID;
echo Agent pid 1709;

소켓 파일이 생성되므로 이 소켓 파일을 확인한다.
BackupServer ~# ls -l /tmp/ssh-xlPP2qAR7w10/
합계 0
srw-------. 1 root root 0  2월 15 10:56 agent.1708

ssh-agent가 메모리에 떠있으므로 이 프로세스를 확인한다.
BackupServer ~# ps aux | grep agent
root       1709  0.0  0.0  72472   776 ?        Ss   10:56   0:00 ssh-agent
root       1712  0.0  0.1 116972  1024 pts/0    S+   10:56   0:00 grep --color=auto agent

위에서 출력된 소켓파일의 위치와 프로세스 번호를 환경변수로 등록한다.
BackupServer ~# SSH_AUTH_SOCK=/tmp/ssh-xlPP2qAR7w10/agent.1708; export SSH_AUTH_SOCK;
BackupServer ~# SSH_AGENT_PID=1709; export SSH_AGENT_PID;

암호문을 ssh-add 명령어를 통해서 입력한다.
BackupServer ~# ssh-add
Enter passphrase for /root/.ssh/id_rsa:   <-- P@ssw0rd를 입력한다.
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)

원격 백업 테스트를 실행하기 위해서 /backup 디렉터리에 임시로 저장한 백업 파일들을 모두 삭제한다.
ssh-add 명령어로 암호문을 등록했기 때문에 Real Server로 접속할 때 자동으로 ssh-agent가 암호문을 대신 전달해준다.
여기까지 잘 실행되서 원격 백업을 할 수 있다면 Cron 에 자동으로 등록해서 Real Server의 자료를 백업할 수 있다.
BackupServer ~# rm -rf /backup/*
BackupServer ~# rsyncBackup.sh 
>>> /var/log Directory Backup <<<
>>> /etc Directory Backup <<<
>>> /home Directory Backup <<<
BackupServer ~# tree -L 2 /backup/
/backup/
└── 20230215
    ├── etc
    ├── home
    └── log

4 directories, 0 files

만약 자동 접속을 해제하고 싶다면 ssh-agent -k, unset 을 이용해서 환경변수를 삭제하면 된다. 
ssh-agent 프로세스를 종료하는 방법은 ssh-agent -k를 사용한다. (kill 보다는 이 방법을 사용하는 것을 추천한다.)
ssh-agent -k 를 사용하면 
첫 번째 : 소켓 파일이 삭제된다. (/tmp/ssh-yYeeCgpi8NQB/agent.44230)
두 번째 : 프로세스가 종료된다. (ssh-agent)
세 번째 : 환경변수는 아래 출력되는 unset으로 직접 삭제해야 한다.
BackupServer ~# ssh-agent -k
unset SSH_AUTH_SOCK;
unset SSH_AGENT_PID;
echo Agent pid 1709 killed;

환경변수 정보를 모두 삭제한다.
BackupServer ~# unset SSH_AUTH_SOCK; unset SSH_AGENT_PID;

######################
step 7. crond 등록
######################
새벽 4시 20분에 rsyncBackup.sh 가 실행될 수 있도록 시스템 크론에 등록한다.
BackupServer ~# vi /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

20 04 * * * root /root/bin/rsyncBackup.sh

##########################
step 8. ssh-agent 실행
##########################

ssh-agent를 실행해서 출력되는 내용을 파일로 저장하고 . 을 이용해서 실행한다. 
. ssh-agent.txt를 실행하면 ssh-agent.txt 안에 저장된 환경변수들이 설정된다.
BackupServer ~# ssh-agent > /root/ssh-agent.txt
BackupServer ~# . ssh-agent.txt 
Agent pid 1751

ssh-add 를 실행해서 암호문을 추가한다.
BackupServer ~# ssh-add 
Enter passphrase for /root/.ssh/id_rsa:  <-- 암호문 P@ssw0rd를 입력한다.
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)

백업 스크립트를 실행하고 백업된 파일들을 확인한다.
BackupServer ~# rsyncBackup.sh 
BackupServer ~# tree -L 2 /backup/
/backup/
└── 20230215
    ├── etc
    ├── home
    └── log

4 directories, 0 files

#############################
step 9. 백업스크립트 수정
#############################

ssh-agent 환경변수가 저장된 파일을 실행하는 부분을 스크립트에 추가한다.
BackupServer ~# vi bin/rsyncBackup.sh 
#!/bin/sh
# 파일명: rsyncBackup.sh
# 프로그램 설명: rsync 서버 백업 스크립트
# 작성자: 리눅스마스터넷
# 버전: 2023021502

today=$(date +%Y%m%d)
rsyncServer="200.200.200.3"
backupDir="/var/log /etc /home"

# ssh-agent 환경변수가 저장된 파일을 실행시킨다.
. /root/ssh-agent.txt

# 날짜 디렉터리가 존재하지 않으면 생성한다.
if [ ! -d /backup/$today ]; then
    mkdir -m 700 /backup/$today
fi

# rsync server 로 접속해서 백업한다.
for dir in $backupDir
do
   echo ">>> $dir Directory Backup <<<"
   if [ -x /usr/bin/rsync ]; then
       #rsync -az $rsyncServer::$dir /backup/$today/$dir
       rsync -az -e ssh $rsyncServer:$dir /backup/$today
   fi
done

########################
step 10. 백업 테스트
########################

/backup 디렉터리의 파일들을 삭제한 후 백업이 잘 되는지 확인한다.
BackupServer ~# rm -rf /backup/*
BackupServer ~# ls /backup/
BackupServer ~# date 
2023. 02. 15. (수) 11:15:32 KST

BackupServer ~# date 02160418
2023. 02. 16. (목) 04:18:00 KST

백업이 잘 되는지 로그파일을 모니터링한다.
04:20분에 백업스크립트인 /root/bin/rsyncBackup.sh 파일이 실행되면 CMD 명령어가 아래처럼 출력되고 
Ctrl + C를 눌러서 로그 모니터링을 종료한다. 
BackupServer ~# tail -f /var/log/cron
  :
  :(생략)
Feb 16 04:20:01 ns2 CROND[1810]: (root) CMD (/root/bin/rsyncBackup.sh)
^C  <-- Ctrl + C를 눌러서 종료한다.

BackupServer ~# tree -L 2 /backup
/backup
└── 20230216
    ├── etc
    ├── home
    └── log

4 directories, 0 files

######################
step 11. 시간 복원
######################
원격 백업 테스트가 완료되면 정확한 시간을 설정한다.
BackupServer ~# rdate -s time.bora.net
BackupServer ~# date
2022. 04. 20. (수) 15:19:52 KST

profile
정보보안 전문가

0개의 댓글