리눅스 시스템 기초 · 입문편 — 본문의 "N편"은 입문 과정 번호다. 번호별 글과 전체 250편 구성은 통합 로드맵에서 확인할 수 있다.
리눅스 시스템 기초 48 / 50 · Part 5. 네트워크·보안·SOC
실습 환경: Rocky Linux 9 (10.0.0.200) / Ubuntu 22.04 (10.0.0.210) · journalctl 출력은 형식 예시,secure분석은 21편 샘플 로그의 실제 결과
이전 글: 47. SELinux 이해
이 시리즈에서 로그는 거의 모든 글에 나왔다. 21편 /var/log/secure, 25편 access_log, 34편 audit, 37편 systemctl status 하단의 로그, 38편 /var/log/cron, 39편 OOM 커널 로그, 46편 방화벽 차단 로그, 47편 AVC.
이번 글은 이것들을 하나의 지도 로 정리한다. 관제 요원에게 필요한 질문은 이것이다.
journalctl로 원하는 로그만 빠르게 뽑으려면?| 체계 | 저장 | 형식 | 주요 내용 |
|---|---|---|---|
| systemd-journald | /run/log/journal(휘발) 또는 /var/log/journal(영구) | 바이너리, 필드 구조 | 모든 서비스의 출력, 커널, syslog 메시지 |
| rsyslog | /var/log/* 텍스트 파일 | 한 줄 텍스트 | journald에서 받아 용도별 파일로 분류, 원격 전송 |
| auditd | /var/log/audit/audit.log | key=value | 커널 감사: execve, 파일 감시, 로그인, AVC(47편) |
RHEL 9와 Ubuntu 22.04 모두 journald와 rsyslog를 함께 쓴다. journald가 먼저 받고, rsyslog가 텍스트 파일로 저장한다. 그래서 같은 sshd 로그가 journalctl -u sshd와 /var/log/secure 양쪽에 있다.
journal이 영구 저장되는지는 /var/log/journal 디렉터리 존재 여부와 journald.conf의 Storage= 설정에 따라 다르다. 휘발 모드면 재부팅 시 저널이 사라진다.
| 내용 | RHEL / Rocky | Ubuntu / Debian |
|---|---|---|
| 인증 (sshd, sudo, su, PAM) | /var/log/secure | /var/log/auth.log |
| 일반 시스템 | /var/log/messages | /var/log/syslog |
| cron | /var/log/cron | syslog 안의 CRON |
| 커널 | messages (+ journalctl -k) | /var/log/kern.log |
| 패키지 설치 | /var/log/dnf.log | /var/log/dpkg.log, apt/history.log |
| 감사 | /var/log/audit/audit.log | 같음 (auditd 설치 시) |
| 로그인 기록 (바이너리) | /var/log/wtmp(성공) · btmp(실패) · lastlog | 같음 |
wtmp/btmp는 텍스트가 아니므로 last, lastb, lastlog로 읽는다(10·18편).
rsyslog는 메시지를 facility(출처 분류) 와 severity(심각도) 로 나눠 파일에 보낸다.
# RHEL /etc/rsyslog.conf 일부
authpriv.* /var/log/secure
cron.* /var/log/cron
*.info;mail.none;authpriv.none;cron.none /var/log/messages
| severity | 번호 | journalctl -p |
|---|---|---|
| emerg / alert / crit | 0–2 | 시스템 중단급 |
| err | 3 | 오류 |
| warning | 4 | 경고 |
| notice / info | 5–6 | 일반 |
| debug | 7 | 디버그 |
authpriv는 비밀번호 등 민감한 인증 정보 용 facility라서 root만 읽을 수 있는 secure에 따로 저장된다.

devuser가 SSH로 로그인하면:
Accepted password ... 메시지를 syslog API로 보낸다(facility authpriv)._PID, _UID, _SYSTEMD_UNIT=sshd.service 등)와 함께 저널에 저장한다./var/log/secure(Ubuntu: auth.log)에 한 줄로 쓰고, 설정되어 있으면 SIEM으로 전송한다.wtmp에 로그인 기록을 남긴다(last로 보임).USER_LOGIN 이벤트를 audit.log에 남긴다.한 번의 로그인이 최소 3~4곳에 흔적을 남긴다. 공격자가 한 곳을 지워도 다른 곳과 대조하면 공백이 드러난다.
21편 샘플 로그의 실제 한 줄이다.
Sep 23 02:19:21 rocky sshd[5224]: Accepted password for devuser from 10.0.0.128 port 51514 ssh2
└── 시각 ───┘ └호스트┘ └프로그램[PID]┘ └──────────────── 메시지 ─────────────────┘
전통적인 syslog 시각에는 연도와 시간대가 없다. 여러 서버의 로그를 비교할 때 시계가 어긋나 있으면 순서가 뒤바뀐다. 그래서 모든 서버를 NTP(chrony)로 동기화 하고, 분석할 때는 journalctl -o short-iso처럼 시간대가 포함된 형식을 쓴다.
journald는 메시지를 필드 단위로 저장하므로 grep보다 정확하게 거를 수 있다.
$ journalctl _SYSTEMD_UNIT=sshd.service _PID=5224 -o short-iso (형식 예시)
2026-09-23T02:19:21+0900 rocky sshd[5224]: Accepted password for devuser from 10.0.0.128 port 51514 ssh2
2026-09-23T02:19:21+0900 rocky sshd[5224]: pam_unix(sshd:session): session opened for user devuser(uid=1001) by (uid=0)
2026-09-23T02:31:21+0900 rocky sshd[5224]: pam_unix(sshd:session): session closed for user devuser
같은 PID(5224)로 묶으니 한 세션의 시작과 끝 이 바로 보인다(02:19:21 ~ 02:31:21, 12분).
# 1) 로그 파일 위치
ls -l /var/log/
sudo tail -f /var/log/secure # Ubuntu: /var/log/auth.log
# 2) journalctl 기본
journalctl -e # 마지막으로 이동
journalctl -f # 실시간
journalctl -b # 이번 부팅 이후
journalctl --list-boots # 부팅 이력 (재부팅 시각 확인)
# 3) 필터
journalctl -u sshd --since "2026-09-23 02:00" --until "2026-09-23 03:00"
journalctl -p err -b # 이번 부팅의 오류 이상
journalctl -k --since today # 커널 (OOM, 방화벽 로그)
journalctl _UID=1001 --since today # 특정 사용자 프로세스의 로그
journalctl _COMM=sudo --since today # sudo 사용 기록
# 4) 출력 형식
journalctl -u sshd -o short-iso --no-pager | tail
journalctl -u sshd -o json-pretty -n 1
# 5) 저장 상태·용량
journalctl --disk-usage
ls -ld /var/log/journal 2>/dev/null || echo "journal 휘발 모드일 수 있음"
# 6) 감사 로그
sudo ausearch -m USER_LOGIN -ts today -i
sudo aureport --login --summary -i
sudo aureport -x --summary # 실행 파일별 요약
# 7) 로그인 기록
last -n 10; sudo lastb -n 10; lastlog | grep -v 'Never'
# 8) 원격 전송 설정 확인
grep -rE '^\*\.\*\s+@@?' /etc/rsyslog.conf /etc/rsyslog.d/ 2>/dev/null
① 샘플 secure 로그 요약 (21편 샘플 로그의 실제 결과)
$ grep -c 'Failed password' secure
113
$ grep 'Accepted' secure | awk '{print $1,$2,$3,$7,$9,$11}'
Sep 23 02:19:21 password devuser 10.0.0.128
Sep 23 09:03:20 publickey roror 10.0.0.10
Sep 23 13:03:56 publickey roror 10.0.0.10
Sep 23 18:17:26 publickey roror 10.0.0.10
정상 관리자(roror)는 업무 시간·공개키·10.0.0.10 에서 접속한다. 02:19의 devuser는 새벽·비밀번호·10.0.0.128 이다. 이 차이가 49편 분석의 출발점이다.
아래 ②·③은 형식 설명용 예시다.
② 로그 삭제·공백 흔적
$ ls -l --time-style=full-iso /var/log/secure
-rw------- 1 root root 0 2026-09-23 02:40:12 /var/log/secure ← 크기 0
$ journalctl --list-boots
0 3f1c... Tue 2026-09-23 02:41:05 KST—Tue 2026-09-23 09:10:00 KST ← 02:41 재부팅
$ last -x | grep -E 'reboot|shutdown' | head -2
reboot system boot 5.14.0-... Tue Sep 23 02:41 still running
secure가 02:40에 비워졌고, 곧바로 재부팅되어 휘발 저널도 사라졌다. 로컬 로그만으로는 02:19~02:40 사이의 행위를 볼 수 없다. SIEM으로 이미 전송된 로그 가 유일한 근거가 된다.
③ 저장 방식 확인
$ journalctl --disk-usage
Archived and active journals take 8.0M in the file system.
$ ls -ld /var/log/journal
ls: cannot access '/var/log/journal': No such file or directory
영구 저널 디렉터리가 없다 → 재부팅하면 저널이 사라진다(rsyslog 텍스트 파일은 남음). 관제 대상 서버라면 /var/log/journal을 만들거나 Storage=persistent로 설정한다.
| 공격 | 흔적 | 대응 |
|---|---|---|
| 로그 파일 삭제·비우기 (T1070.002) | 크기 0, 중간 시간대 공백, rm/truncate audit 기록 | 원격 전송(SIEM), chattr +a(추가만 허용) |
| 로그 서비스 중지 | rsyslog·auditd inactive, signal=KILL (37편) | 서비스 상태 경보 |
| 로그인 기록 조작 | wtmp와 secure 불일치 | 교차 대조 |
| 재부팅으로 휘발 저널 제거 | --list-boots에 새벽 재부팅 | 영구 저널 |
| 디스크 가득 채우기 | /var 100%, 기록 중단 (40편) | 별도 파티션, 용량 경보 |
| 시간 조작 | 로그 순서 역전 | NTP 감시 |
로그의 가치는 "서버 밖에 있을 때" 가장 크다. 공격자가 root를 얻으면 로컬 로그는 무엇이든 지울 수 있다. 그래서 관제 체계의 핵심은 발생 즉시 원격으로 보내는 것 이다.
# /etc/rsyslog.d/90-siem.conf — TCP 로 SIEM 전송 (@@ = TCP, @ = UDP)
*.* @@10.0.0.50:514
S="2026-09-23 02:00"; E="2026-09-23 03:00"; D=/root/evidence/logs_$(date +%Y%m%d_%H%M)
mkdir -p $D
journalctl --since "$S" --until "$E" -o short-iso --no-pager > $D/journal.txt
journalctl -k --since "$S" --until "$E" -o short-iso --no-pager > $D/kernel.txt
sudo cp -p /var/log/secure* /var/log/messages* /var/log/cron* $D/ 2>/dev/null # Ubuntu: auth.log*, syslog*
sudo ausearch -ts "09/23/2026" "02:00:00" -te "09/23/2026" "03:00:00" -i > $D/audit.txt 2>/dev/null
last -F > $D/last.txt; sudo lastb -F > $D/lastb.txt 2>/dev/null
sha256sum $D/* > $D/SHA256SUMS # 무결성 (29편)
ausearch -ts의 날짜 형식은 시스템 로케일을 따른다. 형식이 맞지 않으면 -ts today, -ts recent 같은 키워드를 쓴다.
[Alert] SIEM: 10.0.0.200 Failed password 급증 (secure 기반)
↓
[secure] 02:10~02:19 실패 95회 → 02:19:21 devuser Accepted password
↓
[journal] _PID=5224 → 세션 02:19:21 ~ 02:31:21
↓
[wtmp] last → devuser pts/1 10.0.0.128 02:19 - 02:31 (secure 와 일치하는지)
↓
[audit] auid=1001 의 execve 목록 → 세션 중 실행한 명령
↓
[판단] 소스 간 일치 → 신뢰 / 불일치·공백 → 로그 조작 의심
/var/log/secure, Ubuntu /var/log/auth.log. 일반: messages / syslog.journalctl: -u(유닛), --since/--until, -b, -p, -k, _PID=/_UID=/_COMM=, -o short-iso.다음 글 「49. SSH Brute Force 로그 분석」 에서는 21편의 샘플 secure 로그를 처음부터 끝까지 분석한다. 실패 횟수·출발지·시도 계정·분당 속도를 집계해 무차별 대입인지 판단 하고, 성공한 로그인 을 찾아 그 이후의 행위(sudo 거부, su 실패)를 추적한 뒤, 탐지 기준과 대응(fail2ban, 방화벽, 설정 강화)까지 정리한다.