[SELinux] recv() failed (104: Connection reset by peer) while reading response header from upstream...

502 Bad Gateway (nginx error)

2022/12/29 02:51:33 [error] 1600#1600: *627 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: xxx.xxx.xxx.xxx, server: www.xxx.xxx, request: "GET / HTTP/2.0", upstream: "fastcgi://unix:/dev/shm/php-fpm.sock:", host: "www.xxx.xxx"

  SELinux를 끄고 운영하고 있는 웹 서버에서 SELinux를 적용해 보려고 'setenforce 1'로 켰더니, PHP 페이지를 열 때 502 bad gateway 오류가 나고 nginx 로그에 위와 같은 오류가 남았다. 웹에서 흔히 볼 수 있는 chcon이나 restorecon 같은 명령어들을 쓰는 SELinux 설정은 할 수 있는 데까지 해 두었고, PHP-FPM 설정도 점검했다. 그럼에도 문제의 원인이나 해결책을 도무지 찾을 수 없었는데, Nginx PHP-FPM SELinux 정책 추가 내역 | Hoing에 나온 방법을 따라해서 오류를 없앨 수 있었다.

  먼저 SELinux를 켜고 오류가 나는 때의 /var/log/audit/audit.log의 내용을 확인해 보았다.

# tailf /var/log/audit/audit.log
...
type=AVC msg=audit(1672253009.531:631): avc:  denied  { execute } for  pid=2260 comm="php-fpm" path=2F6465762F7A65726F202864656C6574656429 dev="tmpfs" ino=40962 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(1672253009.531:631): arch=c000003e syscall=10 success=no exit=-13 a0=55ca48200000 a1=4000000 a2=5 a3=7fb27b5cb240 items=0 ppid=1 pid=2260 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="php-fpm" exe="/usr/sbin/php-fpm" subj=system_u:system_r:httpd_t:s0 key=(null)
type=PROCTITLE msg=audit(1672253009.531:631): proctitle=2F6F70742F72656D692F70687038322F726F6F742F7573722F7362696E2F7068702D66706D002D2D6E6F6461656D6F6E697A65
...

  그리고 audit2why로 오류가 난 까닭을 알아보았다.

# audit2why < /var/log/audit/audit.log
...
type=AVC msg=audit(1672253009.531:632): avc:  denied  { execute } for  pid=2260 comm="php-fpm" path=2F6465762F7A65726F202864656C6574656429 dev="tmpfs" ino=40962 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.

  아무래도 tmpfs를 쓰는 것이 문제가 된 것 같다. 글의 설명에 따라 'audit2allow -a'로 문제를 풀 수 있는 정보를 더 알아보았다.

# audit2allow -a
...
#============= httpd_t ==============

#!!!! This avc is allowed in the current policy
allow httpd_t ephemeral_port_t:tcp_socket name_connect;
allow httpd_t httpd_tmpfs_t:file execute;

#!!!! This avc is allowed in the current policy
allow httpd_t httpd_user_content_t:dir { add_name create remove_name write };

#!!!! This avc is allowed in the current policy
allow httpd_t httpd_user_content_t:file { append create setattr unlink write };
allow httpd_t pki_ca_port_t:tcp_socket name_bind;
allow httpd_t reserved_port_t:udp_socket name_bind;
allow httpd_t tor_port_t:tcp_socket name_bind;

#!!!! This avc is allowed in the current policy
allow httpd_t unreserved_port_t:tcp_socket name_connect;

#!!!! This avc can be allowed using the boolean 'nis_enabled'
allow httpd_t unreserved_port_t:udp_socket name_bind;

#!!!! This avc can be allowed using the boolean 'httpd_read_user_content'
allow httpd_t user_home_t:dir read;
allow httpd_t user_home_t:dir { add_name create remove_name rmdir write };

#!!!! WARNING 'httpd_t' is not allowed to write or create to var_run_t.  Change the label to httpd_var_run_t.
#!!!! $ semanage fcontext -a -t httpd_var_run_t /run/nginx.pid
#!!!! $ restorecon -R -v /run/nginx.pid
#!!!! The file '/run/nginx.pid' is mislabeled on your system.
#!!!! Fix with $ restorecon -R -v /run/nginx.pid
allow httpd_t var_run_t:file { open read unlink write };

#!!!! This avc is allowed in the current policy
allow httpd_t var_run_t:file { read write };

  nginx.pid 파일에 관한 내용은 문제 해결에 도움은 되지 않았다. nginx에 관하여 이미 설정된 정보는 아래처럼 확인해 볼 수 있다.

