Nginx PHP-FPM SELinux 정책 추가 내역

Last Updated on 2월 11, 2021 by 태랑(정현호)



0. SELinux

SELinux(Security-Enhanced Linux)는 관리자가 시스템 액세스 권한을 효과적으로 제어할 수 있게 하는 Linux 시스템용 보안 아키텍처입니다.
이는 원래 미국 국가안보국(United States National Security Agency, NSA)이 LSM(Linux Security Module)을 사용하여 Linux 커널에 대한 일련의 패치로 개발한 것입니다.

SELinux는 2000년에 오픈소스 커뮤니티에 릴리스되어 2003년에 업스트림 Linux 커널로 통합되었습니다.

SELinux는 시스템의 애플리케이션, 프로세스, 파일에 대한 액세스 제어에 관여되며 SELinux 에 액세스할 수 있는 대상을 정하는 룰 세트인 보안 정책을 사용하여 정책에서 허용된 액세스를 실행 하는 보안 모듈 입니다.



1. 시스템 환경

OS : CentOS 7.9
Nginx : 1.19.6
PHP : 8.0.2



2. 에러 발생 상황

PHP 7.4에서 8.0.2 로 변경 테스트 진행 중 설치 완료 후 phpinfo() 를 확인 과정에서 500 internal server error 가 발생하였습니다. Nginx 와 php-fpm 등의 설정에서는 특이 사항이 없었기에 결국 SELinux 로그를 확인 하게 되었습니다.



3. SELinux Audit 로그 내역

최근 사용 하는 리눅스 시스템에서는 SELinux 를 Enable 한 상태로 사용 중이다 보니 예상 되지 않는 곳에서의 에러는 상당수가 SELinux 에 denied  되어서 문제가 발생되는 경우가 많았습니다. 그래서 이번에도 SELinux Audit 를 확인 하였고 역시나 SELinux 에서의 차단된 내역을 확인 할 수 있었습니다.

참고로 이전에 SELinux 에 의한 문제 발생은 아래 포스팅을 참조하시면 됩니다.



3-1. audit.log

먼저 확인 해본 로그는 SELinux 로그인 audit.log 였으며 에러가 발생하는 시점에 발생되는 내역은 아래와 같습니다 php-fpm 커맨드에서 avc: denied { execute } 내용이 명확히 확인되고 있으며 dev="tmpfs" 라는 내용과 httpd_tmpfs_t 등의 주요 내용이 확인 됩니다.
(가로 사이즈 조절을 위해서 개행되어 편집 되어있습니다)

[root]# cd /var/log/audit/audit.log
<...중략...>
type=AVC msg=audit(1612974836.458:658): avc: denied  { execute } for  pid=9999 comm="php-fpm" 
path=2F6465762F7A65726F202864656C6574656429 dev="tmpfs" ino=34728 scontext=system_u:system_r:httpd_t:s0 
tcontext=system_u:object_r:httpd_tmpfs_t:s0 tclass=file permissive=0
type=SYSCALL msg=audit(1612974836.458:658): arch=c000003e syscall=10 success=no exit=-13 a0=48bc1000 
a1=6400000 a2=5 a3=1 items=0 ppid=9993 pid=9999 auid=4294967295 uid=997 gid=994 euid=997 suid=997 
fsuid=997 egid=994 sgid=994 fsgid=994 tty=(none) ses=4294967295 comm="php-fpm" 
exe="/opt/remi/php80/root/usr/sbin/php-fpm" subj=system_u:system_r:httpd_t:s0 key=(null)
type=PROCTITLE msg=audit(1612974836.458:658): proctitle=7068702D66706D3A20706F6F6C20777777
type=ANOM_ABEND msg=audit(1612974836.458:659): auid=4294967295 uid=997 gid=994 ses=4294967295 
subj=system_u:system_r:httpd_t:s0 pid=9999 comm="php-fpm" reason="memory violation" sig=11
<...중략...>




3-2.audit2why

그 다음으로는 에러난 사유 등을 더 자세하게 확인 하기 위하여 audit2why 를 수행하였습니다.
Missing type enforcement (TE) allow rule 메세지로 보았을 때 이번에도 정책 룰이 없기 때문에 발생된 것으로 확인 됩니다.

[root]# audit2why < /var/log/audit/audit.log

