리눅스 시스템 기초 · 입문편 — 본문의 "N편"은 입문 과정 번호다. 번호별 글과 전체 250편 구성은 통합 로드맵에서 확인할 수 있다.

리눅스 시스템 기초 47 / 50 · Part 5. 네트워크·보안·SOC
실습 환경: Rocky Linux 9 (10.0.0.200, SELinux enforcing) / Ubuntu 22.04 (AppArmor) · 이 글의 출력은 모두 형식 설명용 예시
이전 글: 46. Firewalld 이해

1. 들어가며

15·17편에서 파일 권한(rwx)과 소유자를 배웠다. 이 방식을 DAC(Discretionary Access Control, 임의 접근 제어) 라고 한다. 파일 주인이 권한을 정하고, root는 그 권한을 무시할 수 있다.

DAC에는 두 가지 한계가 있다.

  1. root는 사실상 모든 것을 할 수 있다. root 권한으로 실행되는 서비스가 탈취되면 모든 파일이 위험하다.
  2. 프로세스가 무엇을 하려는지는 보지 않는다. apache 계정에 읽기 권한이 있는 파일이면, 그것이 웹 페이지이든 웹셸이 훔치려는 설정 파일이든 똑같이 허용된다.

SELinux 는 여기에 두 번째 관문을 추가한다. "이 종류의 프로세스가 이 종류의 파일에 이 동작을 해도 되는가"를 시스템 정책으로 강제한다. 이를 MAC(Mandatory Access Control, 강제 접근 제어) 라고 한다.

이번 글에서 주의할 점: SELinux(RHEL 계열 기본)와 AppArmor(Ubuntu 기본)는 목적은 같지만 동작 방식이 다르다. 둘을 혼동하지 않도록 마지막에 따로 비교한다.


2. 핵심 개념

2-1. 보안 컨텍스트

SELinux는 모든 프로세스, 파일, 포트에 라벨(컨텍스트) 을 붙인다.

system_u : object_r : httpd_sys_content_t : s0
 사용자      역할          타입(type)          보안 수준

실무에서 거의 모든 판단은 세 번째 필드인 타입 으로 한다. 프로세스의 타입은 도메인 이라고도 부른다.

대상확인 명령예
프로세스ps -eZ, id -Zhttpd_t, sshd_t, 로그인 사용자는 unconfined_t
파일ls -Z/var/www/html → httpd_sys_content_t, /etc/shadow → shadow_t
포트semanage port -lhttp_port_t → 80, 443, 8080 등

2-2. Type Enforcement

정책은 "도메인 A가 타입 B에 대해 어떤 동작을 허용하는가"의 목록이다.

규칙 (개념)결과
httpd_t → httpd_sys_content_t : read허용 — 웹 페이지 제공
httpd_t → shadow_t : read규칙 없음 → 거부
httpd_t → http_port_t : bind허용 — 80/443에서 대기
httpd_t → 임의 포트 : connect부울 httpd_can_network_connect가 켜져야 허용

허용 규칙이 없으면 거부 가 기본이다. 그래서 웹 서버가 root 권한으로 탈취되어도 httpd_t 도메인에 갇혀 있는 한 /etc/shadow를 읽거나 임의 외부로 연결하기 어렵다.

2-3. 모드

모드동작용도
enforcing정책 위반을 차단 하고 기록운영 기본값
permissive차단하지 않고 기록만문제 분석, 정책 개발
disabled동작 안 함권장하지 않음. 켜고 끌 때 재부팅·재라벨링 필요

setenforce 0/1은 enforcing ↔ permissive를 즉시(재부팅 전까지) 바꾸고, 영구 설정은 /etc/selinux/config의 SELINUX=다.

2-4. 부울(Boolean)

정책을 다시 작성하지 않고 켜고 끌 수 있는 스위치다.

부울켜면
httpd_can_network_connect웹 서버가 외부로 네트워크 연결 가능
httpd_can_network_connect_db웹 서버가 DB 포트로 연결 가능
httpd_enable_homedirs사용자 홈 디렉터리 웹 제공

3. 동작 원리

SELinux — 권한(DAC)을 통과해도 정책(MAC)이 한 번 더 막는다

접근 요청은 커널에서 다음 순서로 검사된다.

  1. DAC 검사 — 소유자·그룹·rwx(15편). 여기서 거부되면 끝(SELinux까지 가지 않음).
  2. SELinux 검사 — 커널의 LSM(Linux Security Module) 훅이 프로세스 도메인과 대상 타입을 정책에서 조회한다. 결과는 캐시(AVC, Access Vector Cache)에 저장된다.
  3. 거부되면 AVC 거부 메시지 가 audit 로그에 남는다.
type=AVC msg=audit(1758562387.412:913): avc:  denied  { read } for  pid=7900 comm="cat"
  name="shadow" dev="dm-0" ino=16797
  scontext=system_u:system_r:httpd_t:s0
  tcontext=system_u:object_r:shadow_t:s0 tclass=file permissive=0
필드의미
denied { read }거부된 동작
pid, comm누가 (프로세스 ID, 명령 이름)
name, ino무엇을
scontext주체(프로세스) 컨텍스트 — httpd_t
tcontext대상(파일) 컨텍스트 — shadow_t
tclass대상 종류 (file, dir, tcp_socket …)
permissive=0enforcing 상태에서 실제로 차단됨 (1이면 기록만)

이 한 줄을 사람이 읽으면: "웹 서버 도메인의 프로세스가 cat으로 /etc/shadow를 읽으려다 차단되었다." 웹 서버가 cat /etc/shadow를 실행할 이유는 없으므로, 웹셸이나 RCE로 명령을 실행한 흔적 이다. SELinux는 막았을 뿐 아니라 공격 시도를 기록 했다.


