편집자 주 – “RHEL 6.6 / CentOS 6.6으로 업그레이드할 때의 NGINX: SELinux 변경 사항”이라는 제목의 블로그 게시물은 이 페이지로 리디렉션됩니다. 이 문서에서는 최신의 일반화된 정보를 제공합니다.
최신 Red Hat Enterprise Linux(RHEL) 및 관련 배포판의 Security-Enhanced Linux(SELinux) 기본 설정은 편의성보다 보안을 우선시하기 때문에 매우 엄격할 수 있습니다. 기본 설정에서는 기본 구성으로 실행되는 NGINX Open Source와 NGINX Plus의 작동을 제한하지 않지만, 추가로 구성하는 다른 기능은 SELinux에서 명시적으로 허용하지 않으면 차단될 수 있습니다. 이 문서에서는 발생 가능한 문제와 권장 해결 방법을 설명합니다.
[편집자 주 – 이 문서는 NGINX Open Source와 NGINX Plus 모두에 적용됩니다. 읽기 쉽도록 문서 전체에서 “NGINX”라는 용어를 사용합니다.
CentOS는 원래 RHEL에서 파생된 관련 배포판으로, NGINX와 NGINX Plus에서 지원됩니다. 또한 NGINX Plus는 관련 배포판인 Amazon Linux와 Oracle Linux도 지원합니다. 이러한 배포판의 기본 SELinux 설정은 CentOS 및 RHEL과 다를 수 있으므로 공급업체 설명서를 참조하십시오.]
SELinux 개요
최신 RHEL 및 CentOS 서버에서는 SELinux가 기본적으로 활성화되어 있습니다. 각 운영 체제 객체(프로세스, 파일 디스크립터, 파일 등)에는 해당 객체가 수행할 수 있는 작업과 권한을 정의하는 SELinux 컨텍스트가 지정됩니다. RHEL 6.6/CentOS 6.6 이상에서는 NGINX에 httpd_t 컨텍스트가 지정됩니다:
# ps auZ | grep nginxunconfined_u:system_r:httpd_t:s0 3234 ? Ss 0:00 nginx: master process /usr/sbin/nginx \
-c /etc/nginx/nginx.conf
unconfined_u:system_r:httpd_t:s0 3236 ? Ss 0:00 nginx: worker processThe httpd_t 컨텍스트를 사용하면 NGINX가 일반적인 웹 서버 포트에서 수신 대기하고, /etc/nginx의 구성 파일과 표준 문서 루트 위치(/usr/share/nginx)의 콘텐츠에 액세스할 수 있습니다. 하지만 업스트림 위치로 프록시하거나 소켓을 통해 다른 프로세스와 통신하는 등의 여러 작업은 허용되지 않습니다.
NGINX에 대해 SELinux를 일시적으로 비활성화하기
SELinux가 아닌 운영 체제에서와 동일한 모든 작업을 NGINX가 수행할 수 있도록 httpd_t 컨텍스트에 대한 SELinux 제한을 일시적으로 비활성화하려면 httpd_t 컨텍스트를 permissive 도메인에 할당합니다. 자세한 내용은 다음 섹션을 참조하세요.
# semanage permissive -a httpd_tSELinux 모드 변경
SELinux는 강제, 허용, 또는 비활성화 모드(일명 도메인)로 실행할 수 있습니다. 기본(엄격한) 권한을 위반할 수 있는 NGINX 구성을 변경하기 전에 테스트 환경(사용 가능한 경우) 또는 프로덕션 환경에서 SELinux를 강제 모드에서 허용 모드로 변경할 수 있습니다. 허용 모드에서는 SELinux가 모든 작업을 허용하지만, 강제 모드였다면 보안 정책을 위반했을 작업을 로그에 기록합니다.
To add httpd_t를 허용 도메인 목록에 추가하려면 다음 명령을 실행합니다.
# semanage permissive -a httpd_tTo delete httpd_t를 허용 도메인 목록에서 삭제하려면 다음을 실행합니다:
# semanage permissive -d httpd_t모드를 전역적으로 permissive로 설정하려면 다음을 실행하세요:
# setenforce 0모드를 전역적으로 enforcing으로 설정하려면 다음을 실행합니다:
# setenforce 1SELinux 보안 예외 해결
In permissive 모드에서는 보안 예외가 기본 Linux 감사 로그인 /var/log/audit/audit.log에 기록됩니다. NGINX가 enforcing 모드로 실행될 때만 문제가 발생하는 경우, permissive 모드에서 기록된 예외를 검토하고 이를 허용하도록 보안 정책을 업데이트하십시오.
문제 1: 프록시 연결이 금지됨
기본적으로 SELinux 구성에서는 NGINX가 원격 HTTP, FastCGI 또는 기타 서버에 연결하는 것을 허용하지 않습니다. 이는 다음과 같은 감사 로그 메시지로 확인할 수 있습니다:
type=AVC msg=audit(1415714880.156:29): avc: denied { name_connect } for pid=1349 \
comm="nginx" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket
type=SYSCALL msg=audit(1415714880.156:29): arch=c000003e syscall=42 success=no \
exit=-115 a0=b \a1=16125f8 a2=10 a3=7fffc2bab440 items=0 ppid=1347 pid=1349 \
auid=1000 uid=497 gid=496 euid=497 suid=497 fsuid=497 egid=496 sgid=496 fsgid=496 \
tty=(none) ses=1 comm="nginx" exe="/usr/sbin/nginx" \
subj=unconfined_u:system_r:httpd_t:s0 key=(null)The audit2why 명령은 메시지 코드(1415714880.156:29)를 해석합니다:
# grep 1415714880.156:29 /var/log/audit/audit.log | audit2whytype=AVC msg=audit(1415714880.156:29): avc: denied { name_connect } for pid=1349 \
comm="nginx" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket
Was caused by:
One of the following booleans was set incorrectly.
Description:
Allow httpd to act as a relay
Allow access by executing:
# setsebool -P httpd_can_network_relay 1
Description:
Allow HTTPD scripts and modules to connect to the network using TCP.
Allow access by executing:
# setsebool -P httpd_can_network_connect 1The output from audit2why의 출력에 따르면 httpd_can_network_relay 및 httpd_can_network_connect 부울 옵션 중 하나 또는 둘 다를 활성화하여 NGINX가 프록시 연결을 수행하도록 허용할 수 있습니다. 이러한 옵션은 일시적으로 또는 영구적으로 활성화할 수 있으며, 영구적으로 활성화하려면 출력에 표시된 대로 ‑P 플래그를 추가합니다.
부울 옵션 이해하기
The sesearch 명령은 부울 옵션에 대한 자세한 정보를 제공하며, setools 패키지를 설치하면 사용할 수 있습니다(yum install setools). 여기서는 httpd_can_network_relay 및 httpd_can_network_connect 옵션의 출력을 보여 줍니다.
The httpd_can_network_relay 부울 옵션
다음은 sesearch 명령으로 httpd_can_network_relay 옵션을 조회한 결과입니다:
# sesearch -A -s httpd_t -b httpd_can_network_relayFound 10 semantic av rules:
allow httpd_t gopher_port_t : tcp_socket name_connect ;
allow httpd_t http_cache_client_packet_t : packet { send recv } ;
allow httpd_t ftp_port_t : tcp_socket name_connect ;
allow httpd_t ftp_client_packet_t : packet { send recv } ;
allow httpd_t http_client_packet_t : packet { send recv } ;
allow httpd_t squid_port_t : tcp_socket name_connect ;
allow httpd_t http_cache_port_t : tcp_socket name_connect ;
allow httpd_t http_port_t : tcp_socket name_connect ;
allow httpd_t gopher_client_packet_t : packet { send recv } ;
allow httpd_t memcache_port_t : tcp_socket name_connect ;이 출력은 httpd_can_network_relay가 httpd_t 컨텍스트로 레이블이 지정된 프로세스(예: NGINX)가 http_port_t 유형을 비롯한 다양한 유형의 포트에 연결할 수 있도록 허용함을 나타냅니다:
# semanage port -l | grep http_port_thttp_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000허용된 포트 집합에 포트(여기서는 8082)를 추가로 http_port_t에 등록하려면 다음을 실행합니다:
# semanage port -a -t http_port_t -p tcp 8082이 명령의 출력에 포트가 이미 정의되어 있다고 표시되는 경우(다음 예시 참조), 해당 포트가 다른 집합에 포함되어 있다는 의미입니다. 다른 서비스에 부정적인 영향을 줄 수 있으므로 이 포트를 http_port_t에 다시 할당하지 마십시오.
# semanage port -a -t http_port_t -p tcp 8080
/usr/sbin/semanage: Port tcp/8080 already defined
# semanage port -l | grep 8080
http_cache_port_t tcp 3128, 8080, 8118, 8123, 10001-10010The httpd_can_network_connect 불리언 옵션
다음은 sesearch 명령으로 httpd_can_network_connect 옵션을 조회한 결과입니다:
# sesearch -A -s httpd_t -b httpd_can_network_connectFound 1 semantic av rules:
allow httpd_t port_type : tcp_socket name_connect ;이 출력은 httpd_can_network_connect가 httpd_t 컨텍스트로 레이블이 지정된 프로세스(예: NGINX)가 port_type 속성을 가진 모든 TCP 소켓 유형에 연결할 수 있도록 허용한다는 것을 나타냅니다. 해당 유형을 나열하려면 다음 명령을 실행합니다:
# seinfo -aport_type -x문제 2: 파일 액세스가 금지됨
기본적으로 SELinux 구성은 NGINX가 널리 알려진 허용 위치 외부의 파일에 액세스하는 것을 허용하지 않습니다. 이는 다음과 같은 감사 로그 메시지에서 확인할 수 있습니다:
type=AVC msg=audit(1415715270.766:31): avc: denied { getattr } for pid=1380 \
comm="nginx" path="/www/t.txt" dev=vda1 ino=1084 \
scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=unconfined_u:object_r:default_t:s0 tclass=fileThe audit2why 명령은 메시지 코드(1415715270.766:31)를 해석합니다:
# grep 1415715270.766:31 /var/log/audit/audit.log | audit2whytype=AVC msg=audit(1415715270.766:31): avc: denied { getattr } for pid=1380 \
comm="nginx" path="/www/t.txt" dev=vda1 ino=1084 \
scontext=unconfined_u:system_r:httpd_t:s0 \
tcontext=unconfined_u:object_r:default_t:s0 tclass=file
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.파일 액세스가 금지된 경우 두 가지 옵션이 있습니다.
옵션 1: 파일 레이블 수정
NGINX가 (httpd_t 컨텍스트로 레이블이 지정된 프로세스로서) 파일에 액세스할 수 있도록 파일 레이블을 수정합니다:
# chcon -v --type=httpd_sys_content_t /www/t.txt기본적으로 이 변경 사항은 파일 시스템의 레이블을 다시 지정하면 삭제됩니다. 변경 사항을 영구적으로 적용하려면 다음 명령을 실행합니다:
# semanage fcontext -a -t httpd_sys_content_t /www/t.txt
# restorecon -v /www/t.txt여러 파일의 파일 레이블을 수정하려면 다음을 실행합니다:
# semanage fcontext -a -t httpd_sys_content_t '/www(/.*)?'# restorecon -Rv /www옵션 2: httpd_t 도메인 권한 확장
추가 파일 위치에 대한 액세스를 허용하도록 httpd_t 정책을 확장합니다:
# grep nginx /var/log/audit/audit.log | audit2allow -m nginx > nginx.te# cat nginx.te
module nginx 1.0;
require {
type httpd_t;
type default_t;
type http_cache_port_t;
class tcp_socket name_connect;
class file { read getattr open };
}
#============= httpd_t ==============
allow httpd_t default_t:file { read getattr open };
#!!!! This avc can be allowed using one of these booleans:
# httpd_can_network_relay, httpd_can_network_connect
allow httpd_t http_cache_port_t:tcp_socket name_connect;컴파일된 정책을 생성하려면 -M 옵션을 포함하세요:
# grep nginx /var/log/audit/audit.log | audit2allow -M nginx정책을 로드하려면 semodule -i를 실행한 다음, semodule -l로 성공 여부를 확인합니다:
# semodule -i nginx.pp
# semodule -l | grep nginx
nginx 1.0이 변경 사항은 재부팅 후에도 유지됩니다.
문제 3: NGINX가 추가 포트에 바인딩할 수 없음
기본적으로 SELinux 구성에서는 NGINX가 bind()를 통해 http_port_t 유형에서 허용 목록에 등록된 기본 포트 이외의 TCP 또는 UDP 포트에서 수신 대기하는 것을 허용하지 않습니다:
# semanage port -l | grep http_port_thttp_port_t tcp 80, 443, 488, 8008, 8009, 8443NGINX가 허용 목록에 없는 포트에서 수신 대기하도록 구성하려고 하면(NGINX 구성의 listen 지시문을 http, stream, 또는 mail 컨텍스트에서 사용), NGINX 구성을 검증하거나(nginx -t) 다시 로드할 때 다음 NGINX 로그 항목과 같은 오류가 발생합니다:
YYYY/MM/DD hh:mm:ss [emerg] 46123#0: bind() to 0.0.0.0:8001 failed (13: Permission denied)You can use semanage를 사용하여 원하는 포트(여기서는 8001)를 http_port_t 유형에 추가할 수 있습니다:
# semanage port -a -t http_port_t -p tcp 8001새 구성으로 NGINX를 다시 로드합니다.
# nginx -s reload문제 4: 열려 있는 파일이 너무 많습니다 오류
열 수 있는 파일 수 제한(RLIMIT_NOFILE)을 초과하면 오류 로그에 다음 메시지가 표시됩니다:
Too many files are openNGINX 워커 프로세스에서 오류가 발생하는 경우
대부분의 경우 NGINX 워커 프로세스가 이 오류를 보고하지만, SELinux에서 worker_rlimit_nofile 시스템 호출을 허용하지 않으므로 NGINX setrlimit() 지시문을 사용하여 제한을 늘릴 수 없습니다. 이는 다음 오류 및 감사 로그 메시지에 보고되어 있습니다.
- CentOS/RHEL 7.4 이상에서는 /var/log/nginx/error.log에 다음과 같이 기록됩니다:
YYYY/MM/DD hh:mm:ss [alert] 12066#0: setrlimit(RLIMIT_NOFILE, 2342) failed (13: Permission denied)- CentOS/RHEL 8.0 이상에서는 /var/log/nginx/error.log에서 확인할 수 있습니다:
YYYY/MM/DD hh:mm:ss [alert] 3327#0: setrlimit(RLIMIT_NOFILE, 65535) failed (1: Operation not permitted)- CentOS/RHEL 7.4 이상에서는 /var/log/audit/audit.log에, CentOS/RHEL 8.0 이상에서는 /var/log/messages에 다음과 같이 기록됩니다:
type=AVC msg=audit(1437731200.211:366): avc: denied { setrlimit } for pid=12066 \ comm="nginx" scontext=system_u:system_r:httpd_t:s0 \
tcontext=system_u:system_r:httpd_t:s0 tclass=process제한을 늘리려면 대신 다음 명령을 root 사용자로 실행하세요:
$ setsebool -P httpd_setrlimit 1NGINX 마스터 프로세스에서 오류가 발생하는 경우
NGINX 마스터 프로세스에서 오류가 보고되면 NGINX의 systemd unit 파일을 업데이트해야 합니다. 이렇게 하면 마스터 프로세스와 워커 프로세스 모두에 파일 디스크립터 제한이 설정됩니다.
- Create a directory for the
nginx.service구성을 위한 디렉터리를 생성합니다:
$ mkdir /etc/systemd/system/nginx.service.d- 다음 줄을 추가합니다: /etc/systemd/system/nginx.service.d/nofile_limit.conf:
[Service]LimitNOFILE=65535- systemd 데몬 구성을 다시 로드하고 NGINX를 재시작합니다:
$ systemctl daemon-reload$ systemctl restart nginx.service추가 자료
SELinux는 운영 체제 권한을 관리하기 위한 복잡하고 강력한 기능입니다. 자세한 내용은 다음 문서에서 확인할 수 있습니다.
- 보안 강화 Linux, RHEL 6 또는 RHEL 7
- SELinux (CentOS 사용 방법)
- 보안 강화 Linux 사용자 가이드(Fedora 프로젝트)
- SELinux 프로젝트 홈페이지
- 보안 강화 리눅스 (미국 국가안보국)
작성자 소개

관련 블로그 게시물
시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.
F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.
Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.
진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.
NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.
Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.