서버에서 /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 규칙 적용 |
|---|---|---|
| 1 | 30.9s | 38.0s |
| 2 | 33.4s | 36.6s |
| 3 | 30.4s | 38.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 같은 무거운 규칙을 얹는 순서를 권한다.
참고
- linux-audit/audit-userspace — auditctl/ausearch/aureport 소스
- Linux Audit Documentation Wiki — 규칙 문법과 필드 레퍼런스
- auditctl(8) man page