Audit 서브시스템

Linux Audit 서브시스템은 커널 수준에서 보안 관련 이벤트를 기록하는 프레임워크입니다. 시스템 콜(System Call), 파일 접근, 네트워크 연결, 사용자 인증 등 거의 모든 커널 활동을 감사할 수 있으며, PCI-DSS, HIPAA, SOX, CAPP(Controlled Access Protection Profile) 등 보안 컴플라이언스 인증의 필수 요구사항을 충족합니다.

전제 조건: 커널 보안 (Kernel Security)시스템 콜(System Call) 문서를 먼저 읽으세요. Audit 서브시스템은 시스템 콜 진입/종료 시점에서 이벤트를 수집하므로 시스템 콜 메커니즘 이해가 필수입니다.
일상 비유: Audit 서브시스템은 건물의 CCTV 관제 시스템과 비슷합니다. 출입문(시스템 콜)마다 카메라(감사 후크)가 설치되어 누가(UID), 언제, 무엇을(파일 접근, 권한 변경) 했는지 기록합니다. 관제실(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 등 보안 컴플라이언스 규칙 세트를 지원합니다.

단계별 이해

  1. 아키텍처 — 커널·사용자 공간 구성 요소와 데이터 흐름을 파악합니다.
  2. audit_context 생명주기 — 시스템 콜 진입/종료 시 감사 데이터 수집 과정을 이해합니다.
  3. 필터 엔진 — 5개 필터 리스트와 규칙 매칭 메커니즘을 학습합니다.
  4. 감사 도구 — auditctl, ausearch, aureport 등 실용 도구 사용법을 익힙니다.
  5. 보안 컴플라이언스 — PCI-DSS, CIS, NIST 800-53, ISO 27001 등에 맞춘 규칙 세트를 적용합니다.
  6. NETLINK_AUDIT 프로토콜 — 커널-사용자 공간 통신 프로토콜의 메시지 타입과 동작을 이해합니다.
  7. 백로그 메커니즘 — 백로그 큐, 실패 모드, 유실 방지 전략을 학습합니다.
  8. 파일 감시 내부 — audit_watch, audit_tree, fsnotify 연동의 내부 동작을 파악합니다.
  9. 컨테이너(Container) 환경 — 컨테이너에서의 감사 제한사항과 eBPF 대안을 이해합니다.
  10. io_uring 감사 — io_uring의 syscall 우회 문제와 감사 후크를 학습합니다.
  11. SIEM 통합 — Splunk, ELK, Wazuh 등 SIEM과의 연동 방법을 익힙니다.
ℹ️

Audit 서브시스템은 CONFIG_AUDIT (기본 프레임워크)와 CONFIG_AUDITSYSCALL (시스템 콜 감사)로 활성화됩니다. 배포판별 기본 활성화 정책은 참고자료에서 최신 상태를 확인하세요. 부팅 시 audit=1 커널 파라미터로 조기 부팅 단계부터 감사를 시작할 수 있습니다.

아키텍처

Audit 서브시스템은 커널 공간의 감사 후크(hook)와 사용자 공간의 auditd 데몬으로 구성됩니다. 커널이 이벤트를 수집하고, NETLINK_AUDIT 소켓을 통해 사용자 공간으로 전달합니다.

커널 공간 사용자 공간 시스템 콜 진입 audit_syscall_entry() audit_context 이벤트 데이터 수집 시스템 콜 종료 audit_syscall_exit() audit_buffer 메시지 직렬화 필터 엔진 규칙 매칭 (5개 리스트) kauditd 커널 스레드 audit_skb_queue netlink 전송 큐 NETLINK_AUDIT AF_NETLINK 소켓 auditd 감사 데몬 audisp 플러그인 이벤트 디스패처 /var/log/audit/ ausearch aureport

감사 규칙 평가 체인

감사 이벤트 발생 시, 커널은 5개의 필터 리스트를 정해진 순서로 평가합니다. 각 리스트의 규칙은 순차적으로 매칭되며, 첫 매칭 규칙의 action(AUDIT_ALWAYS/AUDIT_NEVER)이 적용됩니다. 규칙 배치 순서가 성능에 직접적 영향을 미치므로, 빈도 높은 제외 규칙을 앞에 배치하는 것이 중요합니다.

이벤트 발생 시스템 콜/fork 1. task fork/clone 시점 uid, gid, pid loginuid, sessionid 2. exit syscall 종료 시 모든 필드 사용 가능 (가장 많이 사용) 3. user 사용자 공간 메시지 uid, pid, loginuid msgtype 4. exclude 전송 직전 제외 msgtype 기반 노이즈 필터링 5. filesystem fstype 기반 감시 규칙 매칭 요소 필드 비교 (Field) -F uid=0 -F auid>=1000 -F exit=-EACCES -F arch=b64 AUDIT_EQUAL / NOT_EQUAL Syscall 매칭 -S execve -S openat -S open -S connect -S all (모든 syscall) 비트마스크 O(1) 검사 파일 감시 (Watch) -w /etc/passwd -p wa -w /etc/sudoers -p wa audit_watch + fsnotify audit_tree (디렉토리) inode 기반 추적 action = AUDIT_ALWAYS → audit_context.state = RECORD → 로그 생성 action = AUDIT_NEVER → audit_context.state = DISABLED → 로그 생략 성능 최적화: never(제외) 규칙을 always 규칙보다 앞에 배치하여 불필요한 평가 방지

감사 이벤트 레코드 계층 구조

하나의 감사 이벤트는 여러 레코드 타입으로 구성됩니다. SYSCALL 레코드가 부모 역할을 하며, 관련 정보가 자식 레코드(PATH, CWD, EXECVE, SOCKADDR, PROCTITLE)로 분리됩니다. 모든 레코드는 동일한 시리얼 번호(EPOCH:SERIAL)로 연결됩니다.

이벤트 그룹: msg=audit(1706000000.123:789) — 동일 시리얼로 연결 SYSCALL (type=1300) 부모 레코드 — syscall NR, 인자, UID, PID, exe, key arch=c000003e syscall=257 success=yes exit=3 auid=1000 PATH (1302) name, inode, dev mode, ouid, ogid item=0,1,... (다중) CWD (1307) cwd="/home/user" 현재 작업 디렉토리 EXECVE (1309) argc, a0, a1, a2 실행 인자 전체 긴 인자는 분할 SOCKADDR (1306) saddr (hex 인코딩) 소켓 주소 정보 PROCTITLE (1327) proctitle (hex) 프로세스 커맨드라인 EOE (End of Event) — type=1320 동일 시리얼의 모든 레코드 전송 완료 표시
레코드 재조립:

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 상태 머신:

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

주요 레코드 타입

타입번호설명주요 필드
SYSCALL1300시스템 콜 이벤트arch, syscall, success, exit, auid, uid, exe, key
PATH1302파일 경로 정보name, inode, dev, mode, ouid, ogid, nametype
CWD1307현재 작업 디렉토리cwd
EXECVE1309exec 인자argc, a0, a1, a2...
PROCTITLE1327프로세스(Process) 커맨드라인proctitle (hex 인코딩)
SOCKADDR1306소켓 주소saddr (hex 인코딩 sockaddr)
USER_AUTH1100사용자 인증pid, uid, auid, msg (PAM 정보)
USER_LOGIN1112사용자 로그인pid, uid, auid, ses, msg
USER_CMD1123sudo 명령 실행pid, uid, auid, cmd
AVC1400SELinux 접근 제어(Access Control)pid, comm, scontext, tcontext, tclass, perm
NETFILTER_PKT1325netfilter 패킷(Packet) 감사mark, saddr, daddr, sport, dport, proto
KERN_MODULE1326커널 모듈(Kernel Module) 로드name
ANOM_ABEND1701비정상 프로세스 종료auid, uid, gid, ses, pid, comm, sig
ℹ️

auid (Audit UID)는 사용자가 최초 로그인할 때 설정되며, susudo로 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;
}
kauditd 3-큐 관리 흐름 (retry/hold/main 우선순위) kauditd 3-큐 우선순위 관리 흐름 audit_log_end() audit_queue (main) kauditd_thread() retry_queue (P1 최우선) 1단계 hold_queue (P2) 2단계 main_queue 전송 (P3) 3단계 netlink_unicast(auditd) 실패 → hold_queue 전송 실패 auditd → /var/log/audit/ 전송 성공 재순환 wait_event_freezable() (큐 비어있으면 대기)
ℹ️