4. 실습

# 1) 상태
getenforce
sestatus
grep ^SELINUX= /etc/selinux/config

# 2) 컨텍스트 확인
id -Z
ps -eZ | grep -E 'httpd|sshd'
ls -Z /var/www/html /etc/shadow
sudo semanage port -l | grep http_port_t

# 3) AVC 거부 로그
sudo ausearch -m AVC -ts recent
sudo ausearch -m AVC -ts today -i | grep -E 'scontext|tcontext|comm' | head
sudo sealert -a /var/log/audit/audit.log       # setroubleshoot 설치 시, 원인과 해결책 제안

# 4) 흔한 문제: 다른 곳에서 옮긴 파일의 라벨이 틀림
sudo mv /root/index.html /var/www/html/        # mv 는 원래 라벨(admin_home_t 등) 유지
ls -Z /var/www/html/index.html
sudo restorecon -v /var/www/html/index.html    # 정책에 맞는 라벨로 복원

# 5) 사용자 지정 경로를 웹 콘텐츠로 등록
sudo semanage fcontext -a -t httpd_sys_content_t '/srv/web(/.*)?'
sudo restorecon -Rv /srv/web

# 6) 부울
getsebool -a | grep httpd_can_network
sudo setsebool -P httpd_can_network_connect_db on    # -P : 영구

# 7) 비표준 포트 허용
sudo semanage port -a -t http_port_t -p tcp 8088

# Ubuntu AppArmor
sudo aa-status
ls /etc/apparmor.d/
sudo journalctl -k | grep 'apparmor="DENIED"' | tail

5. 결과 분석

아래 출력은 형식 설명용 예시다.

① 운영 장애: 옮긴 파일의 라벨

$ ls -Z /var/www/html/index.html
unconfined_u:object_r:admin_home_t:s0 /var/www/html/index.html

type=AVC ... avc: denied { read } for pid=946 comm="httpd" name="index.html"
  scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file permissive=0

권한(rwx)은 맞는데 웹 페이지가 403이다. mv는 원래 위치(/root)의 라벨을 그대로 가져오므로 httpd_t가 읽을 수 없다. 해결은 setenforce 0이 아니라 restorecon 이다.

② 보안 사건: 웹 서버의 외부 연결 차단

type=AVC ... avc: denied { name_connect } for pid=7811 comm="sysd" dest=3333
  scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0

httpd_t 도메인에서 실행된 sysd가 3333번 포트(채굴 풀, 32·33편 시나리오)로 연결하려다 막혔다. SELinux 덕분에 채굴은 실패했지만, 코드 실행 자체는 이미 일어났다 는 뜻이다. 즉시 침해 조사 대상이다.


6. 보안 관점

상황의미대응
웹·DB 도메인의 AVC 거부 (shadow_t, name_connect, execute)탈취된 서비스가 권한 밖 행동 시도침해 지표 — 조사
setenforce 0 실행 기록, permissive 전환공격자 또는 관리자의 방어 해제 (T1562.001)audit 로그 MAC_STATUS, sudo 로그
/etc/selinux/config의 SELINUX=disabled 변경재부팅 후 해제파일 무결성 감시
부울 변경 (httpd_can_network_connect on)통로 개방getsebool 기준값 비교
"SELinux 끄면 된다"는 운영 관행방어층 하나를 통째로 제거라벨·부울·포트로 해결

7. SOC / 보안관제 활용

7-1. SELinux 점검 세트

getenforce; sestatus | grep -E 'mode|Policy'
sudo ausearch -m AVC -ts today -i 2>/dev/null | grep -oE 'scontext=[^ ]+|tcontext=[^ ]+|comm="[^"]+"' | sort | uniq -c | sort -rn | head
sudo ausearch -m MAC_STATUS,MAC_CONFIG_CHANGE -ts this-week -i     # 모드·부울 변경

7-2. 분석 흐름

[Alert]   SIEM: audit AVC denied — scontext=httpd_t tcontext=shadow_t comm=cat (02:31:12)
   ↓
[의미]    웹 서버 도메인에서 cat /etc/shadow 시도 → 웹셸 명령 실행
   ↓
[트리]    pid → httpd → sh → cat (35편), access_log 02:31 요청 (25편)
   ↓
[결과]    permissive=0 → 차단 성공. 하지만 코드 실행은 발생
   ↓
[Response] 웹셸 제거, 취약점 조치, 같은 시각 다른 AVC·네트워크 연결 확인

8. 핵심 정리

  • DAC(rwx)는 root를 막지 못하고 프로세스의 의도를 보지 않는다. SELinux(MAC) 는 정책으로 한 번 더 막는다.
  • 컨텍스트 user:role:type:level 중 type 으로 판단한다. ps -eZ, ls -Z, semanage port -l.
  • 기본은 허용 규칙이 없으면 거부. 모드는 enforcing(차단) / permissive(기록만) / disabled.
  • 거부 기록은 /var/log/audit/audit.log의 type=AVC. scontext(누가)·tcontext(무엇을)·permissive=0(실제 차단).
  • 문제는 끄지 말고 restorecon → setsebool -P → semanage port 순으로 해결한다.
  • SELinux = 라벨 기반(RHEL), AppArmor = 경로 기반(Ubuntu). 명령·로그 형식도 다르다.

9. 다음 글

다음 글 「48. Linux 로그와 journalctl」 에서는 지금까지 여러 글에 흩어져 나온 로그를 한곳에 정리한다. rsyslog와 systemd-journald의 관계, RHEL과 Ubuntu의 로그 파일 차이, journalctl의 필터(유닛·시간·우선순위·PID), audit 로그, 그리고 로그를 SIEM으로 보내는 구조를 다룬다.


참고 자료

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글