SELinux 접근 거부 진단: AVC 기록부터 파일 레이블 복구까지

SELinux 접근 거부 진단: AVC 기록부터 파일 레이블 복구까지

SELinux 접근 거부 진단: AVC 기록부터 파일 레이블 복구까지

웹 파일을 기존 디렉터리에서 /srv로 옮긴 뒤 httpd가 403을 반환한다고 가정해 보겠습니다. 파일은 읽을 수 있고 서비스도 실행 중이지만, 그렇다고 바로 권한을 넓히거나 SELinux를 비활성화해서는 안 됩니다. 일반 파일 권한, 서비스의 접근 허용 설정, 강제 접근 제어는 서로 다른 세 계층의 검사입니다. 이 글에서는 AlmaLinux 9에 이미 구성된 httpd 테스트 가상 호스트를 대상으로 실패한 요청과 AVC 기록을 연결하고, 파일 레이블을 영구적으로 복구한 뒤 서비스 동작과 접근 경계를 검증합니다.

1. 테스트 범위와 초기 상태 확정

CloudDDR 물리 서버에서는 AlmaLinux 9를 선택할 수 있습니다. 결제 후 콘솔에서 접속 인증 정보를 확인하고 SSH로 접속합니다. 주소가 여러 개라면 첫 번째 주소를 사용합니다. 아래 작업에는 관리자 권한이 필요하며, 격리된 테스트 환경에서만 실행해야 합니다. 기존 운영 디렉터리를 덮어쓰거나 수신 대기 주소 또는 방화벽을 변경하지 않습니다.

httpd가 설치되어 있고 테스트 가상 호스트와 접근 URL이 이미 구성되어 있어야 합니다. 먼저 해당 가상 호스트 설정을 백업하고 기존 DocumentRoot를 기록합니다. 진단 도구가 없다면 해당 패키지를 설치한 뒤 보안 모드와 감사 서비스를 확인합니다.

sudo dnf install policycoreutils-python-utils
getenforce
sestatus
sudo systemctl status auditd --no-pager
sudo semanage fcontext -l -C
sudo semanage permissive -l

전역 모드는 Enforcing이어야 하며, httpd가 실행되는 도메인이 별도로 permissive로 설정되어 있지 않아야 합니다. 감사 서비스가 정상적으로 실행되지 않는다면 먼저 증거 수집 기능을 복구해야 합니다. “로그에 거부 기록이 없다”는 사실만으로 접근이 제한되지 않았다고 판단할 수는 없습니다. 이후 기존 규칙과 이번에 추가한 규칙을 구분할 수 있도록 로컬 레이블 매핑 목록도 저장합니다.

setenforce 0은 복구 완료를 의미하지 않습니다. 강제 검사를 해제한 상태에서 요청이 성공한 것은 진단 단서일 뿐, enforcing으로 되돌린 뒤에도 정상 동작한다는 증거는 아닙니다.

2. 일반 권한과 설정 오류부터 배제

전용 테스트 디렉터리를 만들고, 콘텐츠에는 검증용 표식 한 줄만 넣습니다. 디렉터리는 탐색할 수 있고 파일은 읽을 수 있도록 설정합니다. 이 권한은 공개 테스트 콘텐츠에만 적용하며, 키나 백업, 운영 데이터에는 사용하지 않습니다.

sudo install -d -m 0755 /srv/selinux-lab
printf 'selinux-lab-ok\n' | sudo tee /srv/selinux-lab/index.html
sudo chmod 0644 /srv/selinux-lab/index.html
namei -l /srv/selinux-lab/index.html
ls -ldZ /srv/selinux-lab
ls -lZ /srv/selinux-lab/index.html

기존 테스트 가상 호스트 안에서 문서 루트와 해당 디렉터리의 접근 허용 설정을 다음과 같이 변경합니다.

DocumentRoot "/srv/selinux-lab"

<Directory "/srv/selinux-lab">
    AllowOverride None
    Options -Indexes
    Require all granted
</Directory>

