Ubuntu 24.04에서 auditd로 파일 변경과 명령 실행 감사하기

서버에서 /etc/passwd가 언제 바뀌었는지는 파일 mtime으로 알 수 있지만, 누가 어떤 명령으로 바꿨는지는 알 수 없다. journald에는 sudo를 거친 명령만 남고, 공격자가 이미 root 셸을 얻었다면 그마저도 남지 않는다. 리눅스 커널의 audit 서브시스템은 이런 상황을 위해 syscall 단위로 기록을 남기고, auditd가 그 기록을 수집한다. 이 글에서는 Ubuntu 24.04에서 auditd 규칙을 작성해 파일 변경과 명령 실행을 추적하고, 규칙이 붙었을 때의 오버헤드까지 실측해서 정리한다.

설치와 상태 확인

커널 쪽 audit은 Ubuntu 기본 커널에 이미 들어있고, 사용자 공간 데몬만 설치하면 된다.

$ sudo apt install -y auditd audispd-plugins

$ sudo auditctl -s
enabled 1
failure 1
pid 1799
rate_limit 0
backlog_limit 8192
lost 0
backlog 0
backlog_wait_time 60000
backlog_wait_time_actual 0

$ sudo auditctl -v
auditctl version 3.1.2

lost가 0이 아니면 커널이 이벤트를 버렸다는 뜻이므로 규칙을 줄이거나 backlog_limit을 키워야 한다.

파일 감시 규칙 (-w)

-w는 경로 하나를 감시하는 가장 단순한 형태이고, -p로 감시할 접근 종류를, -k로 나중에 검색할 키를 지정한다.

플래그의미
-p r읽기
-p w쓰기
-p x실행
-p a속성 변경(chmod/chown 등)
$ sudo auditctl -w /etc/passwd -p wa -k passwd_watch
$ sudo auditctl -l
-w /etc/passwd -p wa -k passwd_watch

# 다른 터미널에서 계정 셸을 바꿨다고 가정
$ sudo usermod -s /usr/sbin/nologin audit_demo

$ sudo ausearch -k passwd_watch -ts recent --format text
At 14:51:10 08/30/2026 noble, acting as root, successfully add_rule passwd_watch using /usr/sbin/auditctl
At 14:51:10 08/30/2026 noble, acting as root, successfully opened-file /etc/passwd using /usr/sbin/usermod
At 14:51:10 08/30/2026 noble, acting as root, successfully renamed /etc/passwd+ to /etc/passwd using /usr/sbin/usermod

“noble, acting as root”가 핵심이다. audit은 로그인 시점의 원래 사용자 ID(auid)를 프로세스마다 물려주기 때문에, sudo나 su로 root가 된 뒤의 행동도 원래 계정으로 추적된다.

시스템콜 규칙 (-a)

경로가 아니라 syscall 자체를 거는 형태다. -F 필터를 붙여 대상을 좁히지 않으면 로그가 순식간에 폭증하므로, 일반 사용자(auid>=1000)로 범위를 제한하는 것이 기본이다.

$ sudo auditctl -a always,exit -F arch=b64 -S execve -F 'auid>=1000' -F 'auid!=unset' -k exec_user
$ sudo auditctl -a always,exit -F arch=b64 -S openat -F 'exit=-EACCES' -F 'auid>=1000' -k denied

$ sudo auditctl -l
-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=-1 -F key=exec_user
-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F key=denied

일반 사용자로 명령을 실행하고 권한 없는 파일을 열어본 결과다.

$ sudo su - audit_demo -s /bin/bash -c 'id -u; cat /etc/shadow'
1001
cat: /etc/shadow: Permission denied

$ sudo ausearch -k exec_user -ts recent --format text | head -2
At 14:51:49 08/30/2026 noble, acting as audit_demo, successfully executed /usr/bin/id
At 14:51:49 08/30/2026 noble, acting as audit_demo, successfully executed /usr/bin/cat

$ sudo ausearch -k denied -ts recent --format text | tail -1
At 14:51:49 08/30/2026 noble, acting as audit_demo, unsuccessfully opened-file /etc/shadow using /usr/bin/cat

exit=-EACCES 필터 덕분에 성공한 접근은 전부 걸러지고 거부된 접근만 남는다. 침해 흔적을 찾을 때 가장 먼저 보게 되는 규칙이다.

ausearch와 aureport로 조회하기

명령용도
ausearch -k <key>규칙에 붙인 키로 검색
ausearch -ua <user>특정 사용자(auid 포함)의 이벤트
ausearch -x <path>특정 실행 파일이 일으킨 이벤트
ausearch -ts recent최근 10분 (today, 02:00 등도 가능)
--format text원시 레코드 대신 한 줄 요약
aureport -k --summary키별 이벤트 건수 집계
$ sudo aureport -k --summary

Key Summary Report
===========================
total  key
===========================
130  exec_user
73  shadow_watch
8  passwd_watch
3  denied

