换了SSL Cert之后,Nginx无法启动,发生如下错误。

nginx: [emerg] cannot load certificate “/etc/nginx/ssl/test.crt”: BIO_new_file() failed (SSL: error:0200100D:system library:fopen:Permission denied:fopen(’/etc/nginx/ssl/test.crt’,‘r’) error:2006D002:BIO routines:BIO_new_file:system lib)

  • 确认使用 sudo 运行。
  • 确认该文件可以 cat 打开。
  • 确认文件权限与原Cert一致。
  • nginx -t successful.

查了一下,原来是 SELinux 的问题。

SELinux,即 Security Enhanced Linux,是一种基于委任式存取控制 (Mandatory Access Control, MAC)的权限控制系统,比通常所理解的用户自主式存取控制 (Discretionary Access Control, DAC)更严格。

DAC 主要根据程序的拥有者和文件的rwx权限来决定用户可以进行的操作,但 root 可以控制一切,777文件可以被任何人操作。

MAC 可以通过规则限定特定的程序只能操作指定的文件,这样就算是 root 运行的程序,也不能随意访问其他不相关的文件了。

SELinux 默认使用 targeted模式。

getenforce

sestatus -v

检查 Audit log 可以发现,文件不能访问的原因,是程序与目标文件的 scontext(Security Context) 不一致。

Nginx 使用的是httpd_t,自己copy的文件使用的是user_home_t

导致这个问题的操作是,先在 home 下创建了文件,然后再 mv 到当前目录,而 scontext 不会因复制移动而修改。

$ sudo ausearch -m avc -ts today

time->Thu Apr  9 12:00:42 2020
type=PROCTITLE msg=audit(1586404842.411:635786): proctitle=2F7573722F7362696E2F6E67696E78002D63002F6574632F6E67696E782F6E67696E782E636F6E66
type=SYSCALL msg=audit(1586404842.411:635786): arch=c000003e syscall=2 success=no exit=-13 a0=55ba2565c54d a1=0 a2=1b6 a3=24 items=0 ppid=1 pid=65228 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="nginx" exe="/usr/sbin/nginx" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1586404842.411:635786): avc:  denied  { read } for  pid=65228 comm="nginx" name="test.crt" dev="dm-0" ino=136402657 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file permissive=0

查看测试 Cert 与原来版本的区别。

$ sudo ls -lrtZ /etc/nginx/ssl
-rw-r--r--. root root system_u:object_r:httpd_config_t:s0 origin.crt
-rw-r--r--. root root system_u:object_r:httpd_config_t:s0 origin.key
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 test.crt
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 test.key

使用 restorecon 让文件恢复正确的 SELinux type。

$ sudo restorecon -v -R /etc/nginx/ssl/test.*
restorecon reset /etc/nginx/ssl/test.crt context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_config_t:s0
restorecon reset /etc/nginx/ssl/test.key context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_config_t:s0
$ sudo ls -lrtZ /etc/nginx/ssl
-rw-r--r--. root root system_u:object_r:httpd_config_t:s0 origin.crt
-rw-r--r--. root root system_u:object_r:httpd_config_t:s0 origin.key
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 test.crt
-rw-r--r--. root root unconfined_u:object_r:httpd_config_t:s0 test.key

可以使用 semanage 查询和修改默认的目录安全性本文,此即restorecon 恢复的所谓正确 SELinux type 的来源。

$ sudo semanage fcontext -l|grep etc/nginx
/etc/nginx(/.*)?                                   all files          system_u:object_r:httpd_config_t:s0

重启 Nginx , 成功!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