변경하기 전에 설정 파일의 포함 관계를 확인하여 다른 디렉터리 설정 블록이 접근 허용 설정을 덮어쓰지 않는지 살펴봅니다. httpd -t로 구문을 검사하고, httpd -S로 요청을 처리할 가상 호스트를 확인합니다. 검사에 통과한 뒤에만 설정을 다시 로드합니다.

Shell 변수 CHECK_URL을 실제 테스트 접근 URL로 설정하고, 경로는 /index.html을 가리키도록 합니다. URL은 해당 가상 호스트와 일치해야 하며, 인증 정보를 URL에 넣어서는 안 됩니다. 요청할 때는 연결 성공 여부만 보지 말고 응답 본문을 확인합니다.

sudo httpd -t
sudo httpd -S
sudo systemctl reload httpd
curl --fail --show-error "$CHECK_URL"

요청이 실패하면 먼저 httpd 오류 로그를 확인합니다. 상위 디렉터리에 실행 권한이 없거나, 요청이 다른 가상 호스트로 전달되거나, 접근 허용 규칙에서 거부되어도 비슷한 현상이 나타날 수 있습니다. 이때 재귀적으로 권한을 대폭 완화해도 레이블 문제는 해결되지 않으며, 노출 범위만 넓어집니다.

3. AVC로 주체·객체·동작 식별

요청이 발생한 시각을 기록하고 실패한 작업을 한 번만 재현한 뒤, 같은 시간대의 거부 기록을 조회합니다.

sudo ausearch -m AVC,USER_AVC -ts recent -i
ps -eZ | grep '[h]ttpd'
matchpathcon -V /srv/selinux-lab/index.html

AVC에서는 scontext, tcontext, tclass와 거부된 권한을 중점적으로 확인합니다. scontext는 접근을 요청한 프로세스의 도메인을, tcontext는 대상 객체의 보안 컨텍스트를 나타냅니다. 파일 읽기와 디렉터리 탐색은 서로 다른 동작이므로 프로세스 이름만으로 판단해서는 안 됩니다.

기록에 나온 경로, 프로세스, 시각을 실패한 요청과 대조해야 합니다. 디렉터리 탐색이 거부되었다면 경로를 구성하는 각 단계의 디렉터리도 확인해야 합니다. 최종 파일만 복구해서는 효과가 없을 수 있습니다. 로그에 경로 정보가 없다면 감사 이벤트 일련번호를 이용해 같은 이벤트에 속한 다른 기록을 확인할 수 있습니다.

AVC가 없다고 해서 SELinux와 무관하다고 단정할 수는 없습니다. 먼저 조회 시간 범위, 감사 상태, 서비스가 실제로 실행되는 프로세스 도메인을 확인합니다. 그래도 관련 증거가 없다면 애플리케이션 설정과 일반 권한 점검으로 돌아가야 하며, 허용 규칙을 무작정 추가해서는 안 됩니다. 과거의 모든 거부 기록을 정책 생성 도구에 넣는 것도 피해야 합니다. 다른 서비스에서 발생한 기록이 섞여 있을 수 있기 때문입니다.

4. 웹 콘텐츠 레이블의 영구 복구

httpd가 읽는 일반 정적 콘텐츠에는 기존 정책에 정의된 httpd_sys_content_t 유형을 사용합니다. 테스트 경로의 레이블이 용도에 맞지 않는다는 증거가 있을 때만 해당 경로에 한정된 매핑을 추가합니다.

sudo semanage fcontext -a -t httpd_sys_content_t \
    '/srv/selinux-lab(/.*)?'
sudo restorecon -Rv /srv/selinux-lab
matchpathcon -V /srv/selinux-lab/index.html
ls -lZ /srv/selinux-lab/index.html

완전히 같은 표현식이 이미 존재한다면 기존 규칙을 확인하고, 필요할 경우 -m으로 수정합니다. 규칙을 계속 덧붙여서는 안 됩니다. 표현식은 테스트 디렉터리만 포함해야 하며, /srv 전체를 웹 콘텐츠 유형으로 변경하지 않습니다. semanage는 경로와 유형의 매핑을 저장하고, restorecon은 그 매핑에 따른 예상 컨텍스트를 기존 파일에 적용합니다.