$ sudo ausearch -ua audit_demo -ts recent --format text | tail -3
At 14:51:49 08/30/2026 noble, acting as audit_demo, successfully executed /usr/bin/id
At 14:51:49 08/30/2026 noble, acting as audit_demo, successfully executed /usr/bin/cat
At 14:51:49 08/30/2026 noble, acting as audit_demo, unsuccessfully opened-file /etc/shadow using /usr/bin/cat

위 집계에서 shadow_watch가 73건인데, 이건 /etc/shadow에 읽기 감시(-p rwa)를 걸어둔 결과다. 로그인·sudo·su가 모두 shadow를 읽으므로 읽기 감시는 이렇게 금방 불어난다.

규칙 영구 적용

auditctl로 넣은 규칙은 재부팅하면 사라진다. /etc/audit/rules.d/에 파일로 두면 부팅 시 augenrules가 합쳐서 로드한다.

## 계정/인증 관련 파일 변경 감시
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity
-w /etc/sudoers.d/ -p wa -k identity

## sshd 설정 변경 감시
-w /etc/ssh/sshd_config -p wa -k sshd_config

## 일반 사용자의 명령 실행 기록
-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=unset -k exec_user

## 권한 거부된 파일 접근
-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -k denied
-a always,exit -F arch=b64 -S openat -F exit=-EPERM  -F auid>=1000 -k denied
$ sudo augenrules --load > /dev/null
$ sudo reboot

# 재부팅 후
$ sudo auditctl -l
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity
-w /etc/sudoers.d -p wa -k identity
-w /etc/ssh/sshd_config -p wa -k sshd_config
-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=-1 -F key=exec_user
-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F key=denied
-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F key=denied

오버헤드와 로그 증가량 실측

execve 규칙은 프로세스를 띄울 때마다 레코드를 만들기 때문에 비용이 가장 큰 축에 든다. 같은 호스트(Ubuntu 24.04, 커널 6.8.0-138)에서 일반 사용자로 /bin/true를 2만 번 실행해 비교했다.

$ su - audit_demo -s /bin/bash -c 'for i in $(seq 20000); do /bin/true; done'
회차규칙 없음execve 규칙 적용
130.9s38.0s
233.4s36.6s
330.4s38.1s

10~25% 정도 느려지고, 같은 구간에서 audit.log는 7,014 KiB 늘었다. 이벤트 하나에 약 350바이트인 셈이다.

$ grep -E '^(max_log_file|num_logs|max_log_file_action|disk_full_action)' /etc/audit/auditd.conf
max_log_file = 8
num_logs = 5
max_log_file_action = ROTATE
disk_full_action = SUSPEND

기본값은 8MB짜리 로그 5개, 총 40MB다. 위 측정대로면 execve 11만 건 정도로 전체 로그가 한 바퀴 돌아 오래된 기록이 사라진다.

주의사항

  • -F 'auid>=1000'은 반드시 따옴표로 감쌀 것. 감싸지 않으면 셸이 >를 리다이렉션으로 해석해 =1000이라는 파일이 생기고, auditctl은 -F missing operation for auid 오류를 낸다.
  • 스크립트나 cron에서 ausearch를 파이프로 실행하면 결과가 비어 나온다. stdin이 파이프면 ausearch가 로그 파일 대신 stdin을 입력으로 삼기 때문이다. 이 경우 --input-logs를 붙여야 한다.
  • 읽기 감시(-p r)는 신중하게. /etc/shadow처럼 인증 경로에서 자주 열리는 파일에 걸면 로그가 빠르게 회전해 정작 필요한 기록이 밀려난다. 장기 보존이 필요하면 max_log_file/num_logs를 먼저 키우거나 원격 수집을 붙인다.
  • auditctl -e 2(immutable)는 재부팅 전까지 되돌릴 수 없다. 규칙 변경 자체를 막는 모드라 운영 서버에 적용할 때는 규칙을 충분히 검증한 뒤여야 한다.
  • 32비트 바이너리가 도는 시스템은 -F arch=b32 규칙도 함께 넣어야 한다. arch=b64만 걸면 32비트 프로세스의 syscall은 그대로 빠져나간다.
$ sudo auditctl -e 2
enabled 2
$ sudo auditctl -w /tmp -p wa -k tmp_watch
The audit system is in immutable mode, no rule changes allowed

마무리

auditd의 값어치는 auid에 있다. 파일 mtime이나 sudo 로그로는 root 뒤에 숨은 실제 계정을 되짚을 수 없지만, audit 레코드는 로그인 시점의 사용자를 끝까지 물고 간다. 처음부터 규칙을 넓게 깔기보다 계정 파일 감시와 권한 거부 접근 두 가지로 시작해서, 로그 증가량을 보면서 execve 같은 무거운 규칙을 얹는 순서를 권한다.

참고

답글 남기기