큐 우선순위(Priority): kauditd는 매 루프에서 retry → hold → main 순서로 큐를 처리합니다. retry 큐에 실패 메시지가 있으면 main 큐 새 메시지보다 먼저 재전송(Retransmission)하여, 감사 로그의 시간순 일관성을 최대한 유지합니다. auditd가 완전히 종료된 경우 hold 큐에 메시지가 누적되며, audit_hold_queue의 크기가 audit_backlog_limit을 초과하면 오래된 메시지부터 폐기됩니다.

필터 엔진

감사 규칙은 5개의 필터 리스트에 배치되며, 이벤트 발생 시 해당 리스트의 규칙을 순차 매칭합니다. 첫 매칭 규칙의 action(always/never)이 적용됩니다.

필터 리스트평가 시점사용 가능 필드
taskfork/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 (잠금(Lock) 모드):

프로덕션 환경에서는 규칙 설정 완료 후 -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-syslogsyslog/rsyslog로 감사 이벤트 전달syslog.conf
audisp-remote원격 감사 서버로 TCP 전달au-remote.conf
sedispatchSELinux 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, ...);
}
시스콜 경로의 감사 오버헤드 측정 지점 시스콜 경로 감사 오버헤드 측정 지점 User syscall() syscall_entry P1: audit_syscall_entry() audit_n_rules 체크 + context 할당 실제 syscall 실행 P2: 경로/이름 수집 audit_inode(), getname_flags() syscall_exit P3: audit_syscall_exit() 필터 매칭 + 레코드 조립 + skb 전송 오버헤드 구성 비율 (감사 활성 시) P3 필터 매칭 + skb 조립 (~60%) P2 경로 수집 (~25%) P1 (~10%) 기타 벤치마크 (syscall 당 추가 지연, x86_64) 규칙 0개 (audit=1, 프레임워크만 활성): ~50-100ns/syscall 규칙 10개 (일반적 컴플라이언스 세트): ~200-500ns/syscall 규칙 100개+ (과도한 설정): ~1-5μs/syscall 파일 감시 (-w) 1000개+: ~2-10μs/open (해시 탐색) audit=0 (완전 비활성): 0ns (컴파일 시 제거)
오버헤드 측정 방법:

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_exitaudit_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.2root 활동 감사-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.6MAC 정책 변경-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 404IT 통제 변경-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-72095chown 감사-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;       /* 감사 불필요 */
}

