Audit 서브시스템
Linux Audit 서브시스템은 커널 수준에서 보안 관련 이벤트를 기록하는 프레임워크입니다. 시스템 콜(System Call), 파일 접근, 네트워크 연결, 사용자 인증 등 거의 모든 커널 활동을 감사할 수 있으며, PCI-DSS, HIPAA, SOX, CAPP(Controlled Access Protection Profile) 등 보안 컴플라이언스 인증의 필수 요구사항을 충족합니다.
auditd)에서 영상을 저장하고, 보안 규정(PCI-DSS, CIS)에 따라 특정 구역만 집중 감시할 수 있습니다.
핵심 요약
- Audit 서브시스템은 커널 공간(Kernel Space)의 감사 후크(hook)와 사용자 공간(User Space)의
auditd데몬으로 구성됩니다. NETLINK_AUDIT소켓(Socket)을 통해 커널 이벤트가 사용자 공간으로 전달됩니다.audit_context구조체(Struct)가 시스템 콜 진입/종료 시 이벤트 데이터를 수집합니다.- 5개의 필터 리스트(task, exit, user, exclude, filesystem)로 규칙 매칭을 수행합니다.
auditctl로 규칙 관리,ausearch로 로그 검색,aureport로 보고서를 생성합니다.- PCI-DSS, CIS, STIG 등 보안 컴플라이언스 규칙 세트를 지원합니다.
단계별 이해
- 아키텍처 — 커널·사용자 공간 구성 요소와 데이터 흐름을 파악합니다.
- audit_context 생명주기 — 시스템 콜 진입/종료 시 감사 데이터 수집 과정을 이해합니다.
- 필터 엔진 — 5개 필터 리스트와 규칙 매칭 메커니즘을 학습합니다.
- 감사 도구 — auditctl, ausearch, aureport 등 실용 도구 사용법을 익힙니다.
- 보안 컴플라이언스 — PCI-DSS, CIS, NIST 800-53, ISO 27001 등에 맞춘 규칙 세트를 적용합니다.
- NETLINK_AUDIT 프로토콜 — 커널-사용자 공간 통신 프로토콜의 메시지 타입과 동작을 이해합니다.
- 백로그 메커니즘 — 백로그 큐, 실패 모드, 유실 방지 전략을 학습합니다.
- 파일 감시 내부 — audit_watch, audit_tree, fsnotify 연동의 내부 동작을 파악합니다.
- 컨테이너(Container) 환경 — 컨테이너에서의 감사 제한사항과 eBPF 대안을 이해합니다.
- io_uring 감사 — io_uring의 syscall 우회 문제와 감사 후크를 학습합니다.
- SIEM 통합 — Splunk, ELK, Wazuh 등 SIEM과의 연동 방법을 익힙니다.
Audit 서브시스템은 CONFIG_AUDIT (기본 프레임워크)와 CONFIG_AUDITSYSCALL (시스템 콜 감사)로 활성화됩니다. 배포판별 기본 활성화 정책은 참고자료에서 최신 상태를 확인하세요. 부팅 시 audit=1 커널 파라미터로 조기 부팅 단계부터 감사를 시작할 수 있습니다.
아키텍처
Audit 서브시스템은 커널 공간의 감사 후크(hook)와 사용자 공간의 auditd 데몬으로 구성됩니다. 커널이 이벤트를 수집하고, NETLINK_AUDIT 소켓을 통해 사용자 공간으로 전달합니다.
감사 규칙 평가 체인
감사 이벤트 발생 시, 커널은 5개의 필터 리스트를 정해진 순서로 평가합니다. 각 리스트의 규칙은 순차적으로 매칭되며, 첫 매칭 규칙의 action(AUDIT_ALWAYS/AUDIT_NEVER)이 적용됩니다. 규칙 배치 순서가 성능에 직접적 영향을 미치므로, 빈도 높은 제외 규칙을 앞에 배치하는 것이 중요합니다.
감사 이벤트 레코드 계층 구조
하나의 감사 이벤트는 여러 레코드 타입으로 구성됩니다. SYSCALL 레코드가 부모 역할을 하며, 관련 정보가 자식 레코드(PATH, CWD, EXECVE, SOCKADDR, PROCTITLE)로 분리됩니다. 모든 레코드는 동일한 시리얼 번호(EPOCH:SERIAL)로 연결됩니다.
ausearch는 동일 시리얼(EPOCH:SERIAL)을 가진 모든 레코드를 자동으로 그룹화하여 표시합니다. --raw 옵션으로 원시 형식을 확인하면 각 레코드가 별도 줄로 출력되며, --format text로 사람이 읽기 쉬운 형태로 재조립됩니다. 프로그래밍 방식으로 로그를 파싱할 때는 auparse 라이브러리(C API)를 사용하면 이벤트 그룹화를 자동 처리합니다.
audit_context 생명주기
모든 감사 가능한 태스크(Task)는 task_struct->audit_context를 통해 audit_context 구조체를 갖습니다. 이 구조체는 시스템 콜 진입/종료 시 이벤트 데이터를 수집하고, 규칙 매칭 결과에 따라 로그 생성 여부를 결정합니다.
/* kernel/audit.h — audit_context 핵심 필드 */
struct audit_context {
int in_syscall; /* 시스템 콜 실행 중 여부 */
enum audit_state state; /* AUDIT_STATE_{DISABLED,BUILD,RECORD} */
enum audit_state current_state; /* 현재 감사 상태 */
unsigned int serial; /* 이벤트 시리얼 번호 */
int major; /* 시스템 콜 번호 (NR) */
int uring_op; /* io_uring 연산 코드 */
unsigned long argv[4]; /* 시스템 콜 인자 (a0~a3) */
long return_code; /* 시스템 콜 반환값 */
u64 prio; /* 우선순위 (에러 시 증가) */
int return_valid; /* 반환값 유효 여부 */
/* 이름/경로 정보 */
struct audit_names *names; /* 파일 이름 연결 리스트 */
int name_count; /* 이름 항목 수 */
struct path pwd; /* 현재 작업 디렉토리 */
/* IPC/소켓 감사 정보 */
struct audit_aux_data *aux; /* 보조 감사 데이터 체인 */
struct audit_aux_data *aux_pids; /* PID 추적 보조 데이터 */
struct sockaddr_storage *sockaddr; /* 소켓 주소 */
size_t sockaddr_len;
/* 필터링 */
pid_t target_pid; /* 대상 프로세스 PID */
kuid_t target_auid; /* 대상 audit UID */
kuid_t target_uid; /* 대상 실제 UID */
/* execve 인자 (EXECVE 레코드용) */
struct audit_tree_refs *trees; /* 감시 트리 참조 */
struct audit_proctitle proctitle; /* PROCTITLE 레코드 데이터 */
/* ... */
};
/* kernel/auditsc.c — 시스템 콜 감사 흐름 */
/* 1. 시스템 콜 진입 시 — entry 후크 */
void __audit_syscall_entry(int major, unsigned long a1,
unsigned long a2, unsigned long a3,
unsigned long a4)
{
struct audit_context *context = audit_context();
if (!context)
return;
context->serial = 0; /* 새 이벤트마다 리셋 */
context->in_syscall = 1; /* 시스템 콜 내부 마크 */
context->current_state = state;
context->major = major; /* syscall NR 저장 */
context->argv[0] = a1; /* 인자 저장 */
context->argv[1] = a2;
context->argv[2] = a3;
context->argv[3] = a4;
}
/* 2. 시스템 콜 종료 시 — exit 후크 */
void __audit_syscall_exit(int success, long return_code)
{
struct audit_context *context = audit_context();
context->return_valid = AUDITSC_SUCCESS;
context->return_code = return_code;
/* exit 필터 리스트에서 규칙 매칭 */
if (context->current_state == AUDIT_STATE_BUILD)
state = audit_filter_syscall(context);
/* RECORD 상태면 감사 레코드 생성 및 전송 */
if (context->current_state >= AUDIT_STATE_RECORD)
audit_log_exit(); /* → audit_log_start() + audit_log_format() */
context->in_syscall = 0; /* 시스템 콜 완료 */
audit_free_names(context); /* 이름 목록 해제 */
audit_free_aux(context); /* 보조 데이터 해제 */
}
AUDIT_STATE_DISABLED(감사 안 함) → AUDIT_STATE_BUILD(데이터 수집 중, 아직 로그 기록 미확정) → AUDIT_STATE_RECORD(규칙 매칭 성공, 로그 기록 확정). entry 필터에서 BUILD로 전환하고, exit 필터에서 최종 RECORD 여부를 결정합니다. 이 2단계 평가 방식으로 시스템 콜 반환값 기반 필터링이 가능합니다.
커널 감사 후크
Audit 서브시스템은 커널 전반에 후크를 삽입하여 보안 관련 이벤트를 포착합니다. 주요 후크 지점:
| 후크 함수 | 호출 위치 | 수집 정보 |
|---|---|---|
__audit_syscall_entry() | 시스템 콜 진입점(Entry Point) | syscall NR, 인자 4개 |
__audit_syscall_exit() | 시스템 콜 반환점 | 반환값, 성공/실패, 규칙 매칭 → 레코드 생성 |
__audit_inode() | VFS 경로 해석 | inode, 디바이스, 파일 모드, UID/GID |
__audit_inode_child() | 디렉토리 내 파일 생성/삭제 | 부모 inode, 자식 이름 |
audit_log_task_info() | 레코드 기록 시 | PID, UID, GID, comm, exe, sessionid |
__audit_mq_open() | POSIX 메시지 큐 열기 | 큐 이름, 모드, 속성 |
__audit_socket_* | 소켓 연산 | 소켓 주소, bind/connect/accept 정보 |
__audit_fd_pair() | pipe/socketpair | 파일 디스크립터(File Descriptor) 쌍 |
__audit_ptrace() | ptrace 호출 | 대상 PID, 작업 코드 |
__audit_log_kern_module() | 모듈 로드 | 모듈 이름 |
__audit_fanotify() | fanotify 응답 | 응답 유형, 대상 파일 |
__audit_tk_injoffset() | 시간 조정 | timekeeping 오프셋(Offset) 변경 |
/* fs/namei.c — VFS 경로 해석 중 감사 후크 호출 예 */
static struct dentry *__lookup_hash(
const struct qstr *name,
struct dentry *base, unsigned int flags)
{
struct dentry *dentry = lookup_dcache(name, base, flags);
if (dentry)
return dentry;
dentry = __lookup_slow(name, base, flags);
/* 감사 후크: 경로 해석 결과를 audit_context에 기록 */
if (!IS_ERR(dentry) && unlikely(audit_context()))
__audit_inode(name, dentry, flags);
return dentry;
}
감사 메시지 형식
감사 레코드는 type=TYPE msg=audit(EPOCH:SERIAL): FIELDS 형식을 따릅니다. 동일 이벤트의 여러 레코드는 같은 EPOCH:SERIAL 쌍으로 연결됩니다.
# 하나의 이벤트는 여러 레코드 타입으로 구성됨 (같은 serial 공유)
# SYSCALL — 시스템 콜 기본 정보
type=SYSCALL msg=audit(1706000000.123:789): arch=c000003e syscall=257
success=yes exit=3 a0=ffffff9c a1=7ffd1234 a2=0 a3=0
items=1 ppid=4521 pid=4523 auid=1000 uid=0 gid=0 euid=0
suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0
ses=3 comm="cat" exe="/usr/bin/cat"
subj=unconfined_u:unconfined_r:unconfined_t:s0
key="sensitive_files"
# CWD — 현재 작업 디렉토리
type=CWD msg=audit(1706000000.123:789): cwd="/home/user"
# PATH — 접근한 파일 경로 (item 번호로 순서 지정)
type=PATH msg=audit(1706000000.123:789): item=0
name="/etc/shadow" inode=131074 dev=08:01 mode=0100640
ouid=0 ogid=42 rdev=00:00 nametype=NORMAL
cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0
# PROCTITLE — 프로세스 제목 (hex 인코딩)
type=PROCTITLE msg=audit(1706000000.123:789):
proctitle=636174002F6574632F736861646F77
주요 레코드 타입
| 타입 | 번호 | 설명 | 주요 필드 |
|---|---|---|---|
SYSCALL | 1300 | 시스템 콜 이벤트 | arch, syscall, success, exit, auid, uid, exe, key |
PATH | 1302 | 파일 경로 정보 | name, inode, dev, mode, ouid, ogid, nametype |
CWD | 1307 | 현재 작업 디렉토리 | cwd |
EXECVE | 1309 | exec 인자 | argc, a0, a1, a2... |
PROCTITLE | 1327 | 프로세스(Process) 커맨드라인 | proctitle (hex 인코딩) |
SOCKADDR | 1306 | 소켓 주소 | saddr (hex 인코딩 sockaddr) |
USER_AUTH | 1100 | 사용자 인증 | pid, uid, auid, msg (PAM 정보) |
USER_LOGIN | 1112 | 사용자 로그인 | pid, uid, auid, ses, msg |
USER_CMD | 1123 | sudo 명령 실행 | pid, uid, auid, cmd |
AVC | 1400 | SELinux 접근 제어(Access Control) | pid, comm, scontext, tcontext, tclass, perm |
NETFILTER_PKT | 1325 | netfilter 패킷(Packet) 감사 | mark, saddr, daddr, sport, dport, proto |
KERN_MODULE | 1326 | 커널 모듈(Kernel Module) 로드 | name |
ANOM_ABEND | 1701 | 비정상 프로세스 종료 | auid, uid, gid, ses, pid, comm, sig |
auid (Audit UID)는 사용자가 최초 로그인할 때 설정되며, su나 sudo로 UID가 변경되어도 원래 로그인 사용자를 추적할 수 있습니다. loginuid가 한 번 설정되면 변경 불가하도록 CONFIG_AUDIT_LOGINUID_IMMUTABLE을 설정할 수 있습니다. auid가 4294967295(-1)이면 로그인 과정을 거치지 않은 데몬 프로세스입니다.
kauditd 커널 스레드(Kernel Thread)
kauditd는 커널 감사 메시지를 사용자 공간 auditd로 전달하는 커널 스레드입니다. 3개의 skb 큐를 관리하며, auditd 연결 상태에 따라 메시지 처리 전략을 결정합니다.
/* kernel/audit.c — kauditd 큐 관리 */
static struct sk_buff_head audit_queue; /* 기본 전송 큐 */
static struct sk_buff_head audit_retry_queue; /* 전송 실패 재시도 큐 */
static struct sk_buff_head audit_hold_queue; /* auditd 부재 시 보관 큐 */
static int kauditd_thread(void *dummy)
{
while (!kthread_should_stop()) {
/* 1. retry 큐: 이전 전송 실패 메시지 재전송 시도 */
kauditd_send_queue(sk, &audit_retry_queue,
UNICAST_RETRIES, kauditd_rehold_skb);
/* 2. hold 큐: auditd 복귀 시 보관 메시지 전송 */
kauditd_send_queue(sk, &audit_hold_queue,
UNICAST_RETRIES, kauditd_hold_skb);
/* 3. main 큐: 새 감사 메시지 전송 */
kauditd_send_queue(sk, &audit_queue,
1, kauditd_rehold_skb);
/* 메시지 없으면 대기 (wake_up으로 깨움) */
wait_event_freezable(kauditd_wait,
skb_queue_len(&audit_queue));
}
return 0;
}
큐 우선순위(Priority): kauditd는 매 루프에서 retry → hold → main 순서로 큐를 처리합니다. retry 큐에 실패 메시지가 있으면 main 큐 새 메시지보다 먼저 재전송(Retransmission)하여, 감사 로그의 시간순 일관성을 최대한 유지합니다. auditd가 완전히 종료된 경우 hold 큐에 메시지가 누적되며, audit_hold_queue의 크기가 audit_backlog_limit을 초과하면 오래된 메시지부터 폐기됩니다.
필터 엔진
감사 규칙은 5개의 필터 리스트에 배치되며, 이벤트 발생 시 해당 리스트의 규칙을 순차 매칭합니다. 첫 매칭 규칙의 action(always/never)이 적용됩니다.
| 필터 리스트 | 평가 시점 | 사용 가능 필드 |
|---|---|---|
task | fork/clone 시 (자식에 적용) | uid, gid, pid, loginuid, sessionid |
exit | 시스템 콜 종료 시 (가장 많이 사용) | 모든 필드 (syscall NR, 반환값, 경로, uid 등) |
user | 사용자 공간 메시지 도착 시 | uid, pid, loginuid, msgtype |
exclude | 레코드 전송 직전 | msgtype (특정 메시지 타입 제외) |
filesystem | 파일시스템(Filesystem) 감시 규칙 | fstype |
/* kernel/auditfilter.c — 필터 규칙 구조체 */
struct audit_krule {
u32 pflags; /* 규칙 플래그 */
u32 flags; /* AUDIT_FILTER_{TASK,EXIT,...} */
u32 listnr; /* 필터 리스트 번호 */
u32 action; /* AUDIT_ALWAYS 또는 AUDIT_NEVER */
u32 mask[AUDIT_BITMASK_SIZE]; /* syscall 비트마스크 */
u32 buflen;
u32 field_count; /* 조건 필드 수 */
struct audit_field *fields; /* 필드 조건 배열 */
struct audit_watch *watch; /* 파일 감시 (-w 규칙) */
struct audit_tree *tree; /* 디렉토리 트리 감시 */
struct audit_fsnotify_mark *exe; /* 실행 파일 감시 */
char *filterkey; /* -k 키 문자열 */
struct list_head list; /* 리스트 연결 */
struct list_head rlist; /* 규칙 인덱스 */
};
struct audit_field {
u32 type; /* AUDIT_PID, AUDIT_UID, AUDIT_ARCH, ... */
u32 val; /* 비교 값 */
u32 op; /* AUDIT_EQUAL, AUDIT_NOT_EQUAL, ... */
union {
kuid_t uid;
kgid_t gid;
struct {
char *lsm_str;
void *lsm_rule; /* LSM 규칙 (SELinux 컨텍스트 등) */
};
};
};
감사 규칙 유형
제어 규칙 (Control Rules)
감사 서브시스템 자체의 동작을 제어합니다.
# 감사 활성화/비활성화
auditctl -e 0 # 비활성화
auditctl -e 1 # 활성화
auditctl -e 2 # 잠금 (재부팅 전까지 규칙 변경 불가)
# 백로그 제한 (기본 64, 프로덕션에서 증가 필요)
auditctl -b 8192 # 백로그 버퍼 크기
# 실패 모드 (백로그 초과 시 동작)
auditctl -f 0 # silent — 초과분 버림
auditctl -f 1 # printk — 경고 메시지 출력 (기본값)
auditctl -f 2 # panic — 커널 패닉 (고보안 환경)
# 초당 최대 메시지 수 제한
auditctl -r 100 # 초당 100개 (0 = 무제한)
# 모든 규칙 삭제
auditctl -D
# 현재 상태 확인
auditctl -s
# enabled 1
# failure 1
# pid 1234 (auditd PID)
# backlog_limit 8192
# lost 0 (유실된 메시지 수)
# backlog 0 (현재 큐 대기 수)
프로덕션 환경에서는 규칙 설정 완료 후 -e 2로 잠금하여 공격자가 감사 규칙을 비활성화하지 못하도록 방지합니다. 잠금은 재부팅으로만 해제됩니다. 규칙 파일의 마지막 줄에 -e 2를 배치하세요.
파일시스템 감시 규칙 (Watch Rules)
# -w (감시 대상) -p (권한 필터) -k (검색 키)
# 권한: r=읽기, w=쓰기, x=실행, a=속성변경
# 인증 관련 파일 감시
auditctl -w /etc/passwd -p wa -k auth_files
auditctl -w /etc/shadow -p wa -k auth_files
auditctl -w /etc/group -p wa -k auth_files
auditctl -w /etc/gshadow -p wa -k auth_files
auditctl -w /etc/sudoers -p wa -k auth_files
auditctl -w /etc/sudoers.d/ -p wa -k auth_files
# PAM 설정 감시
auditctl -w /etc/pam.d/ -p wa -k pam_config
# SSH 설정 감시
auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config
auditctl -w /root/.ssh/ -p wa -k root_ssh
# 시간 변경 감시 (규정 준수 필수)
auditctl -w /etc/localtime -p wa -k time_change
# 커널 모듈 관련
auditctl -w /sbin/insmod -p x -k module_load
auditctl -w /sbin/modprobe -p x -k module_load
auditctl -w /etc/modprobe.d/ -p wa -k module_config
# cron 설정 감시
auditctl -w /etc/cron.d/ -p wa -k cron_config
auditctl -w /etc/crontab -p wa -k cron_config
auditctl -w /var/spool/cron/ -p wa -k cron_config
-w 규칙은 내부적으로 audit_watch 구조체로 변환되어 fsnotify 프레임워크와 연동됩니다. 감시 대상 inode에 대한 FS_MODIFY, FS_ATTRIB 등의 이벤트를 수신하여 감사 레코드를 생성합니다. 디렉토리 감시(-w /etc/sudoers.d/)는 audit_tree를 사용하여 하위 파일까지 재귀적으로 추적합니다.
시스템 콜 규칙 (Syscall Rules)
# 형식: -a action,filter -F field=value -S syscall -k key
# action: always (기록) / never (무시)
# filter: task, exit, user, exclude
# 프로세스 실행 추적 (모든 execve)
auditctl -a always,exit -F arch=b64 -S execve -k exec_log
# 접근 거부 감사 (EACCES, EPERM)
auditctl -a always,exit -F arch=b64 -S open -S openat -S openat2 \
-F exit=-EACCES -k access_denied
auditctl -a always,exit -F arch=b64 -S open -S openat -S openat2 \
-F exit=-EPERM -k access_denied
# 파일 삭제 추적
auditctl -a always,exit -F arch=b64 -S unlink -S unlinkat -S rename \
-S renameat -k file_delete
# 시간 변경 시스템 콜 감사
auditctl -a always,exit -F arch=b64 -S adjtimex -S settimeofday \
-S clock_settime -k time_change
# 네트워크 연결 감사 (connect만)
auditctl -a always,exit -F arch=b64 -S connect -F a2!=110 -k network_connect
# 특정 UID 범위 감사 (서비스 계정 제외)
auditctl -a always,exit -F arch=b64 -S execve -F auid>=1000 \
-F auid!=4294967295 -k user_exec
# 커널 모듈 로드/언로드
auditctl -a always,exit -F arch=b64 -S init_module -S finit_module \
-S delete_module -k kernel_modules
# mount/umount 감사
auditctl -a always,exit -F arch=b64 -S mount -S umount2 -k mount_ops
# ptrace 감사 (디버거 연결 탐지)
auditctl -a always,exit -F arch=b64 -S ptrace -k ptrace_attach
# 네트워크 설정 변경 (sethostname, setdomainname)
auditctl -a always,exit -F arch=b64 -S sethostname -S setdomainname -k hostname
# 32비트 시스템 콜도 함께 감사 (호환성 계층)
auditctl -a always,exit -F arch=b32 -S execve -k exec_log_32bit
제외 규칙 (Exclude Rules)
# 노이즈가 많은 메시지 타입 제외
auditctl -a always,exclude -F msgtype=CWD # CWD 레코드 제외
auditctl -a always,exclude -F msgtype=EOE # 이벤트 종료 마커 제외
auditctl -a always,exclude -F msgtype=CRYPTO_KEY_USER # SSH 키 이벤트 제외
# 특정 프로그램의 감사 제외 (성능 최적화)
auditctl -a never,exit -F arch=b64 -S all -F exe=/usr/sbin/chronyd
auditctl -a never,exit -F arch=b64 -S all -F exe=/usr/bin/vmtoolsd
감사 도구
auditctl — 규칙 관리
# 현재 규칙 목록
auditctl -l
# 현재 상태
auditctl -s
# 규칙 삭제 (개별)
auditctl -d always,exit -F arch=b64 -S execve -k exec_log
# 모든 규칙 삭제
auditctl -D
# 규칙 파일에서 로드
auditctl -R /etc/audit/rules.d/custom.rules
ausearch — 로그 검색
# 키로 검색
ausearch -k passwd_changes --start today
# 메시지 타입으로 검색
ausearch -m SYSCALL -sc execve --start recent
ausearch -m USER_AUTH -sv no # 인증 실패만
# auid (원래 로그인 사용자)로 검색
ausearch -ua 1000 --start today
# 특정 PID로 검색
ausearch -p 4523
# 시간 범위 검색
ausearch --start 01/15/2024 12:00:00 --end 01/15/2024 18:00:00
# 실행 파일로 검색
ausearch -x /usr/bin/passwd
# 파일 이름으로 검색
ausearch -f /etc/shadow
# 해석된 형식 출력 (-i: UID→이름, syscall→이름 변환)
ausearch -k exec_log -i --start today
# 이벤트 단위 구분자와 함께 출력
ausearch -k exec_log --format text
# CSV 형식 출력 (외부 도구 연동)
ausearch -k exec_log --format csv
# 특정 이벤트 ID로 검색
ausearch -a 789 # serial 789인 모든 레코드
# 여러 조건 AND 결합
ausearch -m SYSCALL -sc openat -k sensitive_files -sv no --start today
aureport — 보고서 생성
# 종합 요약 보고서
aureport --summary
# 인증 이벤트 보고서
aureport --auth --start this-week
# 파일 접근 보고서
aureport --file --summary
# 시스템 콜 통계
aureport --syscall --summary
# 이상 이벤트
aureport --anomaly
# 실패한 이벤트만
aureport --failed
# 실행 보고서
aureport -x --summary
# 키별 이벤트 수
aureport -k --summary
# 로그인 보고서
aureport --login --summary
# 사용자별 이벤트 수
aureport --user --summary
# 터미널별 이벤트
aureport --tty
autrace — 프로세스 추적
# autrace: strace와 유사하지만 audit 프레임워크 사용
# 모든 감사 규칙을 일시 삭제 후 대상 프로세스만 추적
autrace /bin/ls /tmp
# 추적 결과 분석
ausearch --start recent -p 12345 --raw | aureport --file --summary
ausearch --start recent -p 12345 --raw | aureport --syscall
auditd 데몬 설정
# /etc/audit/auditd.conf — 핵심 설정 항목
# 로그 파일 위치
log_file = /var/log/audit/audit.log
# 로그 형식 (RAW: 원시 형식, ENRICHED: UID→이름 등 해석 포함)
log_format = ENRICHED
# 로그 그룹 (adm 그룹에 읽기 권한 부여)
log_group = adm
# 로그 파일당 최대 크기 (MB)
max_log_file = 50
# 최대 로그 파일 수 (순환)
num_logs = 10
# 최대 크기 도달 시 동작
max_log_file_action = ROTATE # ROTATE, SYSLOG, SUSPEND, IGNORE, KEEP_LOGS
# 디스크 공간 부족 시 동작
space_left = 75 # 잔여 공간 경고 임계값 (MB)
space_left_action = SYSLOG # SYSLOG, EMAIL, EXEC, SUSPEND, SINGLE, HALT
admin_space_left = 50 # 관리자 경고 임계값 (MB)
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND # 디스크 꽉 찬 경우
disk_error_action = SUSPEND # 디스크 오류 시
# 네트워크 전달 (원격 감사 서버)
# name_format = HOSTNAME
# name = myserver.example.com
# 디스패처 (audisp 플러그인)
dispatcher = /sbin/audispd
# 플러시 방식
flush = INCREMENTAL_ASYNC # 성능과 안정성 균형
freq = 50 # 50개 레코드마다 플러시
# TCP 리스너 (원격 수집 서버로 사용 시)
# tcp_listen_port = 60
# tcp_max_per_addr = 1
영구 규칙 설정
auditctl로 설정한 규칙은 재부팅 시 사라집니다. 영구 규칙은 /etc/audit/rules.d/ 디렉토리에 .rules 파일로 저장합니다.
# /etc/audit/rules.d/audit.rules — 영구 규칙 파일 구조
# === 1단계: 기존 규칙 초기화 ===
-D
-b 8192
-f 1
--backlog_wait_time 60000
# === 2단계: 파일 감시 규칙 ===
-w /etc/passwd -p wa -k auth_files
-w /etc/shadow -p wa -k auth_files
-w /etc/group -p wa -k auth_files
-w /etc/sudoers -p wa -k auth_files
-w /etc/sudoers.d/ -p wa -k auth_files
-w /etc/ssh/sshd_config -p wa -k sshd_config
# === 3단계: 시스템 콜 규칙 ===
-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k user_exec
-a always,exit -F arch=b32 -S execve -F auid>=1000 -F auid!=4294967295 -k user_exec
-a always,exit -F arch=b64 -S init_module -S finit_module -S delete_module -k kernel_modules
-a always,exit -F arch=b64 -S mount -S umount2 -k mount_ops
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -S clock_settime -k time_change
# === 4단계: 고성능 제외 규칙 ===
-a never,exit -F arch=b64 -S all -F exe=/usr/sbin/chronyd
-a always,exclude -F msgtype=CWD
# === 마지막: 규칙 잠금 (프로덕션 필수) ===
-e 2
# 규칙 적용: augenrules --load 또는 service auditd restart
augenrules은 /etc/audit/rules.d/의 모든 .rules 파일을 알파벳 순으로 병합하여 /etc/audit/audit.rules를 생성합니다. 규칙 파일에 번호 접두사를 사용하면 순서를 제어할 수 있습니다: 10-base.rules, 20-watch.rules, 30-syscall.rules, 99-finalize.rules.
시스템 콜 감사 예제
# 특정 사용자(UID 1000)의 모든 파일 삭제 감사
auditctl -a always,exit -F arch=b64 -S unlinkat -F uid=1000 -k user_deletes
# 감사 로그 확인
ausearch -k user_deletes
# ----
# type=SYSCALL msg=audit(1706000000.123:456): arch=c000003e
# syscall=263 success=yes exit=0 a0=ffffff9c a1=55a8b...
# uid=1000 gid=1000 comm="rm" exe="/usr/bin/rm"
# type=PATH msg=audit(1706000000.123:456): item=1
# name="secret.txt" inode=12345 nametype=DELETE
로그 분석 기법
# 1. 의심스러운 실행 파일 탐지
ausearch -m EXECVE --start today -i | \
aureport -x --summary | sort -rn -k1 | head -20
# 2. 실패한 파일 접근 상위 사용자
ausearch -sv no -m SYSCALL --start this-week | \
aureport --user --summary | sort -rn -k1
# 3. 시간대별 이벤트 분포 (DDoS/brute-force 탐지)
aureport --start today --summary
# 4. 특정 파일에 접근한 모든 프로세스 추적
ausearch -f /etc/shadow -i --start this-month
# 5. 권한 상승 이벤트 추적 (setuid/setgid 호출)
ausearch -m SYSCALL -sc setuid --start today -i
ausearch -m SYSCALL -sc setgid --start today -i
# 6. 특정 사용자의 전체 세션 활동 재구성
ausearch --session 42 -i | aureport --file
ausearch --session 42 -i | aureport --syscall
ausearch --session 42 -i | aureport --host
# 7. PROCTITLE 디코딩 (hex → 텍스트)
ausearch -k exec_log --start today --raw | \
awk '/proctitle=/{gsub(/proctitle=/,""); cmd=$NF; gsub(/../," 0x&",cmd); print cmd}' | \
xargs printf '%b\n'
audisp 플러그인
audisp(Audit Dispatcher)은 감사 이벤트를 외부 시스템으로 전달하는 플러그인 프레임워크입니다. /etc/audit/plugins.d/에 플러그인 설정 파일을 배치합니다.
# /etc/audit/plugins.d/syslog.conf — syslog 전달 플러그인
active = yes
direction = out
path = /sbin/audisp-syslog
type = always
args = LOG_INFO
format = string
# /etc/audit/plugins.d/af_unix.conf — 유닉스 소켓 전달
active = yes
direction = out
path = builtin_af_unix
type = always
args = 0640 /var/run/audispd_events
format = string
| 플러그인 | 용도 | 설정 파일 |
|---|---|---|
audisp-syslog | syslog/rsyslog로 감사 이벤트 전달 | syslog.conf |
audisp-remote | 원격 감사 서버로 TCP 전달 | au-remote.conf |
sedispatch | SELinux setroubleshoot 연동 | sedispatch.conf |
audisp-af_unix | 유닉스 소켓으로 이벤트 전달 | af_unix.conf |
audisp-ids | 침입 탐지 시스템 연동 | ids.conf |
성능 최적화
Audit 서브시스템은 시스템 콜 경로에 후크를 삽입하므로 성능 오버헤드(Overhead)가 발생합니다. 규칙 수가 많을수록, 매칭 빈도가 높을수록 오버헤드가 증가합니다. 일반적으로 1~5% 수준이지만, -S all 규칙이나 과도한 파일 감시 시 더 커질 수 있습니다.
| 최적화 기법 | 설명 |
|---|---|
| 규칙 순서 최적화 | never(제외) 규칙을 always 규칙보다 앞에 배치. 고빈도 제외 대상을 먼저 매칭하여 불필요한 평가 방지 |
| 노이즈 프로세스 제외 | -a never,exit -F exe=/path/to/noisy로 감사 불필요한 데몬 제외 |
| auid 필터 활용 | -F auid>=1000 -F auid!=4294967295로 데몬 프로세스 자동 제외 |
| 백로그 크기 조정 | -b 8192 이상으로 설정. 백로그 초과 시 이벤트 유실 발생 |
backlog_wait_time | 백로그 가득 찬 경우 태스크 대기 시간(ms). 0이면 대기 없이 유실 |
| 로그 플러시(Flush) 방식 | flush = INCREMENTAL_ASYNC로 비동기 플러시 (성능↑, 약간의 유실 위험) |
| ENRICHED 비활성화 | log_format = RAW로 auditd CPU 부하 절감 (UID→이름 해석 생략) |
| exclude 규칙 | -a always,exclude -F msgtype=CWD로 불필요 레코드 타입 제외 |
/* kernel/auditsc.c — 규칙 매칭 오버헤드 최소화를 위한 최적화 */
/* syscall 비트마스크로 해당 syscall에 규칙이 있는지 O(1) 확인 */
static inline int audit_n_rules; /* 전체 규칙 수 — 0이면 감사 완전 스킵 */
/* 감사 비활성화 시 빠른 경로 */
static inline void audit_syscall_entry(int major, ...)
{
/* audit_n_rules == 0 이면 즉시 반환 (오버헤드 거의 0) */
if (unlikely(audit_n_rules))
__audit_syscall_entry(major, ...);
}
perf stat -e cycles:u -e cycles:k -- dd if=/dev/zero of=/dev/null bs=1 count=1000000로 감사 활성/비활성 시 커널 사이클을 비교할 수 있습니다. audit=0 부트 파라미터로 완전 비활성화한 기준선과, auditctl -e 1 상태에서의 차이가 순수 감사 오버헤드입니다. perf record -g로 플레임그래프를 생성하면 __audit_syscall_exit과 audit_filter_rules가 주요 핫스팟으로 나타납니다.
보안 컴플라이언스 규칙 세트
주요 보안 표준에서 요구하는 감사 규칙 예시:
| 표준 | 요구사항 | 대응 규칙 |
|---|---|---|
| PCI-DSS 10.2.1 | 관리자 활동 감사 | -a always,exit -F arch=b64 -S execve -F uid=0 -k admin_cmd |
| PCI-DSS 10.2.2 | root 활동 감사 | -w /etc/sudoers -p wa -k sudo_changes |
| PCI-DSS 10.2.4 | 접근 실패 기록 | -a always,exit -S openat -F exit=-EACCES -k access_fail |
| PCI-DSS 10.2.6 | 감사 로그 초기화/삭제 | -w /var/log/audit/ -p wa -k audit_log_tamper |
| PCI-DSS 10.2.7 | 객체 생성/삭제 | -a always,exit -S unlink -S rmdir -k object_delete |
| CIS 4.1.4 | 시간 변경 | -a always,exit -S adjtimex -S clock_settime -k time-change |
| CIS 4.1.6 | MAC 정책 변경 | -w /etc/selinux/ -p wa -k MAC-policy |
| CIS 4.1.8 | 로그인/로그아웃 | -w /var/log/lastlog -p wa -k logins |
| CIS 4.1.9 | 세션 정보 | -w /var/run/utmp -p wa -k session |
| HIPAA §164.312(b) | ePHI 접근 감사 | -a always,exit -F arch=b64 -S openat -F dir=/var/lib/medical -k ephi_access |
| HIPAA §164.312(c) | 무결성(Integrity) 보호 | -w /var/lib/medical/ -p wa -k ephi_integrity |
| HIPAA §164.312(d) | 사용자 인증 | -w /var/log/faillog -p wa -k auth_fail |
| SOX Section 302 | 재무 데이터 접근 | -a always,exit -S openat -F dir=/opt/finance -F perm=rw -k sox_finance |
| SOX Section 404 | IT 통제 변경 | -w /etc/ -p wa -k sox_config_change |
| NIST 800-53 AU-2 | 감사 가능 이벤트 | -a always,exit -F arch=b64 -S execve -k nist_exec |
| NIST 800-53 AU-3 | 감사 내용 (who/what/when/where) | -a always,exit -F arch=b64 -S all -F auid>=1000 -F auid!=4294967295 -k nist_all |
| NIST 800-53 AU-6 | 감사 검토/분석 | (도구: aureport --summary, 정책적 요구사항) |
| NIST 800-53 AU-9 | 감사 보호 (변조 방지) | -w /var/log/audit/ -p wa -k nist_audit_protect |
| NIST 800-53 AU-12 | 감사 생성 | auditctl -e 2 (감사 비활성화 금지, immutable 모드) |
| ISO 27001 A.12.4.1 | 이벤트 로깅 | -a always,exit -F arch=b64 -S connect -k iso_network |
| ISO 27001 A.12.4.2 | 로그 보호 | -w /etc/audit/ -p wa -k iso_audit_config |
| ISO 27001 A.12.4.3 | 관리자 로그 | -a always,exit -S execve -F euid=0 -k iso_admin |
| STIG V-72085 | 특권 명령 감사 | -a always,exit -F path=/usr/bin/sudo -F perm=x -k stig_priv |
| STIG V-72095 | chown 감사 | -a always,exit -F arch=b64 -S chown,fchown,lchown -k stig_chown |
audit 패키지에는 CIS, PCI-DSS, STIG 등에 맞춘 사전 규칙 세트가 포함되어 있습니다. /usr/share/audit/sample-rules/ 디렉토리에서 30-pci-dss-v31.rules, 30-stig.rules, 30-nispom.rules 등을 참조하세요. augenrules로 필요한 규칙 파일을 /etc/audit/rules.d/에 복사하여 활성화합니다.
컴플라이언스 규칙 적용 전략: 하나의 시스템에 여러 컴플라이언스 표준을 동시에 충족해야 하는 경우, 규칙이 중복될 수 있습니다. 중복 규칙은 성능 저하를 유발하므로, auditctl -l | sort로 정렬 후 중복을 제거하고, 각 규칙에 -k 키를 표준별로 부여하여 ausearch -k nist_exec 등으로 표준별 필터링이 가능하도록 설계하세요. NIST 800-53 AU-2는 가장 포괄적이므로 이를 기준으로 다른 표준의 세부 요구사항을 추가하는 방식이 효율적입니다.
LSM 연동
Audit 서브시스템은 SELinux, AppArmor 등 LSM과 긴밀하게 연동됩니다. LSM이 접근을 거부하면 자동으로 감사 레코드가 생성됩니다.
# SELinux AVC 거부 → 자동 감사 레코드 생성
type=AVC msg=audit(1706000000.456:321): avc: denied { read } for
pid=3456 comm="httpd" name="index.html" dev="sda1" ino=67890
scontext=system_u:system_r:httpd_t:s0
tcontext=system_u:object_r:user_home_t:s0
tclass=file permissive=0
# AppArmor DENIED → 자동 감사 레코드 생성
type=AVC msg=audit(1706000000.789:654):
apparmor="DENIED" operation="open"
profile="/usr/sbin/nginx" name="/etc/shadow"
pid=5678 comm="nginx" requested_mask="r" denied_mask="r"
fsuid=33 ouid=0
# SELinux 컨텍스트 기반 감사 규칙
# 특정 SELinux 타입이 접근하는 이벤트만 감사
auditctl -a always,exit -F arch=b64 -S openat \
-F subj_type=httpd_t -k httpd_access
/* security/selinux/avc.c — SELinux AVC에서 감사 호출 */
static void avc_audit_post_callback(
struct audit_buffer *ab,
void *a)
{
struct common_audit_data *ad = a;
audit_log_format(ab, " ");
audit_log_untrustedstring(ab, ad->selinux_audit_data->scontext);
audit_log_format(ab, " tcontext=");
audit_log_untrustedstring(ab, ad->selinux_audit_data->tcontext);
audit_log_format(ab, " tclass=%s",
secclass_map[ad->selinux_audit_data->tclass - 1].name);
}
/* 감사 결정: AVC denied 또는 auditallow 규칙 매칭 시 로그 */
static inline int avc_audit_required(
u32 requested, struct av_decision *avd,
int result, u32 auditdeny, u32 *deniedp)
{
u32 denied = requested & ~avd->allowed;
/* 거부된 경우: auditdeny 마스크와 교차 확인 */
if (denied && (denied & auditdeny))
return 1; /* 감사 필요 */
/* 허용된 경우: auditallow 마스크 확인 */
if (!denied && (requested & avd->auditallow))
return 1; /* auditallow로 허용 이벤트도 감사 */
return 0; /* 감사 불필요 */
}
NETLINK_AUDIT 프로토콜 상세
Audit 서브시스템의 커널-유저 공간 통신은 전적으로 NETLINK_AUDIT 프로토콜 패밀리를 통해 이루어집니다. 이 넷링크 소켓은 양방향 통신을 지원하며, auditd가 커널에 규칙을 설정하고 이벤트를 수신하는 유일한 채널입니다.
메시지 타입 분류
NETLINK_AUDIT은 1000번대 메시지 타입을 사용하며, 크게 제어 메시지(1000~1099), 이벤트 메시지(1100~1399), 사용자 메시지(1400~1499)로 분류됩니다.
| 메시지 타입 | 번호 | 방향 | 설명 |
|---|---|---|---|
AUDIT_GET | 1000 | 유저 → 커널 | 현재 감사 상태 조회 (enabled, pid, backlog 등) |
AUDIT_SET | 1001 | 유저 → 커널 | 감사 상태 설정 (enabled, pid, backlog_limit, failure 등) |
AUDIT_LIST_RULES | 1013 | 유저 → 커널 | 현재 등록된 모든 규칙 조회 |
AUDIT_ADD_RULE | 1011 | 유저 → 커널 | 감사 규칙 추가 |
AUDIT_DEL_RULE | 1012 | 유저 → 커널 | 감사 규칙 삭제 |
AUDIT_USER | 1005 | 유저 → 커널 | 사용자 공간 메시지 로깅 (PAM 등) |
AUDIT_SIGNAL_INFO | 1010 | 유저 → 커널 | 시그널(Signal) 발신자 정보 조회 |
AUDIT_TRIM | 1014 | 유저 → 커널 | 감시 트리에서 유효하지 않은 항목 정리 |
AUDIT_MAKE_EQUIV | 1015 | 유저 → 커널 | 디렉토리 감시 경로 동등성 설정 |
AUDIT_SET_FEATURE | 1018 | 유저 → 커널 | 감사 기능 플래그 설정 (loginuid_immutable 등) |
AUDIT_GET_FEATURE | 1019 | 유저 → 커널 | 감사 기능 플래그 조회 |
AUDIT_SYSCALL | 1300 | 커널 → 유저 | 시스템 콜 감사 이벤트 |
AUDIT_PATH | 1302 | 커널 → 유저 | 파일 경로 정보 레코드 |
AUDIT_IPC | 1303 | 커널 → 유저 | IPC 객체 정보 레코드 |
AUDIT_SOCKADDR | 1306 | 커널 → 유저 | 소켓 주소 정보 레코드 |
AUDIT_CWD | 1307 | 커널 → 유저 | 현재 작업 디렉토리 레코드 |
AUDIT_EXECVE | 1309 | 커널 → 유저 | execve 인자 레코드 |
AUDIT_PROCTITLE | 1327 | 커널 → 유저 | 프로세스 타이틀 레코드 |
AUDIT_EOE | 1320 | 커널 → 유저 | 이벤트 종료 표시자 (End of Event) |
audit_status 구조체
/* include/uapi/linux/audit.h — 감사 상태 구조체 */
struct audit_status {
__u32 mask; /* 어떤 필드가 유효한지 나타내는 비트마스크 */
__u32 enabled; /* 0=비활성, 1=활성, 2=immutable(잠금) */
__u32 failure; /* 실패 모드: 0=silent, 1=printk, 2=panic */
__u32 pid; /* auditd의 PID (등록/해제) */
__u32 rate_limit; /* 초당 최대 메시지 수 (0=무제한) */
__u32 backlog_limit; /* 백로그 큐 최대 크기 */
__u32 lost; /* 유실된 메시지 수 (읽기 전용) */
__u32 backlog; /* 현재 백로그 큐 크기 (읽기 전용) */
union {
__u32 version; /* audit API 버전 */
__u32 feature_bitmap; /* 지원 기능 비트맵 */
};
__u32 backlog_wait_time; /* 백로그 대기 시간(ms) */
__u32 backlog_wait_time_actual; /* 실제 대기 시간(읽기 전용) */
};
auditd 등록 과정
auditd가 시작되면 다음 순서로 커널에 등록합니다:
socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT)로 넷링크 소켓 생성bind()로 멀티캐스트 그룹AUDIT_NLGRP_READLOG에 참여AUDIT_SET메시지로 자신의 PID를 커널에 등록 (audit_status.pid = getpid())AUDIT_SET로enabled=1,backlog_limit,failure등 설정AUDIT_LIST_RULES로 기존 규칙 확인 후 필요한 규칙 추가
/* kernel/audit.c — audit_receive_msg() 핵심 메시지 처리 분기 */
static int audit_receive_msg(struct sk_buff *skb,
struct nlmsghdr *nlh)
{
u32 seq = nlh->nlmsg_seq;
int err = 0;
switch (nlh->nlmsg_type) {
case AUDIT_GET:
/* 현재 감사 상태를 audit_status로 응답 */
audit_send_reply(skb, seq, AUDIT_GET, 0, 0,
&s, sizeof(s));
break;
case AUDIT_SET:
/* 권한 확인: CAP_AUDIT_CONTROL 필요 */
if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
return -EPERM;
/* enabled 설정 — 2(immutable)면 재부팅까지 변경 불가 */
if (s.mask & AUDIT_STATUS_ENABLED) {
err = audit_set_enabled(s.enabled);
if (err < 0)
return err;
}
/* auditd PID 등록 — kauditd가 이 PID로 유니캐스트 전송 */
if (s.mask & AUDIT_STATUS_PID)
audit_set_pid(s.pid, NETLINK_CB(skb).portid);
/* 백로그 한도 설정 */
if (s.mask & AUDIT_STATUS_BACKLOG_LIMIT)
err = audit_set_backlog_limit(s.backlog_limit);
break;
case AUDIT_ADD_RULE:
case AUDIT_DEL_RULE:
/* 규칙 추가/삭제 — audit_rule_data 파싱 후 필터 리스트에 삽입 */
if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
return -EPERM;
err = audit_rule_change(nlh->nlmsg_type, portid, seq,
data, nlh->nlmsg_len);
break;
case AUDIT_USER:
case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
/* 사용자 공간 메시지 — PAM, login 등에서 보낸 감사 이벤트 */
if (!netlink_capable(skb, CAP_AUDIT_WRITE))
return -EPERM;
audit_log_user_recv_msg(&ab, nlh->nlmsg_type);
break;
case AUDIT_SIGNAL_INFO:
/* 마지막 시그널 발신자 정보 응답 */
err = audit_signal_info(skb, seq);
break;
}
return err;
}
멀티캐스트 그룹: 커널 3.16+에서 AUDIT_NLGRP_READLOG 멀티캐스트 그룹이 추가되었습니다. auditd 외에도 다른 프로세스가 이 그룹에 참여하여 감사 이벤트를 수신할 수 있습니다. 이를 통해 실시간(Real-time) 모니터링 도구(예: go-audit, laurel)가 auditd와 병렬로 이벤트를 소비할 수 있습니다. setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &AUDIT_NLGRP_READLOG, sizeof(int))로 참여합니다.
백로그 메커니즘 상세
Audit 백로그는 커널에서 생성된 감사 메시지가 kauditd를 통해 auditd로 전달되기 전에 대기하는 커널 내부 큐입니다. 이 큐의 크기와 동작 방식은 시스템 안정성과 감사 데이터 무결성 사이의 균형을 결정합니다.
핵심 파라미터
| 파라미터 | 기본값 | 설정 방법 | 설명 |
|---|---|---|---|
backlog_limit | 64 | auditctl -b N | 백로그 큐 최대 크기. 0=무제한 |
backlog_wait_time | 60000ms | auditctl --backlog_wait_time N | 큐 가득 시 태스크 최대 대기 시간 |
failure | 1 (printk) | auditctl -f N | 실패 모드: 0=silent, 1=printk, 2=panic |
rate_limit | 0 | auditctl -r N | 초당 최대 메시지 수 (0=무제한) |
실패 모드 상세
| 모드 | 값 | 동작 | 적용 환경 |
|---|---|---|---|
AUDIT_FAIL_SILENT | 0 | 메시지 자동 폐기, lost 카운터 증가, 태스크 차단 없음 | 가용성 우선 시스템 (웹 서버 등) |
AUDIT_FAIL_PRINTK | 1 | 커널 로그에 경고 출력 후 폐기, lost 카운터 증가 | 일반적인 기본 설정 |
AUDIT_FAIL_PANIC | 2 | 커널 패닉(Kernel Panic) 발생 — 감사 이벤트 유실 방지 최우선 | CAPP/LSPP 인증 환경, 군사/금융 |
/* kernel/audit.c — audit_log_start() 백로그 대기 로직 */
struct audit_buffer *audit_log_start(
struct audit_context *ctx,
gfp_t gfp_mask, int type)
{
struct audit_buffer *ab;
unsigned long timeout_start = jiffies;
/* 감사 비활성화 시 즉시 반환 */
if (audit_initialized != AUDIT_INITIALIZED)
return NULL;
if (unlikely(!audit_filter_type(type)))
return NULL;
/* 속도 제한 확인 */
if (audit_rate_limit &&
audit_rate_check())
return NULL;
/* 백로그 한도 초과 시 대기 */
while (audit_backlog_limit &&
skb_queue_len(&audit_queue) > audit_backlog_limit) {
/* backlog_wait_time 동안 대기 (디폴트 60초) */
if (audit_backlog_wait_time) {
unsigned long sleep_time;
sleep_time = timeout_start +
audit_backlog_wait_time - jiffies;
if (((long)sleep_time) <= 0) {
/* 타임아웃: 실패 모드에 따라 처리 */
if (audit_rate_check())
audit_log_lost("backlog limit exceeded");
return NULL;
}
/* 대기 — kauditd가 큐를 비울 때까지 */
wait_event_interruptible_timeout(
audit_backlog_wait,
skb_queue_len(&audit_queue)
< audit_backlog_limit,
sleep_time);
}
}
ab = audit_buffer_alloc(ctx, gfp_mask, type);
return ab;
}
/* kernel/audit.c — 감사 메시지 유실 처리 */
static void audit_log_lost(const char *message)
{
static unsigned long last_msg = 0;
static int rate_limit = 5;
atomic_inc(&audit_lost);
switch (audit_failure) {
case AUDIT_FAIL_SILENT:
break; /* 조용히 카운터만 증가 */
case AUDIT_FAIL_PRINTK:
if (printk_ratelimit())
pr_warn("audit: %s (lost=%d)",
message, atomic_read(&audit_lost));
break;
case AUDIT_FAIL_PANIC:
panic("audit: %s", message);
break;
}
}
일반 서버 환경에서는 -b 8192 이상, 고부하 환경에서는 -b 65536을 권장합니다. backlog_wait_time=15000(15초)으로 설정하면 대기 시간이 지나치게 길어지는 것을 방지하면서도 burst 트래픽을 흡수할 수 있습니다. auditctl -s로 현재 lost 카운터를 모니터링하고, Prometheus/Grafana에서 node_audit_backlog 메트릭을 추적하세요. CAPP 인증 환경에서는 반드시 -f 2(panic)를 설정해야 합니다.
파일 감시 내부 구현
Audit 파일 감시(-w 규칙)는 fsnotify 프레임워크 위에 구축된 커널 내부 메커니즘입니다. audit_watch는 개별 파일을, audit_tree는 디렉토리 트리를 재귀적으로 감시합니다.
audit_watch 구조체
/* kernel/audit_watch.c — 파일 감시 구조체 */
struct audit_watch {
struct list_head wlist; /* 부모 audit_parent의 감시 목록 */
struct list_head rules; /* 이 감시에 연결된 감사 규칙 목록 */
struct audit_parent *parent; /* 부모 디렉토리의 fsnotify 마크 */
char *path; /* 감시 대상 파일명 (디렉토리 기준 상대경로) */
dev_t dev; /* 디바이스 번호 */
unsigned long ino; /* inode 번호 (파일 식별) */
refcount_t count; /* 참조 카운트 */
};
/* 부모 디렉토리 감시 — fsnotify mark를 보유 */
struct audit_parent {
struct list_head watches; /* 이 디렉토리의 감시 목록 */
struct fsnotify_mark mark; /* fsnotify 프레임워크 마크 */
};
/* audit_tree.c — 디렉토리 트리 감시 */
struct audit_tree {
struct list_head list; /* 전역 트리 목록 */
struct list_head rules; /* 연결된 감사 규칙 */
int goner; /* 삭제 예정 플래그 */
refcount_t count; /* 참조 카운트 */
char pathname[]; /* 감시 경로 (가변 길이) */
};
-p 권한 플래그와 fsnotify 이벤트 매핑(Mapping)
| 감사 플래그 (-p) | 의미 | fsnotify 이벤트 | 설명 |
|---|---|---|---|
r | 읽기 | FS_ACCESS | 파일 내용 읽기 (read, mmap) |
w | 쓰기 | FS_MODIFY | 파일 내용 변경 (write, truncate) |
x | 실행 | FS_OPEN + 실행 권한 | 파일 실행 (execve) |
a | 속성 변경 | FS_ATTRIB | 권한, 소유자, 타임스탬프 변경 (chmod, chown, utime) |
| (내부) | 삭제 | FS_DELETE | 파일 삭제 시 감시 해제 처리 |
| (내부) | 이동 | FS_MOVED_FROM / FS_MOVED_TO | rename 시 감시 재연결 |
/* kernel/audit_watch.c — 감시 추가 핵심 흐름 */
static int audit_add_watch(struct audit_krule *krule,
struct list_head *list)
{
struct audit_watch *w = krule->watch;
struct audit_parent *parent;
struct path parent_path;
int ret;
/* 1. 부모 디렉토리 경로 조회 */
ret = kern_path(w->path, LOOKUP_PARENT, &parent_path);
/* 2. 부모 디렉토리에 fsnotify mark 설정 (없으면 생성) */
parent = audit_find_parent(d_backing_inode(parent_path.dentry));
if (!parent) {
parent = audit_init_parent(&parent_path);
/* fsnotify_add_inode_mark()로 디렉토리 inode에 마크 설정 */
}
/* 3. 대상 파일의 현재 inode 번호 기록 */
w->ino = d_backing_inode(dentry)->i_ino;
w->dev = d_backing_inode(dentry)->i_sb->s_dev;
/* 4. 감시를 부모의 목록에 연결 */
list_add(&w->wlist, &parent->watches);
return 0;
}
/* rename/replace 시 감시 재연결 */
static void audit_update_watch(
struct audit_parent *parent,
const struct qstr *dname,
dev_t dev, unsigned long ino,
unsigned invalidating)
{
struct audit_watch *owatch, *nwatch;
/* 이름이 일치하는 기존 감시 찾기 */
list_for_each_entry(owatch, &parent->watches, wlist) {
if (strcmp(owatch->path, dname->name))
continue;
/* 새 inode 정보로 감시 갱신 */
nwatch = audit_dupe_watch(owatch);
nwatch->dev = dev;
nwatch->ino = ino;
/* 기존 감시의 규칙들을 새 감시로 이전 */
audit_watch_log_rule_change(owatch, nwatch, "updated_rules");
list_replace(&owatch->wlist, &nwatch->wlist);
audit_put_watch(owatch);
}
}
파일 감시 규칙은 시스콜 기반 규칙과 달리 fsnotify를 통해 동작하므로, 대량의 감시 규칙(1000개+)은 inode lookup 오버헤드를 유발합니다. 특히 /etc/ 전체를 -w /etc/ -p wa로 감시하면 해당 디렉토리의 모든 파일 변경마다 감사 레코드가 생성됩니다. 민감한 파일만 개별 지정하는 것이 성능에 유리합니다.
컨테이너 환경 감사
컨테이너 환경에서 Linux Audit 사용은 근본적인 아키텍처 제한에 직면합니다. 모든 컨테이너가 호스트 커널을 공유하므로, 단일 auditd 데몬이 호스트와 모든 컨테이너의 감사 이벤트를 수집합니다.
주요 제한사항
| 문제 | 원인 | 영향 |
|---|---|---|
| 단일 auditd | NETLINK_AUDIT 소켓은 하나의 PID만 등록 가능 | 컨테이너별 독립 감사 불가 |
| loginuid 문제 | 컨테이너 내부에서 auid=-1 (4294967295) | 사용자 추적 불가능 |
| 규칙 격리(Isolation) 없음 | 호스트와 컨테이너가 동일 규칙 세트 공유 | 컨테이너별 정책 분리 불가 |
| 네임스페이스(Namespace) 미지원 | audit 네임스페이스 커널 패치(Patch) 미병합 (2024년 현재) | 멀티테넌트 감사 제한 |
| 성능 집중 | 모든 컨테이너 이벤트가 단일 auditd로 집중 | 대규모 환경에서 백로그 초과 |
컨테이너 감사 대안 비교
| 도구 | 기반 기술 | 컨테이너 인식 | 실시간 차단 | 커널 변경 필요 | 장점 |
|---|---|---|---|---|---|
| Linux Audit | 커널 후크 | 제한적 (호스트 공유) | 불가 | 불필요 | 컴플라이언스 인증, 안정성 |
| Falco | eBPF/커널 모듈 | 완전 (K8s 네이티브) | 불가 (탐지만) | 불필요 | K8s 통합, YAML 규칙 |
| Sysdig | eBPF | 완전 | 불가 | 불필요 | 풍부한 메타데이터 |
| Tracee | eBPF | 완전 | 불가 | 불필요 | 보안 이벤트 특화 |
| Tetragon | eBPF | 완전 | 가능 | 불필요 | 실시간 정책 적용 |
| KubeArmor | eBPF/AppArmor | 완전 | 가능 | 불필요 | K8s 네이티브 정책 |
# 컨테이너 환경에서 audit 규칙 예제
# containerid 필드로 특정 컨테이너 필터링 (커널 6.x+ 패치 적용 시)
auditctl -a always,exit -F arch=b64 -S execve \
-F containerid=12345 -k container_exec
# 대안: eBPF 기반 Falco 규칙으로 컨테이너 감사
# /etc/falco/falco_rules.yaml
- rule: Shell Spawned in Container
desc: Detect shell execution inside container
condition: >
spawned_process and container and
proc.name in (bash, sh, zsh, dash)
output: >
Shell spawned in container
(user=%user.name container=%container.name
image=%container.image.repository
command=%proc.cmdline)
priority: WARNING
tags: [container, shell]
# Tetragon 정책: 컨테이너 내 민감 파일 접근 차단
# tetragon-policy.yaml
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: audit-sensitive-files
spec:
kprobes:
- call: "security_file_open"
args:
- index: 0
type: "file"
selectors:
- matchArgs:
- index: 0
operator: "Prefix"
values:
- "/etc/shadow"
- "/etc/passwd"
컨테이너 런타임은 PAM 세션을 거치지 않고 프로세스를 생성하므로, 컨테이너 내부 프로세스의 loginuid는 -1(4294967295)로 설정됩니다. 이는 "누가 이 작업을 수행했는지" 추적이 불가능함을 의미합니다. CONFIG_AUDIT_LOGINUID_IMMUTABLE=y를 설정하면 loginuid가 한 번 설정된 후 변경할 수 없어 보안이 강화되지만, 컨테이너에서의 유용성은 여전히 제한됩니다.
io_uring 감사
io_uring은 비동기 I/O 인터페이스로, 시스템 콜을 거치지 않고 커널 작업을 수행할 수 있습니다. 이는 전통적인 시스콜 기반 감사 체계를 우회하는 보안 사각지대를 만듭니다.
감사 우회 문제
전통적인 감사는 audit_syscall_entry()와 audit_syscall_exit() 후크에 의존합니다. io_uring의 SQE(Submission Queue Entry)는 커널 내부에서 직접 처리되므로, 이 후크를 거치지 않습니다. 커널 5.6+에서 audit_context에 uring_op 필드가 추가되었지만, 완전한 감사 커버리지는 아직 진행 중입니다.
/* io_uring/io_uring.c — io_uring 감사 후크 (커널 5.6+) */
/* 주요 uring op 코드 (일부) */
enum io_uring_op {
IORING_OP_NOP = 0,
IORING_OP_READV = 1,
IORING_OP_WRITEV = 2,
IORING_OP_READ_FIXED = 4,
IORING_OP_WRITE_FIXED = 5,
IORING_OP_OPENAT = 18,
IORING_OP_CLOSE = 19,
IORING_OP_RENAMEAT = 35,
IORING_OP_UNLINKAT = 36,
IORING_OP_MKDIRAT = 37,
IORING_OP_SOCKET = 45,
IORING_OP_CONNECT = 16,
/* ... 총 50+ 오퍼레이션 */
};
/* 감사 진입 후크 — 각 io_uring 오퍼레이션 처리 전 호출 */
static inline void audit_uring_entry(u8 op)
{
if (unlikely(audit_enabled))
__audit_uring_entry(op);
}
/* kernel/auditsc.c */
void __audit_uring_entry(u8 op)
{
struct audit_context *ctx = audit_context();
if (!ctx)
return;
/* io_uring 오퍼레이션 코드 기록 */
ctx->uring_op = op;
ctx->in_syscall = 1; /* syscall과 동일하게 처리 */
ctx->current_state = AUDIT_STATE_BUILD;
}
/* 감사 종료 후크 — 오퍼레이션 완료 후 규칙 매칭 및 레코드 생성 */
void __audit_uring_exit(int success, long code)
{
struct audit_context *ctx = audit_context();
if (ctx && ctx->in_syscall) {
/* 필터 매칭 수행 (exit 필터 리스트) */
ctx->return_valid = AUDITSC_SUCCESS;
ctx->return_code = code;
/* 감사 로그 생성 — syscall exit와 동일한 경로 */
audit_filter_syscall(ctx);
audit_log_exit();
}
}
io_uring 감사가 없는 커널에서는 공격자가 io_uring을 통해 파일 접근, 네트워크 연결, 파일 삭제 등을 감사 로그 없이 수행할 수 있습니다. 이는 PCI-DSS, HIPAA 등 컴플라이언스 요구사항 위반입니다. 커널 5.6 이전 버전에서는 io_uring 사용을 io_uring_setup() seccomp 필터로 차단하거나, eBPF 기반 감사(Tracee, Tetragon)를 보조 수단으로 사용하세요. sysctl kernel.io_uring_disabled=2로 io_uring을 완전 비활성화할 수도 있습니다.
원격 감사 로깅
대규모 인프라에서는 각 서버의 감사 로그를 중앙 수집기로 전송하여 통합 관리합니다. audisp-remote 플러그인이 이 역할을 담당하며, TCP/TLS를 통해 안전한 원격 전송을 지원합니다.
원격 전송 프로토콜 비교
| 전송 방식 | 포트 | 암호화(Encryption) | 인증 | 장점 | 단점 |
|---|---|---|---|---|---|
| TCP (평문) | 60 (기본) | 없음 | 없음 | 단순 구성, 최소 오버헤드 | 도청/변조 취약 |
| TLS | 60 (기본) | TLS 1.2/1.3 | X.509 인증서 | 전송 암호화, 상호 인증 | 인증서 관리 필요 |
| Kerberos (GSSAPI) | 60 | GSSAPI 래핑 | Kerberos 티켓 | 중앙화된 인증, AD 통합 | KDC 인프라 필요 |
# /etc/audit/audisp-remote.conf — 원격 전송 설정
# 기본 연결 설정
remote_server = audit-collector.example.com
port = 60
transport = tcp # tcp 또는 tls
# TLS 설정 (transport = tls 시)
# enable_krb5 = no # Kerberos 사용 여부
# krb5_principal = auditd/hostname@REALM # Kerberos principal
# 장애 복구 설정
queue_depth = 2048 # 전송 실패 시 내부 큐 크기
network_retry_time = 5 # 네트워크 재시도 간격 (초)
max_tries_per_record = 3 # 레코드당 최대 재시도 횟수
max_time_per_record = 5 # 레코드당 최대 전송 시간 (초)
# 장애 시 동작
network_failure_action = syslog # 네트워크 장애: syslog/stop/halt/single/suspend
disk_low_action = suspend # 디스크 부족: suspend/ignore/syslog/halt
disk_full_action = suspend # 디스크 가득: halt/single/suspend
disk_error_action = syslog # 디스크 에러: syslog/halt/single
# 하트비트 (연결 상태 확인)
heartbeat_timeout = 0 # 0=비활성, N=N초마다 하트비트
# 오버플로우 동작
overflow_action = syslog # 내부 큐 초과 시 동작
# /etc/audit/plugins.d/au-remote.conf — 플러그인 활성화
active = yes
direction = out
path = /sbin/audisp-remote
type = always
format = string
# 수집기 측 auditd.conf — 원격 수신 설정
# tcp_listen_port = 60
# tcp_listen_queue = 5
# tcp_max_per_addr = 1
# tcp_client_ports = 1024-65535
# tcp_client_max_idle = 0 # 0=무제한
원격 감사 로깅 구성 시 반드시 TLS 상호 인증을 사용하세요. 네트워크 장애 시 network_failure_action = suspend로 설정하면 로그 유실 없이 연결 복구 후 자동 재전송합니다. 중앙 수집기에는 WORM(Write Once Read Many) 스토리지를 사용하여 로그 변조를 물리적으로 방지하세요. heartbeat_timeout = 30으로 설정하면 30초 간격으로 연결 상태를 확인합니다.
포렌식 분석 워크플로
침해 사고 대응에서 audit 로그는 공격 타임라인 재구성, 영향 범위 파악, 증거 보존의 핵심 데이터 소스입니다. 체계적인 분석 워크플로를 통해 사고의 전체 그림을 파악할 수 있습니다.
공격 체인 추적 예제
#!/bin/bash
# 포렌식 분석 스크립트 — 침해 사고 타임라인 재구성
# === 1단계: 증거 보존 ===
EVIDENCE_DIR="/forensics/case-$(date +%Y%m%d)"
mkdir -p "$EVIDENCE_DIR"
# 로그 파일 해시 기록 (무결성 증명용)
sha256sum /var/log/audit/audit.log* > "$EVIDENCE_DIR/log_hashes.txt"
cp -a /var/log/audit/ "$EVIDENCE_DIR/audit_backup/"
# === 2단계: 초기 접근 탐지 (Initial Access) ===
# 의심 시간대의 인증 실패 이벤트
ausearch --start "03/15/2026" "00:00:00" \
--end "03/16/2026" "23:59:59" \
--message USER_LOGIN --success no \
--interpret > "$EVIDENCE_DIR/failed_logins.txt"
# 성공한 SSH 로그인 (잠재적 초기 진입점)
ausearch --start "03/15/2026" "00:00:00" \
-m USER_LOGIN -sv yes \
--interpret > "$EVIDENCE_DIR/successful_logins.txt"
# === 3단계: 권한 상승 탐지 (Privilege Escalation) ===
# sudo 사용 내역
ausearch -k sudo_changes --interpret > "$EVIDENCE_DIR/sudo_activity.txt"
# uid 변경 (setuid, su 등)
ausearch -sc setuid -sc setreuid --interpret > "$EVIDENCE_DIR/uid_changes.txt"
# === 4단계: 측면 이동 탐지 (Lateral Movement) ===
# 외부 연결 시도
ausearch -sc connect --interpret > "$EVIDENCE_DIR/network_connections.txt"
# SSH 키 추가/변경
ausearch -f /root/.ssh/ -f /home/ -k ssh_keys \
--interpret > "$EVIDENCE_DIR/ssh_key_changes.txt"
# === 5단계: 지속성 확보 탐지 (Persistence) ===
# crontab 변경
ausearch -f /etc/crontab -f /var/spool/cron \
--interpret > "$EVIDENCE_DIR/cron_changes.txt"
# 서비스/데몬 등록
ausearch -f /etc/systemd/ -f /lib/systemd/ \
--interpret > "$EVIDENCE_DIR/service_changes.txt"
# === 6단계: 세션별 타임라인 재구성 ===
# 의심 사용자의 전체 활동 (세션 ID 기반)
SUSPECT_SESSION=42
ausearch --session "$SUSPECT_SESSION" --interpret \
> "$EVIDENCE_DIR/session_${SUSPECT_SESSION}_timeline.txt"
# === 7단계: 요약 보고서 ===
aureport --auth --failed --start "03/15/2026" \
> "$EVIDENCE_DIR/report_auth_failures.txt"
aureport --file --summary \
> "$EVIDENCE_DIR/report_file_access.txt"
aureport --executable --summary \
> "$EVIDENCE_DIR/report_executables.txt"
echo "분석 완료. 결과: $EVIDENCE_DIR"
법적 증거로 사용하려면 로그의 무결성 체인(Chain of Custody)을 유지해야 합니다. (1) 원본 로그를 즉시 해시(sha256sum)하고 해시값을 별도 보관합니다. (2) 분석은 반드시 사본에서 수행합니다. (3) auditctl -e 2(immutable 모드)로 감사 설정 변경을 방지합니다. (4) 원격 로그 서버의 WORM 스토리지에 보관된 사본과 로컬 로그를 교차 검증합니다. (5) 모든 분석 과정과 발견사항을 타임스탬프와 함께 기록합니다.
fanotify 감사 연동
fanotify(Filesystem-wide Access Notification)는 파일 시스템 이벤트를 모니터링하는 인터페이스로, 감사(audit)와 밀접하게 연관됩니다. 특히 FAN_ACCESS_PERM과 FAN_OPEN_PERM 권한 이벤트는 실시간 접근 제어와 감사 로깅을 모두 지원합니다.
fanotify 이벤트 타입과 감사 레코드 매핑
| fanotify 이벤트 | 감사 레코드 타입 | 설명 | 차단 가능 |
|---|---|---|---|
FAN_ACCESS | AUDIT_FANOTIFY (1327) | 파일 읽기 접근 | 아니오 |
FAN_MODIFY | AUDIT_FANOTIFY | 파일 수정 | 아니오 |
FAN_OPEN | AUDIT_FANOTIFY | 파일 열기 | 아니오 |
FAN_CLOSE_WRITE | AUDIT_FANOTIFY | 쓰기 모드로 열린 파일 닫기 | 아니오 |
FAN_OPEN_PERM | AUDIT_FANOTIFY | 파일 열기 권한 요청 | 예 |
FAN_ACCESS_PERM | AUDIT_FANOTIFY | 파일 읽기 권한 요청 | 예 |
FAN_OPEN_EXEC_PERM | AUDIT_FANOTIFY | 실행 파일 열기 권한 요청 | 예 |
/* fs/notify/fanotify/fanotify.c — fanotify 감사 후크 */
/* 감사 레코드에 fanotify 응답 기록 */
void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
{
/* response: FAN_ALLOW 또는 FAN_DENY */
/* friar: 규칙 번호 정보 (커널 6.1+) */
audit_log_start(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY);
audit_log_format(ab, "resp=%u fan_type=%u fan_info=%X subj_trust=%u obj_trust=%u",
response, friar ? friar->hdr.type : 0,
friar ? friar->rule_number : 0,
friar ? friar->subj_trust : 0,
friar ? friar->obj_trust : 0);
audit_log_end(ab);
}
/* fanotify 권한 이벤트 응답 구조체 */
struct fanotify_response {
__s32 fd; /* 이벤트의 파일 디스크립터 */
__u32 response; /* FAN_ALLOW (0x01) 또는 FAN_DENY (0x02) */
};
/* 확장 응답 정보 (커널 6.1+) */
struct fanotify_response_info_audit_rule {
struct fanotify_response_info_header hdr;
__u32 rule_number; /* 매칭된 규칙 번호 */
__u32 subj_trust; /* 주체 신뢰 수준 */
__u32 obj_trust; /* 객체 신뢰 수준 */
};
실시간 차단 vs 사후 감사: FAN_OPEN_PERM/FAN_ACCESS_PERM 이벤트를 사용하면 악성코드 스캐너(ClamAV 등)가 파일 접근을 실시간으로 차단할 수 있으며, 동시에 차단/허용 결정이 감사 로그에 기록됩니다. audit의 -w 규칙은 사후 감사만 가능한 반면, fanotify의 PERM 이벤트는 접근 전에 차단할 수 있다는 점이 핵심 차이입니다. fapolicyd(File Access Policy Daemon)는 이를 활용한 실제 구현 사례입니다.
SIEM 통합
감사 로그의 가치는 중앙 집중화된 분석과 실시간 알림을 통해 극대화됩니다. 주요 SIEM 플랫폼과의 통합 방법을 살펴봅니다.
SIEM별 통합 비교
| SIEM | 수집 방법 | 파싱 | 실시간 | 설정 난이도 | 비용 |
|---|---|---|---|---|---|
| Splunk | Splunk UF + Audit Add-on | 자동 (props.conf) | 예 | 낮음 | 높음 (라이선스) |
| Elastic SIEM | auditbeat / filebeat | ECS 자동 매핑 | 예 | 중간 | 무료 (기본) / 유료 (고급) |
| Wazuh | wazuh-agent (내장) | 내장 decoder | 예 | 낮음 | 무료 (오픈소스) |
| Graylog | auditbeat / syslog | 파이프라인(Pipeline) 규칙 | 예 | 중간 | 무료 (오픈소스) / 유료 |
| QRadar | syslog / WinCollect | DSM 자동 | 예 | 낮음 | 높음 (라이선스) |
# auditbeat.yml — Elastic auditbeat 설정 예제
auditbeat.modules:
- module: auditd
resolve_ids: true # UID→이름 변환
failure_mode: silent # 감사 실패 시 동작
backlog_limit: 8192 # 백로그 한도
rate_limit: 0 # 속도 제한 없음
include_raw_message: false # 원본 메시지 포함 여부
include_warnings: true
audit_rules: |
## 파일 접근 감사
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
## 특권 명령 감사
-a always,exit -F arch=b64 -S execve -F euid=0 -k root_cmd
## 네트워크 감사
-a always,exit -F arch=b64 -S connect -F a2!=110 -k network
- module: file_integrity
paths:
- /etc/
- /usr/bin/
- /usr/sbin/
scan_at_start: true
scan_rate_per_sec: 50 MiB
output.elasticsearch:
hosts: ["https://es-cluster:9200"]
username: "elastic"
password: "${ES_PASSWORD}"
ssl:
certificate_authorities: ["/etc/pki/ca.pem"]
# Splunk props.conf — Audit 로그 소스타입
# [linux_audit]
# TIME_PREFIX = msg=audit\(
# TIME_FORMAT = %s.%3N
# MAX_TIMESTAMP_LOOKAHEAD = 20
# SHOULD_LINEMERGE = false
# LINE_BREAKER = ([\n\r]+)type=
# TRUNCATE = 10000
커널 설정 옵션
Audit 서브시스템은 다수의 Kconfig 옵션으로 제어됩니다. 보안 요구사항과 성능 트레이드오프에 따라 적절한 조합을 선택해야 합니다.
| Kconfig 옵션 | 기본값 | 의존성 | 설명 |
|---|---|---|---|
CONFIG_AUDIT | y | 없음 | 기본 감사 프레임워크. 사용자 공간 메시지 로깅, 넷링크 인터페이스 제공 |
CONFIG_AUDITSYSCALL | y | AUDIT | 시스콜 감사. audit_syscall_entry/exit 후크 활성화. 비활성 시 시스콜 감사 불가 |
CONFIG_AUDIT_WATCH | y | AUDITSYSCALL, FSNOTIFY | 파일 감시 (-w 규칙). fsnotify 기반 개별 파일 변경 감시 |
CONFIG_AUDIT_TREE | y | AUDITSYSCALL, FSNOTIFY | 디렉토리 트리 감시. 재귀적 디렉토리 감시 지원 |
CONFIG_AUDIT_ARCH | y (자동) | 아키텍처 의존 | 아키텍처별 시스콜 번호 매핑. x86_64에서 32/64비트 구분 |
CONFIG_AUDIT_LOGINUID_IMMUTABLE | n | AUDITSYSCALL | loginuid(auid) 변경 금지. 한 번 설정 후 재설정 불가 |
CONFIG_AUDIT_GENERIC | 아키텍처별 | AUDITSYSCALL | 아키텍처 독립적 감사 지원 (일부 아키텍처만) |
CONFIG_INTEGRITY_AUDIT | y | AUDIT, INTEGRITY | IMA 무결성 검증 감사 이벤트 생성 |
CONFIG_NET | y | (간접) | NETLINK_AUDIT 소켓 전제 조건 |
# 현재 커널의 audit 관련 설정 확인
grep -E "^CONFIG_AUDIT" /boot/config-$(uname -r)
# CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL=y
# CONFIG_AUDIT_WATCH=y
# CONFIG_AUDIT_TREE=y
# CONFIG_AUDIT_ARCH=y
# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
# 런타임 감사 상태 확인
auditctl -s
# enabled 1
# failure 1
# pid 1234
# rate_limit 0
# backlog_limit 8192
# lost 0
# backlog 0
# backlog_wait_time 60000
# 부트 파라미터로 감사 제어
# audit=0 — 완전 비활성화 (성능 최적화, 오버헤드 0)
# audit=1 — 활성화 (기본)
# audit_backlog_limit=8192 — 부트 시 백로그 한도 설정
# GRUB 설정 예제
# GRUB_CMDLINE_LINUX="audit=1 audit_backlog_limit=8192"
최소 설정 가이드: 컴플라이언스가 불필요한 개발 환경에서는 audit=0 부트 파라미터로 감사를 완전 비활성화하여 최대 성능을 확보할 수 있습니다. 반대로 PCI-DSS/HIPAA 인증 환경에서는 CONFIG_AUDITSYSCALL=y, CONFIG_AUDIT_WATCH=y, CONFIG_AUDIT_TREE=y가 모두 필요합니다. CONFIG_AUDIT_LOGINUID_IMMUTABLE=y는 보안을 강화하지만 컨테이너 환경과 호환성 문제가 있으므로 신중하게 선택하세요.
트러블슈팅 가이드
Audit 서브시스템 운영 중 자주 발생하는 문제와 체계적인 진단 방법을 정리합니다.
진단 명령어 모음
# === 기본 상태 확인 ===
auditctl -s # 감사 상태 (enabled, pid, lost, backlog)
auditctl -l # 현재 규칙 목록
systemctl status auditd # auditd 서비스 상태
# === 백로그 모니터링 ===
# 실시간 백로그 추적
watch -n 1 'auditctl -s | grep -E "lost|backlog"'
# 커널 메시지에서 audit 경고 확인
dmesg | grep -i audit
# === 규칙 디버깅 ===
# 규칙이 실제로 매칭되는지 확인
ausearch -k "my_key" --start recent
# 특정 시스콜에 대한 규칙 확인
auditctl -l | grep "execve"
# 모든 규칙 삭제 후 재로드
auditctl -D # 주의: immutable(-e 2) 모드에서는 실패
augenrules --load
# === 디스크 문제 ===
df -h /var/log/audit/ # 감사 로그 파티션 공간
du -sh /var/log/audit/ # 감사 로그 총 크기
ls -la /var/log/audit/ # 로그 파일 및 로테이션 확인
# === 성능 영향 측정 ===
# audit 관련 CPU 소비 확인
perf top -g | grep audit # 실시간 핫스팟
grep kauditd /proc/*/comm # kauditd 스레드 PID
cat /proc/$(pgrep kauditd)/status # kauditd 상태
# === auditd 설정 검증 ===
auditd -f # 포그라운드 모드로 실행 (디버깅용)
ausearch --input-logs --raw # 원시 로그 확인
일반적인 에러 메시지와 해결 방법
| 증상 | 원인 | 진단 방법 | 해결 방법 |
|---|---|---|---|
| audit.log에 레코드 없음 | 감사 비활성화 | auditctl -s로 enabled 확인 | auditctl -e 1 또는 부트 파라미터 확인 |
| 특정 이벤트만 누락 | 규칙 미등록 또는 never 규칙 우선 매칭 | auditctl -l로 규칙 순서 확인 | 규칙 순서 조정, never 규칙 검토 |
lost > 0 증가 | 백로그 초과 | auditctl -s의 backlog/backlog_limit | -b 65536, 노이즈 규칙 제거 |
| auditd 반복 재시작(Reboot) | 디스크 가득 또는 설정 오류 | journalctl -u auditd | 로그 로테이션, max_log_file_action=rotate |
| 규칙 추가 시 EPERM | 권한 부족 또는 immutable | auditctl -s의 enabled 값 | root로 실행, enabled=2면 재부팅 |
| 파일 감시 무반응 | 경로 오류 또는 마운트(Mount) 변경 | auditctl -l로 -w 규칙 확인 | 절대 경로 사용, 심볼릭 링크 주의 |
| auid=-1 (4294967295) | PAM 세션 미경유 | 컨테이너 또는 비인터랙티브 프로세스 | 정상 동작 (loginuid 미설정) |
| 높은 CPU 사용 | 과도한 규칙 또는 고빈도 이벤트 | perf top으로 핫스팟 확인 | 규칙 최적화, exclude 규칙 추가 |
감사 대상 시스템 콜 분류
효과적인 감사 정책 수립을 위해 시스템 콜을 보안 관점에서 분류하고, 각 카테고리별 중요도와 권장 감사 수준을 정리합니다.
파일 시스템 관련
| 시스콜 | 보안 중요도 | 설명 | 감사 권장 |
|---|---|---|---|
open / openat | 높음 | 파일 열기 (읽기/쓰기/생성) | 실패 시 필수 (exit=-EACCES) |
creat | 높음 | 파일 생성 | 민감 디렉토리에서 필수 |
unlink / unlinkat | 높음 | 파일 삭제 | 필수 (증거 인멸 탐지) |
rename / renameat | 중간 | 파일 이름 변경 | 권장 (로그 변조 탐지) |
chmod / fchmod | 높음 | 파일 권한 변경 | 필수 (권한 에스컬레이션) |
chown / fchown / lchown | 높음 | 파일 소유자 변경 | 필수 |
truncate / ftruncate | 중간 | 파일 크기 변경 | 로그 파일에 대해 필수 |
link / linkat | 중간 | 하드 링크 생성 | 권장 |
symlink / symlinkat | 중간 | 심볼릭 링크 생성 | 권장 (심링크 공격) |
mkdir / rmdir | 중간 | 디렉토리 생성/삭제 | 민감 경로에서 필수 |
mount / umount2 | 높음 | 파일 시스템 마운트/언마운트 | 필수 |
프로세스 관련
| 시스콜 | 보안 중요도 | 설명 | 감사 권장 |
|---|---|---|---|
execve / execveat | 최고 | 프로그램 실행 | 필수 (명령 실행 추적의 핵심) |
fork / clone / clone3 | 중간 | 프로세스 생성 | 선택적 (고빈도) |
kill / tkill / tgkill | 중간 | 시그널 전송 | SIGKILL/SIGSTOP에 대해 권장 |
ptrace | 최고 | 프로세스 추적/디버깅(Debugging) | 필수 (인젝션 공격 탐지) |
prctl | 중간 | 프로세스 속성 변경 | PR_SET_DUMPABLE 등 권장 |
권한 관련
| 시스콜 | 보안 중요도 | 설명 | 감사 권장 |
|---|---|---|---|
setuid / setreuid / setresuid | 최고 | 사용자 ID 변경 | 필수 (권한 에스컬레이션 핵심) |
setgid / setregid / setresgid | 높음 | 그룹 ID 변경 | 필수 |
setgroups | 높음 | 보조 그룹 설정 | 필수 |
capset | 최고 | Capability 설정 | 필수 |
setxattr / lsetxattr / fsetxattr | 높음 | 확장 속성(Extended Attribute) 설정 (SELinux 컨텍스트 포함) | 필수 |
personality | 중간 | 실행 도메인 변경 | 권장 |
네트워크 관련
| 시스콜 | 보안 중요도 | 설명 | 감사 권장 |
|---|---|---|---|
socket | 중간 | 소켓 생성 | 선택적 (고빈도) |
connect | 높음 | 외부 연결 | C2 통신 탐지에 필수 |
bind | 높음 | 포트 바인딩 | 비인가 서비스 탐지에 필수 |
listen | 높음 | 연결 대기 | 백도어 탐지에 필수 |
accept / accept4 | 중간 | 연결 수락 | 서버에서 권장 |
sendto / recvfrom | 낮음 | 데이터 송수신 | 매우 고빈도, 선택적 |
시간/모듈/시스템 관련
| 시스콜 | 보안 중요도 | 설명 | 감사 권장 |
|---|---|---|---|
adjtimex / clock_settime | 최고 | 시스템 시간 변경 | 필수 (타임라인 변조 방지) |
settimeofday | 최고 | 시간대/시간 변경 | 필수 |
init_module / finit_module | 최고 | 커널 모듈 로드 | 필수 (루트킷 탐지) |
delete_module | 최고 | 커널 모듈 언로드 | 필수 |
swapon / swapoff | 중간 | 스왑(Swap) 활성/비활성 | 권장 |
reboot | 높음 | 시스템 재부팅 | 필수 |
sethostname / setdomainname | 중간 | 호스트명 변경 | 필수 (CIS 요구) |
kexec_load | 최고 | 새 커널 로드 | 필수 |
bpf | 높음 | eBPF 프로그램 로드 | 필수 (eBPF 악용 탐지) |
IPC 관련
| 시스콜 | 보안 중요도 | 설명 | 감사 권장 |
|---|---|---|---|
msgget / msgsnd / msgrcv | 낮음 | System V 메시지 큐 | 선택적 |
semget / semctl | 낮음 | System V 세마포어(Semaphore) | 선택적 |
shmget / shmat / shmdt | 중간 | System V 공유 메모리 | 보안 환경에서 권장 |
mq_open / mq_send | 낮음 | POSIX 메시지 큐 | 선택적 |
성능과 보안의 균형을 위한 최소 권장 세트: execve, ptrace, setuid/setreuid/setresuid, setgid/setregid/setresgid, capset, connect, bind, listen, init_module/finit_module/delete_module, adjtimex/clock_settime, mount, reboot, kexec_load, bpf, unlink(로그 파일 경로만), chmod/chown(민감 경로만). 이 세트는 약 20개 규칙으로 MITRE ATT&CK의 주요 기법을 커버합니다.
# 최소 감사 권장 규칙 세트 (minimal-audit.rules)
# 규칙 삭제 및 버퍼 설정
-D
-b 8192
# === 1. 프로그램 실행 (최우선) ===
-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k exec
-a always,exit -F arch=b32 -S execve -F auid>=1000 -F auid!=4294967295 -k exec
# === 2. 권한 변경 ===
-a always,exit -F arch=b64 -S setuid,setreuid,setresuid -k priv_esc
-a always,exit -F arch=b64 -S setgid,setregid,setresgid -k priv_esc
# === 3. 커널 모듈 ===
-a always,exit -S init_module,finit_module,delete_module -k modules
# === 4. 시간 변경 ===
-a always,exit -S adjtimex,settimeofday,clock_settime -k time
# === 5. 네트워크 ===
-a always,exit -F arch=b64 -S connect -F a2!=110 -k network_connect
-a always,exit -F arch=b64 -S bind,listen -k network_listen
# === 6. 민감 파일 ===
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k sudo
-w /var/log/audit/ -p wa -k audit_tamper
# === 7. 마운트/부팅 ===
-a always,exit -S mount -k mount
-a always,exit -S reboot,kexec_load -k reboot
# === 8. 디버깅/인젝션 ===
-a always,exit -S ptrace -k injection
-a always,exit -S bpf -k bpf
# 규칙 고정 (immutable) — 프로덕션에서 권장
# -e 2
관련 문서
외부 참고 자료
- The /proc Filesystem — Kernel Documentation — /proc/PID/loginuid 등 감사 관련 proc 인터페이스입니다
- Linux Audit — Steve Grubb (Red Hat) — 리눅스 감사 시스템 메인테이너 사이트입니다
- audit-userspace GitHub — auditd, auditctl, ausearch, aureport 등 사용자 공간 도구 소스입니다
- audit-kernel GitHub — 커널 감사 서브시스템 개발 저장소입니다
- RHEL 9 — Auditing the System — Red Hat 공식 감사 시스템 구성 가이드입니다
- auditd(8) — Linux man page — Linux Audit 데몬 매뉴얼 페이지입니다
- auditctl(8) — Linux man page — 감사 규칙 설정 도구 매뉴얼입니다
- audit.rules(7) — Linux man page — 감사 규칙 문법 및 예제입니다
- Kernel Security Subsystem — 감사 서브시스템이 속한 커널 보안 문서 인덱스입니다
- Gentoo Wiki — Audit — Linux Audit 설치 및 설정 가이드입니다