天天看点

CentOS 7 设置httpd (apache) 创建文件的umask

(首发于我的博客)

最近在部署网页后端脚本的时候碰到一个关于创建文件的权限问题。

系统版本是CentOS 7,在我的场景中,网页(html/php)由Apache驱动,用户/组为apache/apache。同时后端有一组应用Apps需要以另一个用户(websrv)的身份运行,没有同样使用apache用户是因为涉及到特定软件和环境变量的问题。这些Apps需要在Apache产生的目录中写/改/删文件,同时Apache也需要读取Apps生成的文件。

现在的策略是将websrv用户的group设置为apache,并使websrv和apache用户生成的文件具有group的写权限(g+w),后者是通过设置用户进程的umask实现。

这里[1]介绍了 linux下umask的原理和用法。在我的场景中,就是设置websrv和apache的umask为0002,使创建的目录权限为775,创建的文件权限为664,这样同属一个group的websrv和apache其进程就可以互相往对方创建的目录写文件了。

修改websrv用户的umask很简单,因为这是一个可登录用户,有自己的家目录和配置文件,于是直接修改其用户配置文件,向~/.bashrc文件中加入umask命令即可:

echo 'umask 002' >> ~/.bashrc

重新登录websrv用户(也即

source ~/.bashrc

)或在这之后以websrv用户身份重新运行的进程,其创建目录及文件的umask已经是002了。

但是,Apache的umask的设置需要通过其他方式,一则apache用户并没有自己的配置文件,二则httpd进程是由systemd进程以apache身份运行。于是google了一下,发现不少帖子都提到,CentOS下修改httpd的umask需要在/etc/sysconfig/httpd中加入

umask 002

命令(相应地,在Debian/Ubuntu系是在/etc/apache2/envvars中)。修改之后,

systemctl restart httpd

重启httpd进程。重新测试发现,哦哟,新创建目录的umask仍然不变。这是怎么回事?

排查的过程中首先注意到,/etc/sysconfig/httpd文件中的注释写着,其中内容是以

OPTION = $option

的形式记录。OK,我将

umask 002

改为

UMask = 0002

(大小写及首位多加的0是综合各种google结果而来,略去不表),然后

systemctl restart httpd

重启httpd进程,再测试,WC,新创建目录的umask仍旧岿然不动。WTF?!

尽管原因尚未找到,但网站还需要运行,只好采用前面google到的另一种并不推荐的方案,就是修改httpd的Service配置文件(/usr/lib/systemd/system/httpd.service),向其中

[Service]

块加入

UMask=0002

,然后要先

systemctl daemon-reload

重新加载修改后的配置文件,再

systemctl restart httpd

重启服务(否则会运行不了并报错甩你一脸)。这样一番操作之后再测试,咦,果然可以了。

然而,上面的方式并不优雅也不安全,因为usr/lib/systemd/system/httpd.service是系统文件,有被系统改回去的危险。果不其然,第二天我在这个系统上运行了一次

yum update

,更新了部分软件,结果第三天发现网站异常,一排查,是创建文件夹写权限的问题,再一看httpd的Service配置文件,好嘛,改回去了(而且文件的时间戳都回到了2019-11-27)。真是君子不立危墙之下啊。

那么现在的问题是,如何优雅安全地修改Service文件呢?在这里[2]看到在/etc/systemd/system/下创建httpd.service.d目录并放入自定义额外配置文件的方式,

This was the first result in Google search results for "CentOS 7 apache umask", so I will share what I needed to do to get this work with CentOS 7.

With CentOS 7 the echo "umask 002" >> /etc/sysconfig/httpd -method did not work for me.

I did overwrite the systemd startup file by creating a folder /etc/systemd/system/httpd.service.d and there I created a file umask.conf with lines:

[Service]
UMask=0007
           
Booted and it worked for me

经测试有效,而且这个自定义配置文件不需要修改系统文件并且不会被系统命令覆盖掉,算是一种比较好的方式。

虽然问题算是解决了,但为什么网络上SO/SE/SF等各大IT问答网站大家频繁提到的修改/etc/sysconfig/httpd的方式会无效呢?碰巧的是google过程中在这里[3]看到一个帖子:

With sysV init script, /etc/syconfig/httpd was a bash script which can alter the environment of httpd process.

With systemd, this in no more a bash script, only a list of variables which will be add to the environment, so umask isn't expected to work there.

You must use the systemd UMask option in the service file.

Remember : don't alter provided service file.

Create your own service file : /etc/systemd/system/httpd.service, with

.include /lib/systemd/system/httpd.service
[Service]
UMask = 0002
           

Don't forget to reload systemd daemon using systemctl daemon-reload after editing a unit file.

See http://fedoraproject.org/wiki/Systemd#HowdoIcustomizeaunitfile.2Faddacustomunit_file.3F

这里解释了为什么

umask 002

命令放在/etc/sysconfig/httpd文件中不起作用,因为CentOS 7使用systemd来管理系统服务(systemd作为1号进程,是后面所有启动进程的父进程),而不是CentOS 6中的sysVinit系统,网上流传的CentOS 7的/etc/sysconfig/httpd的改法可能是想当然或者以讹传讹吧。作为引申,可以去这里[4]简要了解sysVinit与systemd管理方式的区别。

最后,还是有一个小问题没有搞清楚。既然CentOS 7下安装httpd确实生成了/etc/sysconfig/httpd这个文件,还煞有介事地在注释中写了如何使用,说明systemd应该是用到了这个文件。即便是systemd不将其作为bash脚本执行,也就是不能直接使用

umask 002

这种命令的方式,那么我之前按照

UMask=0002

的形式写为什么也不起作用呢?

参考内容:

  1. What Is Umask and How to Use It Effectively? ↩︎
  2. Setting the umask of the Apache user ↩︎
  3. setting apache's umask not working in Fedora 16 and 17? ↩︎
  4. SysVinit Vs systemd Cheatsheet ↩︎