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