Audit 서브시스템의 커널-유저 공간 통신은 전적으로 NETLINK_AUDIT 프로토콜 패밀리를 통해 이루어집니다. 이 넷링크 소켓은 양방향 통신을 지원하며, auditd가 커널에 규칙을 설정하고 이벤트를 수신하는 유일한 채널입니다.

메시지 타입 분류

NETLINK_AUDIT은 1000번대 메시지 타입을 사용하며, 크게 제어 메시지(1000~1099), 이벤트 메시지(1100~1399), 사용자 메시지(1400~1499)로 분류됩니다.

메시지 타입번호방향설명
AUDIT_GET1000유저 → 커널현재 감사 상태 조회 (enabled, pid, backlog 등)
AUDIT_SET1001유저 → 커널감사 상태 설정 (enabled, pid, backlog_limit, failure 등)
AUDIT_LIST_RULES1013유저 → 커널현재 등록된 모든 규칙 조회
AUDIT_ADD_RULE1011유저 → 커널감사 규칙 추가
AUDIT_DEL_RULE1012유저 → 커널감사 규칙 삭제
AUDIT_USER1005유저 → 커널사용자 공간 메시지 로깅 (PAM 등)
AUDIT_SIGNAL_INFO1010유저 → 커널시그널(Signal) 발신자 정보 조회
AUDIT_TRIM1014유저 → 커널감시 트리에서 유효하지 않은 항목 정리
AUDIT_MAKE_EQUIV1015유저 → 커널디렉토리 감시 경로 동등성 설정
AUDIT_SET_FEATURE1018유저 → 커널감사 기능 플래그 설정 (loginuid_immutable 등)
AUDIT_GET_FEATURE1019유저 → 커널감사 기능 플래그 조회
AUDIT_SYSCALL1300커널 → 유저시스템 콜 감사 이벤트
AUDIT_PATH1302커널 → 유저파일 경로 정보 레코드
AUDIT_IPC1303커널 → 유저IPC 객체 정보 레코드
AUDIT_SOCKADDR1306커널 → 유저소켓 주소 정보 레코드
AUDIT_CWD1307커널 → 유저현재 작업 디렉토리 레코드
AUDIT_EXECVE1309커널 → 유저execve 인자 레코드
AUDIT_PROCTITLE1327커널 → 유저프로세스 타이틀 레코드
AUDIT_EOE1320커널 → 유저이벤트 종료 표시자 (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가 시작되면 다음 순서로 커널에 등록합니다:

  1. socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT)로 넷링크 소켓 생성
  2. bind()로 멀티캐스트 그룹 AUDIT_NLGRP_READLOG에 참여
  3. AUDIT_SET 메시지로 자신의 PID를 커널에 등록 (audit_status.pid = getpid())
  4. AUDIT_SETenabled=1, backlog_limit, failure 등 설정
  5. AUDIT_LIST_RULES로 기존 규칙 확인 후 필요한 규칙 추가