type=AVC msg=audit(1612974836.458:658): avc: denied { execute } for  pid=9999 comm="php-fpm" 
path=2F6465762F7A65726F202864656C6574656429 dev="tmpfs" ino=34728 
scontext=system_u:system_r:httpd_t:s0 
tcontext=system_u:object_r:httpd_tmpfs_t:s0 tclass=file permissive=0

   Was caused by:
      Missing type enforcement (TE) allow rule.

      You can use audit2allow to generate a loadable module to allow this access.




3-3. audit2allow

audit2allow -a 명령어를 통해서 해결 가능한 룰이나 명령어 정보를 알아 볼 수 있으며 수행 하였을 때 명령어는 없었으며 추가가 필요한 정책(권한)의 목록만 확인 할 수 있었습니다 명령어로 권한부여가 가능하면 명령어에 대한 정보도 제공됩니다
예시 : #!!!! Fix with $ restorecon -R -v /var/lib/mysql/ibdata1 

[root]# audit2allow -a

#============= httpd_t ==============
allow httpd_t httpd_tmpfs_t:file execute;
allow httpd_t postfix_etc_t:file read;
allow httpd_t self:capability sys_ptrace;




4. semodule 를 통한 정책반영

semodule 를 통해 생성한 정책을 반영 할 수 있습니다. 그 전에 위에서 추가해야할 정책 을 포함하여 te 파일의 작성이 필요 합니다(type enforcement (TE))


4-1. te 파일 작성

아래는 위의 3개 정책 외 추가적으로 SELinux 에서 차단이 되는 정책을 같이 반영하기 위해서 포함된 내역 입니다 nginx-passenger.te 파일을 만들어서 아래 내용을 입력 하면 됩니다.

[root]# vi nginx-passenger.te



module nginx-passenger 1.0;

require {
        type var_run_t;
        type user_home_dir_t;
        type httpd_t;
        type user_home_t;
        type httpd_tmp_t;
        type httpd_tmpfs_t;
        type passenger_exec_t;
        type postgresql_port_t;
        type httpd_log_t;
        type httpd_sys_content_t;
        type postfix_etc_t;
        class process execmem;
        class capability { fowner sys_resource fsetid sys_ptrace };
        class tcp_socket name_connect;
        class file { execute setattr read create execute_no_trans write ioctl open append };
        class capability2 block_suspend;
        class process ptrace;
        class file { ioctl write execute setattr read rename create open getattr execute_no_trans getattr };
        class lnk_file { read getattr };
        class dir { write search read create open getattr add_name };
}

#============= httpd_t ==============

allow httpd_t httpd_tmp_t:file execute;
allow httpd_t httpd_tmpfs_t:file execute;
allow httpd_t httpd_log_t:file setattr;
allow httpd_t passenger_exec_t:dir { search getattr };
allow httpd_t self:capability sys_ptrace;
allow httpd_t self:process ptrace;
allow httpd_t self:capability2 block_suspend;
allow httpd_t user_home_t:file { execute execute_no_trans };
allow httpd_t var_run_t:file { read write };
allow httpd_t postfix_etc_t:file { read getattr open };



4-2. checkmodule

위에서 작성한 te 파일을 통해 checkmodule 를 수행을 합니다 정상적으로 수행된다면 아래와 같이 수행될 것 입니다.

[root]# checkmodule -M -m -o nginx-passenger.mod nginx-passenger.te
checkmodule:  loading policy configuration from httpdtmpexec.te
checkmodule:  policy configuration loaded
checkmodule:  writing binary representation (version 19) to httpdtmpexec.mod



4-3 package 생성 및 허용 정책 적용

semodule_package 과 semodule 명령어를 이용하여 허용 정책을 추가 합니다. 특별한 메세지 없이 종료 된다면 정상적으로 수행된 것입니다. 문제가 있다면 에러가 발생되게 됩니다.

[root]# semodule_package -o nginx-passenger.pp -m nginx-passenger.mod
[root]# semodule -i nginx-passenger.pp




5. 확인

여기 까지 진행 후 다시 한번 phpinfo 를 체크 하였고 audit.log 에서 추가적인 차단 내용 없이 페이지 로드가 정상적으로 수행 되는 것을 확인 하였습니다.




Ref link.
github.com/nginx-passenger.te [Link]


관련된 다른 글

답글 남기기