# semanage fcontext -l | grep run/nginx
/var/run/nginx.* all files system_u:object_r:httpd_var_run_t:s0
/var/opt/rh/rh-nginx18/run/nginx(/.*)? all files system_u:object_r:httpd_var_run_t:s0

  그래도 넣어 보려 했더니, 아래와 같이 /run/nginx.pid를 고칠 수 없어서 /var/run/nginx를 고치라고 나온다.

# semanage fcontext -a -t httpd_var_run_t /run/nginx.pid
ValueError: File spec /run/nginx.pid conflicts with equivalency rule '/run /var/run'; Try adding '/var/run/nginx.pid' instead
# semanage fcontext -a -t httpd_var_run_t /var/run/nginx.pid

  다시 Nginx PHP-FPM SELinux 정책 추가 내역 | Hoing에 나오는 대로 vi로 nginx-passenger.te 파일을 아래처럼 만들었다. 별다른 효과가 없을지도 모르지만, httpd_user_content_t와 httpd_user_rw_content_t를 더 끼워 넣었다.

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 httpd_user_content_t;
type postfix_etc_t;
type var_log_t;
type root_t;
type etc_runtime_t;
type fusefs_t;
type default_t;
type http_cache_port_t;
type unreserved_port_t;
type unconfined_t;
type admin_home_t;
type system_mail_t;
type httpd_sys_rw_content_t;
type httpd_user_rw_content_t;
class process execmem;
class capability { fowner sys_resource fsetid sys_ptrace };
class tcp_socket name_connect;
class shm { associate getattr read unix_read unix_write write destroy };
class file { execute setattr read create execute_no_trans write ioctl open append map };
class capability2 block_suspend;
class process ptrace;
class process setrlimit;
class file { ioctl write execute setattr read rename create open execute_no_trans getattr lock};
class lnk_file { read getattr write open };
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:process execmem;
allow httpd_t self:capability2 block_suspend;
allow httpd_t user_home_t:file { execute execute_no_trans read open write };
allow httpd_t var_run_t:file { read write };
allow httpd_t postfix_etc_t:file { read getattr open };
allow httpd_t root_t:dir write;
allow httpd_t root_t:dir add_name;
allow httpd_t root_t:file create;
allow httpd_t root_t:file { open read write };
allow httpd_t root_t:file lock;
allow httpd_t etc_runtime_t:file write;
allow httpd_t fusefs_t:file { getattr read open write };
allow httpd_t fusefs_t:dir { read write };
allow httpd_t user_home_t:lnk_file { read write open };
allow httpd_t default_t:lnk_file { read write open };
allow httpd_t default_t:file { read write open };
allow httpd_t http_cache_port_t:tcp_socket name_connect;
allow httpd_t unreserved_port_t:tcp_socket name_connect;
allow httpd_t admin_home_t:file getattr;
allow system_mail_t httpd_sys_rw_content_t:file { read write };
allow httpd_t unconfined_t:shm { unix_read unix_write associate getattr read write destroy };
allow httpd_t self:process setrlimit;
allow httpd_t var_log_t:file open;
allow httpd_t root_t:file map;

  그리고 나서 아래처럼 checkmoudle, semodule_package, semodule 명령어를 실행했다.

# checkmodule -M -m -o nginx-passenger.mod nginx-passenger.te
checkmodule: loading policy configuration from nginx-passenger.te
checkmodule: policy configuration loaded
checkmodule: writing binary representation (version 19) to nginx-passenger.mod
# semodule_package -o nginx-passenger.pp -m nginx-passenger.mod
# semodule -i nginx-passenger.pp

  이렇게 하고 나니 SELinux를 켰을 때 웹 페이지가 뜨지 않는 문제가 바로 사라졌다. 웹에서 쓰는 디렉토리들 가운데 tmpfs 기능을 이용한 것이 있어서 Nginx PHP-FPM SELinux 정책 추가 내역 | Hoing에 나오는 방법을 따라한 효과가 난 것 같다. 다만 혹시나 이러면 될까 싶어서 이리저리 바꾼 PHP-FPM 설정 때문에 다른 오류가 나서 이를 되돌리느라 시간은 좀 걸렸다.

2022/12/30 00:34 2022/12/30 00:34
글 걸기 주소 : 이 글에는 글을 걸 수 없습니다.

덧글을 달아 주세요