NETLINK_AUDIT 메시지 교환 시퀀스 (auditd ↔ 커널) NETLINK_AUDIT 메시지 교환 시퀀스 auditd 커널 audit 서브시스템 socket(NETLINK_AUDIT) AUDIT_SET (pid=self, enabled=1, backlog_limit=8192) NLMSG_ERROR (error=0, ACK) AUDIT_ADD_RULE (syscall=execve, action=always) NLMSG_ERROR (error=0, ACK) AUDIT_GET (상태 조회) AUDIT_GET (audit_status 응답) ... 감사 대상 이벤트 발생 ... AUDIT_SYSCALL (type=1300, 감사 이벤트) AUDIT_CWD + AUDIT_PATH (보조 레코드) AUDIT_PROCTITLE (프로세스 타이틀) AUDIT_EOE (이벤트 종료 표시) AUDIT_USER (PAM 인증 이벤트 전달) NLMSG_ERROR (ACK)
/* 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_limit64auditctl -b N백로그 큐 최대 크기. 0=무제한
backlog_wait_time60000msauditctl --backlog_wait_time N큐 가득 시 태스크 최대 대기 시간
failure1 (printk)auditctl -f N실패 모드: 0=silent, 1=printk, 2=panic
rate_limit0auditctl -r N초당 최대 메시지 수 (0=무제한)

실패 모드 상세

모드동작적용 환경
AUDIT_FAIL_SILENT0메시지 자동 폐기, lost 카운터 증가, 태스크 차단 없음가용성 우선 시스템 (웹 서버 등)
AUDIT_FAIL_PRINTK1커널 로그에 경고 출력 후 폐기, lost 카운터 증가일반적인 기본 설정
AUDIT_FAIL_PANIC2커널 패닉(Kernel Panic) 발생 — 감사 이벤트 유실 방지 최우선CAPP/LSPP 인증 환경, 군사/금융
백로그 큐 흐름 (audit_queue → kauditd → auditd, 실패 모드 분기) Audit 백로그 큐 흐름과 실패 모드 분기 audit_log_start() backlog < limit? 큐에 삽입 (enqueue) Yes kauditd 전송 backlog_wait 대기 No (초과) 공간 확보? Yes audit_log_lost() No (타임아웃) FAIL_SILENT (0) 조용히 폐기, lost++ FAIL_PRINTK (1) dmesg 경고 + lost++ FAIL_PANIC (2) kernel panic!
/* 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[];              /* 감시 경로 (가변 길이) */
};
audit_watch ↔ fsnotify ↔ inode 관계 다이어그램 audit_watch ↔ fsnotify ↔ inode 관계 auditctl -w /etc/passwd -p rwa audit_watch path="passwd" ino=12345, dev=sda1 audit_parent 디렉토리: /etc/ parent 포인터 fsnotify_mark mask: FS_MODIFY|FS_ATTRIB mark inode (/etc/) i_fsnotify_marks list 연결 inode (passwd) ino=12345 fsnotify 이벤트 발생 → audit_watch_handle_event() 감사 레코드 생성 audit_log_start() → kauditd rename/replace 시 FS_MOVED_FROM 이벤트 → audit_update_watch()

