대상 OS: Rocky Linux 9
서버 침해사고의 시작은 종종 ‘새로 떨어진 실행 파일’입니다.
웹쉘이든 크론이든, 공격자가 결국 하고 싶은 건 임의 바이너리를 실행하는 것이죠.
방화벽/계정정책/패치가 좋아도 “실행 자체”를 통제하지 않으면 마지막 문이 열려있습니다.
Rocky Linux 9에서는 fapolicyd(File Access Policy Daemon)로 실행을 화이트리스트에 가깝게 묶을 수 있습니다.
이 글은 fapolicyd를 학습 모드에서 시작해 운영 강제 모드로 전환하고, 규칙 튜닝/예외 처리/우회 포인트까지 실제로 굴릴 수 있게 정리합니다.
---
실행 제어를 넣어야 하는 순간
1) 서버에 “정체불명 바이너리”가 자꾸 생긴다
2) 운영 자동화가 많아 계정 권한을 줄이기 어렵다(하지만 실행 범위는 줄이고 싶다)
3) EDR이 없거나, 있어도 리눅스에서는 커버리지가 약하다
4) 컨테이너가 아니라 전통적인 VM/베어메탈을 오래 운용한다
fapolicyd는 SELinux처럼 강력한 MAC 체계의 일부가 아니라 “파일 접근/실행 이벤트를 정책으로 결정”하는 별도 계층입니다. 완벽한 대체재라기보다, 방어 계층을 하나 더 쌓는 용도로 좋습니다.
---
fapolicyd가 보는 것(개념만 빠르게)
- 어떤 프로세스가 어떤 파일을 열거나 실행하려는지
- 그 파일이 rpm 패키지 소속인지(=배포판이 설치한 신뢰 가능한 파일인지)
- 경로/확장자/서명/해시 등의 속성
- 규칙의 allow/deny 우선순위
운영 핵심은 이겁니다.
- “rpm으로 설치된 바이너리/라이브러리”는 기본적으로 허용
- “/tmp, /var/tmp, 홈 디렉터리에서 생성된 파일 실행”은 기본적으로 차단
- 필요한 예외만 명시적으로 풀기
---
1) 설치 및 서비스 상태 확인
1) 패키지 설치
sudo dnf -y install fapolicyd
2) 서비스 활성화(우선은 학습/관찰 단계로)
sudo systemctl enable --now fapolicyd
sudo systemctl status fapolicyd --no-pager
3) 로그 확인(차단/허용 메시지)
sudo journalctl -u fapolicyd -n 200 --no-pager
---
2) “학습→강제” 전환 전, 먼저 해야 할 점검
무작정 강제로 켜면 배포/에이전트/백업 스크립트가 터집니다. 강제 전환 전에 아래를 먼저 확인하세요.
1) 서버에서 실제로 실행되는 경로를 수집한다
sudo ausearch -m EXECVE -ts recent 2>/dev/null | tail -n 50
2) 사용 중인 배포/운영 도구의 설치 방식 확인
- dnf/rpm으로 설치되면 비교적 안전(패키지 소속 파일로 인식)
- curl로 받아서 /usr/local/bin에 두는 형태는 정책에 걸릴 수 있음
3) “임시 디렉터리 실행” 습관부터 없앤다
- /tmp에서 실행하는 설치 스크립트
- CI가 /tmp에 바이너리를 내려받아 실행
이걸 없애는 것만으로도 보안이 올라가고, fapolicyd 튜닝 비용이 확 줄어듭니다.
---
3) 기본 정책 파일 구조 파악(어디를 만지는가)
1) 주요 경로 확인
rpm -ql fapolicyd | sed -n '1,120p'
2) 설정/룰 파일 위치 확인
ls -la /etc/fapolicyd
ls -la /etc/fapolicyd/rules.d || true
Rocky 9 환경에 따라 룰이 단일 파일로 있거나 rules.d로 분리될 수 있습니다. 운영에서는 “커스텀 룰만 별도 파일로” 관리하는 게 안전합니다.
---
4) 차단이 실제로 일어나는지 ‘안전하게’ 확인
테스트용으로 홈 디렉터리에 아주 단순한 스크립트를 만들고 실행을 시도해 봅니다.
1) 테스트 파일 생성
cat > /tmp/hello.sh