问题概述
在编写巡检脚本,通过nginx -t参数获取nginx的配置文件时,在执行nginx -t命令后,发现proxy_temp目录权限发生了变化,目录权限修改为nobody
问题原因
nginx -t命令的含义:
-t — test the configuration file: nginx checks the configuration for correct syntax, and then tries to open files referred in the configuration.
从官方的解释可以看到nginx -t命令执行:检查当前nginx配置文件语法是否正确,然后尝试去打开配置文件中引用的文件。
怀疑是执行nginx -t命令修改了目录权限。
测试模拟如下:
环境说明:使用ultimatech用户启动nginx,然后使用root用户执行nginx -t命令。
通过上图可以可以看到使用root用户执行nginx -t命令后,发现临时文件temp文件目录权限修改为nobody了。
Nginx源码分析
首先查看nginx -t命令输出内容:
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
查看nginx.c源码文件,因为执行的命令为nginx -t,源码首先先去校验传入的参数执行的函数为:ngx_get_options代码如下;
int ngx_cdecl
main(int argc, char *const *argv)
{
……
if (ngx_get_options(argc, argv) != NGX_OK) {
return 1;
}
……
cycle = ngx_init_cycle(&init_cycle);
if (cycle == NULL) {
if (ngx_test_config) {
ngx_log_stderr(0, “configuration file %s test failed”,
init_cycle.conf_file.data);
}
return 1;
}
if (ngx_test_config) {
if (!ngx_quiet_mode) {
ngx_log_stderr(0, "configuration file %s test is successful",
cycle->conf_file.data);
}
}
static ngx_int_t
ngx_get_options(int argc, char *const *argv)
{
case 't':
ngx_test_config = 1;
break;
}
执行ngx_get_options,会将变量ngx_test_config设置为1。程序继续执行 ngx_init_cycle函数
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
{
……
if (ngx_test_config && !ngx_quiet_mode) {
ngx_log_stderr(0, “the configuration file %s syntax is ok”,
cycle->conf_file.data);
}
……
if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
goto failed;
}
}
从nginx -t输出内容中可以看到程序代码执行了上面的逻辑,代码继续执行ngx_create_paths操作,该函数中存在chown操作,函数具体实现如下:
ngx_int_t
ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user)
{
……
//###
for (i = 0; i < cycle->paths.nelts; i++) {
if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
ngx_log_stderr(0, "nginx create paths start continue ");
continue;
}
if (fi.st_uid != user) {
if (chown((const char *) path[i]->name.data, user, -1) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"chown(\"%s\", %d) failed",
path[i]->name.data, user);
return NGX_ERROR;
}
}
……
}
}
标红代码为nginx -t命令权限验证。
首先去检验配置文件中的user,如果使用普通用户执行时,配置文件中的user会被忽略,if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT)这个判断语句执行成功,ngx_create_paths执行结束,不会对文件进行修改。
但是如果使用root用户执行时,配置文件中如果配置了user选项,user的值会被赋予配置文件中的值,如果user值没有配置,默认用户为nobody。所以if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT)这个代码逻辑就不会执行。程序会进行下面的校验if (fi.st_uid != user),fi.st_uid这个值为当前文件所属用户。如果这个所属用户与配置文件中指定的用户不相同,程序就会执行chown操作,将文件属性修改为配置文件中定义用户。
使用strace命令跟踪
使用操作系统命令strace命令跟踪nginx -t命令
从输出的跟踪文件strace.log文件中可以看到使用root用户执行的时候,会发现存在chown的操作,将文件目录修改nobody
结论
按照官网对nginx -t命令的解释,该命令只是去检查配置文件语法,并打开配置文件中预定义文件,因此该命令不会对文件目录权限进行修改,但是在实际测试过程中发现使用普通用户运行nginx服务,nginx服务目录权限修改普通用户, nginx配置文件nginx.conf中没有配置user xxx内容,在使用root用户执行nginx -t命令时会将临时文件(fastcgi_temp、scgi_temp、uwsgi_temp、client_body_temp、proxy_temp)目录修改为nobody,造成启动nginx服务的用户没有*_temp目录的权限,应用部分页面无法访问。
Nginx临时目录权限修改触发条件:
1)nginx服务进程使用非root和nobody用户启动,
2)nginx配置文件nginx.conf中没有配置user xxx内容;
3)使用root用户执行nginx -t命令;
解决方案
在nginx配置文件nginx.conf文件中添加user配置项,添加user配置项,服务启动的时候会出现warning,但是对服务没有任何影响。
告警信息如下:
nginx: [warn] the “user” directive makes sense only if the master process runs with super-user privileges, ignored in /usr/local/nginx1.20/conf/nginx.conf:2