chcon은 현재 레이블을 직접 변경하지만 영구 매핑을 만들지는 않으므로 이 단계를 대신할 수 없습니다. 나중에 레이블을 다시 적용하면 임시 변경이 되돌려질 수 있습니다.

정적 디렉터리에는 서비스의 쓰기 권한이 필요하지 않습니다. 거부 한 건을 없애려고 모든 콘텐츠를 쓰기 가능한 유형으로 바꾸거나, 관련 없는 불리언 설정까지 활성화해서는 안 됩니다. 실제로 업로드나 캐시 등의 쓰기 작업이 필요하다면 별도 디렉터리를 마련하고, 실제 동작에 맞춰 권한과 레이블을 따로 설계해야 합니다.

5. 복구 결과 검증과 롤백 경로 확보

enforcing을 유지한 상태에서 같은 URL에 다시 접근하여 응답 본문에 selinux-lab-ok가 포함되어 있는지 확인합니다. 동시에 해당 요청과 연관된 새로운 AVC가 발생했는지도 확인합니다. 이어서 restorecon을 다시 실행하고 테스트 서비스를 재시작한 뒤 요청을 반복하여, 복구 결과가 임시 레이블이나 이전 프로세스 상태에 의존하지 않는지 검증합니다.

getenforce
sudo restorecon -Rv /srv/selinux-lab
sudo systemctl restart httpd
curl --fail --show-error "$CHECK_URL"
sudo ausearch -m AVC,USER_AVC -ts recent -i

검증에는 허용되지 않아야 할 동작에 대한 확인도 포함해야 합니다. 존재하지 않는 파일 요청은 실패해야 하고, 테스트 디렉터리는 디렉터리 목록 표시를 허용하지 않아야 합니다. 서비스에 예상하지 않은 수신 대기가 추가되지 않았는지, 로컬 레이블 변경이 정해진 경로에만 적용되었는지도 확인합니다. 이 검사는 각각 애플리케이션 동작, 설정, 변경 범위를 검증하므로 서로 대체할 수 없습니다.

실험을 마칠 때는 먼저 기존 가상 호스트 설정을 복원하고, 구문 검사에 통과한 뒤 설정을 다시 로드합니다. 그다음 테스트 디렉터리를 정리합니다. 이번 작업에서 실제로 새로 추가한 매핑은 삭제할 수 있습니다. 기존 매핑을 수정했다면 기록해 둔 원래 유형으로 되돌려야 합니다. 정리가 끝나면 유지할 경로에 restorecon을 실행합니다.

최종 기록에는 실패한 요청, 관련 AVC, 변경 전후의 레이블, 매핑 표현식, 재시작 후의 응답 결과를 남깁니다. 요청이 한 번 성공한 것은 기능이 복구되었다는 의미일 뿐입니다. 보안 모드가 바뀌지 않았고, 매핑을 재구성할 수 있으며, 접근 범위가 확대되지 않았을 때 비로소 복구 검증이 완료됩니다.

자주 묻는 질문

HTTP 403 응답이면 SELinux가 원인인가요?

단정할 수 없습니다. 디렉터리 통과 권한, 파일 읽기 권한, httpd 접근 설정을 확인하고 실패한 요청을 같은 시간대의 AVC 기록과 연결해야 합니다.

chcon이나 허용 정책 자동 생성을 바로 사용하면 안 되나요?

chcon으로 설정한 레이블은 restorecon 실행 시 바뀔 수 있습니다. 일반 웹 콘텐츠는 semanage fcontext와 restorecon으로 처리합니다. 허용 정책을 만들기 전에 잘못된 레이블, 경로 설정, 기존 정책 불리언을 확인해야 합니다.

AMD EPYC 7543P 단독 사용 물리 서버, 월 $447부터.

물리 서버 구성은 메모리부터 선택하세요

AMD EPYC 7543P, 128GB 및 256GB DDR4-3200 ECC의 두 가지 구성.