-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_TOrename 시 감시 재연결
/* 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 데몬이 호스트와 모든 컨테이너의 감사 이벤트를 수집합니다.

주요 제한사항

문제원인영향
단일 auditdNETLINK_AUDIT 소켓은 하나의 PID만 등록 가능컨테이너별 독립 감사 불가
loginuid 문제컨테이너 내부에서 auid=-1 (4294967295)사용자 추적 불가능
규칙 격리(Isolation) 없음호스트와 컨테이너가 동일 규칙 세트 공유컨테이너별 정책 분리 불가
네임스페이스(Namespace) 미지원audit 네임스페이스 커널 패치(Patch) 미병합 (2024년 현재)멀티테넌트 감사 제한
성능 집중모든 컨테이너 이벤트가 단일 auditd로 집중대규모 환경에서 백로그 초과
호스트-컨테이너 audit 아키텍처 호스트-컨테이너 Audit 아키텍처 호스트 (Host OS) Linux 커널 (공유) audit 서브시스템 kauditd Container A Web App auid=-1 syscall: openat() Container B Database auid=-1 syscall: write() Container C API Server auid=-1 syscall: connect() 호스트 auditd /var/log/audit/audit.log 호스트 프로세스 auid=1000 (유효)

컨테이너 감사 대안 비교

도구기반 기술컨테이너 인식실시간 차단커널 변경 필요장점
Linux Audit커널 후크제한적 (호스트 공유)불가불필요컴플라이언스 인증, 안정성
FalcoeBPF/커널 모듈완전 (K8s 네이티브)불가 (탐지만)불필요K8s 통합, YAML 규칙
SysdigeBPF완전불가불필요풍부한 메타데이터
TraceeeBPF완전불가불필요보안 이벤트 특화
TetragoneBPF완전가능불필요실시간 정책 적용
KubeArmoreBPF/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"
loginuid (auid) 문제:

컨테이너 런타임은 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_contexturing_op 필드가 추가되었지만, 완전한 감사 커버리지는 아직 진행 중입니다.

io_uring 감사 경로 vs 전통 syscall 감사 경로 비교 전통 Syscall vs io_uring 감사 경로 비교 전통 시스콜 경로 (완전 감사) User: open() audit_entry() do_sys_open audit_exit() 감사 레코드 생성 io_uring 경로 (커널 < 5.6, 감사 우회) User: SQE 제출 io_uring_enter() io_openat() 감사 후크 없음! 로그 없음 io_uring 경로 (커널 5.6+, 부분 감사) User: SQE 제출 io_uring_enter() audit_uring_entry() io_openat() audit_uring_exit() 감사 레코드 생성 감사 후크 존재 감사 사각지대
/* 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 감사가 없는 커널에서는 공격자가 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 (기본)없음없음단순 구성, 최소 오버헤드도청/변조 취약
TLS60 (기본)TLS 1.2/1.3X.509 인증서전송 암호화, 상호 인증인증서 관리 필요
Kerberos (GSSAPI)60GSSAPI 래핑Kerberos 티켓중앙화된 인증, AD 통합KDC 인프라 필요
원격 감사 토폴로지 (다중 서버 → relay → 중앙 수집기) 원격 감사 로깅 토폴로지 소스 서버 Web Server auditd audisp-remote DB Server auditd audisp-remote App Server auditd audisp-remote CI/CD Server auditd audisp-remote Relay Server auditd (수신) audisp-remote (전송) 로컬 백업 보관 TLS 종단 TLS 중앙 수집기 auditd (수신 전용) 장기 보관 스토리지 aureport 분석 SIEM 전송 WORM 스토리지 권장 TLS SIEM 분석/알림
# /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 로그는 공격 타임라인 재구성, 영향 범위 파악, 증거 보존의 핵심 데이터 소스입니다. 체계적인 분석 워크플로를 통해 사고의 전체 그림을 파악할 수 있습니다.

포렌식 분석 파이프라인 (수집 → 정규화 → 타임라인 → 상관 분석 → 보고서) 포렌식 분석 파이프라인 1. 수집 audit.log 확보 로테이션 파일 포함 해시값 기록 2. 정규화 UID→이름 변환 hex→text 디코딩 syscall NR→이름 3. 타임라인 시간순 정렬 세션 그룹핑 공격 단계 식별 4. 상관 분석 다중 소스 교차 IOC 매칭 MITRE ATT&CK 매핑 5. 보고서 사고 경위서 영향 범위 개선 권고 단계별 핵심 도구 수집: cp, rsync, sha256sum, dd (raw disk) 정규화: ausearch --interpret, aureport, aulast 타임라인: ausearch --start/--end --session, aureport --summary --start 상관분석: ausearch -a (이벤트 ID), --key, --comm 보고서: aureport --auth --failed, --file --summary

공격 체인 추적 예제

#!/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_PERMFAN_OPEN_PERM 권한 이벤트는 실시간 접근 제어와 감사 로깅을 모두 지원합니다.

fanotify 이벤트 타입과 감사 레코드 매핑

fanotify 이벤트감사 레코드 타입설명차단 가능
FAN_ACCESSAUDIT_FANOTIFY (1327)파일 읽기 접근아니오
FAN_MODIFYAUDIT_FANOTIFY파일 수정아니오
FAN_OPENAUDIT_FANOTIFY파일 열기아니오
FAN_CLOSE_WRITEAUDIT_FANOTIFY쓰기 모드로 열린 파일 닫기아니오
FAN_OPEN_PERMAUDIT_FANOTIFY파일 열기 권한 요청
FAN_ACCESS_PERMAUDIT_FANOTIFY파일 읽기 권한 요청
FAN_OPEN_EXEC_PERMAUDIT_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 통합 아키텍처 (audit → 수집 → 전처리 → SIEM → 대시보드/알림) SIEM 통합 아키텍처 Linux Kernel audit 서브시스템 auditd + audisp auditbeat filebeat (로그) 전처리 정규화 (필드 매핑) 보강 (GeoIP, DNS) 필터링 (노이즈 제거) ECS 변환 Splunk Elastic SIEM Wazuh/OSSEC 알림/알람 대시보드 보고서 SIEM별 통합 방법 비교 Splunk: Splunk Add-on for Linux Audit, props.conf에서 AUDIT 소스타입 정의, CIM 매핑 Elastic: auditbeat (커널 직접 연동) 또는 filebeat audit module, ECS 필드 자동 매핑 Wazuh: audit decoder 내장, /var/log/audit/audit.log 실시간 파싱, 규칙 ID 80700-80799 Graylog: audisp-syslog → rsyslog → GELF 변환, 또는 Beats input으로 auditbeat 직접 수신 QRadar: Linux Audit DSM, syslog 프로토콜로 수집, 자동 정규화 및 QID 매핑

SIEM별 통합 비교

SIEM수집 방법파싱실시간설정 난이도비용
SplunkSplunk UF + Audit Add-on자동 (props.conf)낮음높음 (라이선스)
Elastic SIEMauditbeat / filebeatECS 자동 매핑중간무료 (기본) / 유료 (고급)
Wazuhwazuh-agent (내장)내장 decoder낮음무료 (오픈소스)
Graylogauditbeat / syslog파이프라인(Pipeline) 규칙중간무료 (오픈소스) / 유료
QRadarsyslog / WinCollectDSM 자동낮음높음 (라이선스)
# 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_AUDITy없음기본 감사 프레임워크. 사용자 공간 메시지 로깅, 넷링크 인터페이스 제공
CONFIG_AUDITSYSCALLyAUDIT시스콜 감사. audit_syscall_entry/exit 후크 활성화. 비활성 시 시스콜 감사 불가
CONFIG_AUDIT_WATCHyAUDITSYSCALL, FSNOTIFY파일 감시 (-w 규칙). fsnotify 기반 개별 파일 변경 감시
CONFIG_AUDIT_TREEyAUDITSYSCALL, FSNOTIFY디렉토리 트리 감시. 재귀적 디렉토리 감시 지원
CONFIG_AUDIT_ARCHy (자동)아키텍처 의존아키텍처별 시스콜 번호 매핑. x86_64에서 32/64비트 구분
CONFIG_AUDIT_LOGINUID_IMMUTABLEnAUDITSYSCALLloginuid(auid) 변경 금지. 한 번 설정 후 재설정 불가
CONFIG_AUDIT_GENERIC아키텍처별AUDITSYSCALL아키텍처 독립적 감사 지원 (일부 아키텍처만)
CONFIG_INTEGRITY_AUDITyAUDIT, INTEGRITYIMA 무결성 검증 감사 이벤트 생성
CONFIG_NETy(간접)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 서브시스템 운영 중 자주 발생하는 문제와 체계적인 진단 방법을 정리합니다.

Audit 트러블슈팅 결정 트리 (문제 유형별 진단 흐름) Audit 트러블슈팅 결정 트리 문제 발생 로그가 생성되지 않음 auditctl -s enabled=1? audit=0 부트? No 규칙 확인 Yes 백로그 초과 (lost > 0) 1. backlog_limit 증가 (-b 65536) 2. 노이즈 프로세스 never 규칙 추가 3. auditd flush=INCREMENTAL_ASYNC auditd 크래시/중단 1. journalctl -u auditd 확인 2. 디스크 공간 확인 (df -h) 3. max_log_file_action 확인 규칙 로드 실패 1. -e 2 (immutable)? 2. 규칙 문법 오류? 3. CAP_AUDIT_CONTROL? 일반적인 에러 메시지와 해결 방법 audit: backlog limit exceeded → backlog_limit 증가 또는 규칙 최적화 audit: audit_lost=N audit_rate_limit → rate_limit을 0으로 변경 또는 값 증가 Error sending add rule request (Rule exists) → 동일 규칙 중복 추가 시도. -D 후 재로드 The audit system is in immutable mode → -e 2 상태. 재부팅 필요 Error sending enable request (EPERM) → CAP_AUDIT_CONTROL 권한 부족. root로 실행 audit: kauditd hold queue overflow → auditd 장기 미응답. auditd 재시작 확인 Error - Loss of audit events → disk_full/disk_error. 로그 로테이션/디스크 확인 Unable to set audit pid (EEXIST) → 다른 auditd 인스턴스 실행 중. kill 후 재시작

진단 명령어 모음

# === 기본 상태 확인 ===
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권한 부족 또는 immutableauditctl -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

외부 참고 자료