rm -fr /* 명령어로 인한 데이터 손실 복구 사례 및 예방 방법

서론

연휴 전, 5일간의 휴가를 앞둔 소린은 마음이 들떠 있었습니다. 간단한 Bash 스크립트 작성에 신경을 덜 쓰고, 작성 후 검토조차 하지 않은 채 바로 물리 서버에서 실행했습니다.

스크립트 실행 중 이상 징후가 발생했지만, 바로 Ctrl + C로 강제 종료시켰습니다. 이후 ls 명령어를 입력하려 했으나, 해당 명령어가 존재하지 않는다는 메시지가 떴습니다. 상황 파악 후 소린은 자신이 rm -fr /* 명령어를 실수로 실행했다는 사실을 깨달았습니다. 이 서버는 회사의 인증 서버였으며, 중요한 기록과 정보들이 저장된 곳이었습니다.

소린은 상황을 리더에게 즉시 보고했습니다. 리더는 웃으면서 "중요 파일부터 확인해보라"며, 자신의 컴파일 서버 백업을 제안했습니다. 다행히도 중요한 데이터들은 손상되지 않았으며, 복구 과정을 통해 문제 해결에 성공했습니다.


문제 원인 분석

문제의 근원지는 다음과 같은 코드에 있었습니다:

new_lic_dir=`pwd`/new_license
rm -fr $new_lic_dir/*

위 코드에서 new_lic_dir 변수에 값을 할당할 때 *백틱()** 을 사용했는데, 이는 쉘에서 명령어 대체를 의미합니다. 즉, ${lic_path}/new_license`는 실제로 실행될 수 없는 명령어로 간주되어 비어있는 값으로 처리되었습니다. 결과적으로 rm -fr / 명령어가 실행되었고, 이는 시스템의 모든 파일을 삭제하려는 위험한 동작입니다.

올바른 코드는 아래와 같습니다:

new_lic_dir="${PWD}/new_license"
rm -fr "${new_lic_dir:?}/*"

여기서 "${new_lic_dir:?}"는 변수가 비어있을 경우 오류를 발생시키므로 안전하게 동작합니다.


###상황 진단 및 조치

####1. 서버 상태 유지 삭제 작업이 진행 중임을 발견한 순간, 즉각히 스크립트를 중단했습니다. 또한 서버 재부팅이나 SSH 세션 종료는 피했습니다. 이를 통해 일부 시스템 파일은 살아남았습니다.

  • 삭제된 주요 디렉터리:
  • /bin, /boot, /dev
  • /lib의 일부 동적 라이브러리 파일

####2. 잔존 파일 확인 ls 명령어가 사라졌지만, cd 명령어는 여전히 작동했습니다. 따라서 Tab 자동완성 기능을 활용해 디렉터리 구조를 확인했습니다.

예시:

cd /bi<Tab>   # → /bin/
cd /bo<Tab>   # → /boot/

이 방법으로 각 디렉터리 내 파일들을 점검하고 삭제 여부를 확인했습니다.


###파일 복구 과정

####1. 필요한 도구 확보 wget 명령어가 살아남아 있어 외부로부터 파일을 다운로드할 수 있었습니다. 다른 서버에서 /bin 디렉터리를 압축하여 웹 서버에 업로드한 후, 이를 다운로드받아 복구했습니다.

예시:

wget http://other-server/path/to/bin.tar.gz
perl -e 'chmod 0755, "tar"'
tar xzf bin.tar.gz -C /

####2. 권한 부여 다운로드된 파일에는 실행 권한이 없었으므로, Perl 스크립트를 통해 권한을 설정했습니다.

예시:

perl -e 'chmod 0755, "ls"'

####3. 나머지 디렉터리 복구 같은 방식으로 /boot, /dev, /lib 디렉터리도 복구했습니다.


###오류 예방 방법

####1. 변수 유효성 검사 삭제 명령어 실행 전, 타겟 디렉터리의 유효성을 체크합니다.

예시:

work_path="${PWD}/target"
if [ -d "$work_path" ]; then
    rm -fr "$work_path/*"
fi

####2. set -u 옵션 사용 스크립트 실행 중 미정의 변수를 사용할 경우 오류를 발생시킵니다.

예시:

#!/bin/bash
set -u

dir="$work_path"
rm -fr "${dir:?}/*"

####3. safe-rm 도구 사용 safely-rm과 같은 도구를 사용하면 특정 경로(예: /etc, /boot)를 보호할 수 있습니다.

설치 및 설정:

sudo apt install safe-rm
echo "/etc" >> /etc/safe-rm.conf
echo "/boot" >> /etc/safe-rm.conf
alias rm="safe-rm"

####4. 리사이클 바구니 구현 삭제된 파일을 별도의 디렉터리로 이동하는 방식으로 삭제 기능을 대체합니다.

예시:

trash_dir="/home/.trash"
mkdir -p "$trash_dir"

mv "$file_to_delete" "$trash_dir/"

crontab 설정을 통해 주기적으로 복구 불가능한 파일들을 정리합니다.

0 0 * * * rm -rf /home/.trash/*

####5. 파일 시스템 읽기 전용 마운트 필요한 경우 루트 파일 시스템을 읽기 전용으로 마운트합니다.

예시:

mount -o remount,ro /

###결론

rm -fr /*와 같은 치명적인 명령어를 방지하기 위해 항상 주의가 필요합니다. 스크립트 작성 후 충분히 검토하고, 테스트 환경에서 실행 결과를 확인해야 합니다. 문제가 발생한 경우에도 즉각적인 조치를 취하면 데이터 손실을 최소화할 수 있습니다.

태그: linux bash safe-rm

5월 31일 16:24에 게시됨