V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
cathedrel
V2EX  ›  Linux

服务器上的程序,以前可以用 user=nobody 的方式跑起来,现在需要读取证书文件,证书文件是 acme.sh 在 root 权限下生成的,如何设置可以让程序以 nobody 权限读取到证书文件跑起来?

  •  
  •   cathedrel · 2021-09-16 12:20:40 +08:00 · 10312 次点击
    这是一个创建于 924 天前的主题,其中的信息可能已经有所发展或是发生改变。

    acme.sh 生成的证书默认放在 /root/.acme/xxx/xxx 里面

    用 supervisor 管理程序的自启动,原配置里写的 user=nobody,安全用了几年了

    现在程序升级,也想要更高的安全。如果把证书文件(没有移动位置)的权限改为“任何人可读”,不行,程序启动失败(就算启动成功了,acme 自动更新后也要失败的吧,到时候又要操作一番,也麻烦)

    supervisor 的配置改为 user=root 就可以成功读取证书运行程序,只要不爆出漏洞好像也没什么问题,但是从安全角度来讲逼格不够

    所以,大佬们,该怎么操作可以显得有逼格呢?

    32 条回复    2021-09-18 12:01:08 +08:00
    oott123
        1
    oott123  
       2021-09-16 12:59:44 +08:00   ❤️ 1
    再专门建个用户,或者你把证书文件移动到别的地方去,再上个 SELinux 啥的
    zengxs
        2
    zengxs  
       2021-09-16 13:02:03 +08:00
    这个是最基础的文件权限问题
    只有 root 用户可以读取 /root/ 目录下的文件

    还有不建议让 nobody 用户拥有读取证书文件的权限,你感觉「安全用了几年」不代表这个行为就真的安全了
    zengxs
        3
    zengxs  
       2021-09-16 13:06:50 +08:00   ❤️ 1
    参考下这个: https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux

    建议将证书文件放在 /etc/ssl 目录,这个目录只允许 root 读取
    cz5424
        4
    cz5424  
       2021-09-16 13:09:25 +08:00 via iPhone
    新建 nginx 用户,证书授权 nginx 用户可读
    pupboss
        5
    pupboss  
       2021-09-16 13:29:21 +08:00   ❤️ 1
    root 账户直接搞 acme 从根儿上就不是很有逼格了,一般都会有一个日常普通用户的

    想要解决这个问题,最好的办法是用 acme 的 deploy 功能,可以部署到 nginx 甚至用 ssh 部署到其他服务器,在你部署的时候,目标文件夹改好权限 644,覆写的文件权限不会变( root 反正肯定能写进去),这样你的 nobody 可以从 deploy 文件夹读到证书。最好别在 acme 根目录做操作,这和使用 root 账户日常办公一样没逼格
    wffnone
        6
    wffnone  
       2021-09-16 13:49:22 +08:00 via iPhone   ❤️ 1
    你不能脱离场景谈用法。你也不能脱离自己谈习惯。

    Linux 有一些基本的使用规则和基本的操作,用户熟悉了之后,用起来就想喝水用杯子一样自然。只是因为方便,不是因为用杯子就比用手高级。

    如果你要开始实行这些规则,你就要试着去实行这一系列的整体,让它们变成你的习惯,至少是你工作里的保持着一致性的守则(千万别兴趣一来就高级一点,没兴趣就低级一点)。你的目的是为了完成工作,不是显得“高级”(更不必谈这根本不高级)。你的所有的规则应当构成一个整体,你应当自如于其中。这应当是一个有乐趣的自己进步的过程。

    接着往下说,这种乐趣学习的过程,一般来说是阅读文档,阅读他人的项目对这些原则和工具的应用。你需要让自己保持开放心态去学习。而针对(这种如此基础的程度的)具体问题的具体解决方案是有害的,因为如此容易获得的答案反而阻止了你进一步学习,你得到了答案,却错过了一个进步的机会(因为问题给你的动力,能冲到比答案更远的地方)。
    msg7086
        7
    msg7086  
       2021-09-16 13:53:23 +08:00   ❤️ 1

    3. copy/安装 证书
    前面证书生成以后, 接下来需要把证书 copy 到真正需要用它的地方.

    注意, 默认生成的证书都放在安装目录下: ~/.acme.sh/, 请不要直接使用此目录下的文件, 例如: 不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.

    正确的使用方法是使用 --install-cert 命令,并指定目标位置, 然后证书文件会被 copy 到相应的位置


    RTFM

    安装命令里可以 chown 把复制后的文件的所属用户改成 nobody,然后再重启服务就可以了。
    ipwx
        8
    ipwx  
       2021-09-16 13:59:02 +08:00   ❤️ 1
    读完以后 fork 然后 setuid
    hushao
        9
    hushao  
       2021-09-16 14:19:16 +08:00   ❤️ 1
    你用 acme 的姿势是不是不对?我记得 acme 可以安装在用户目录下的,并且不建议直接使用~/.acme.sh/xxx 下的证书,取得证书后要把证书复制到自定义目录。

    查查这个命令 `acme.sh --installcert`
    cathedrel
        10
    cathedrel  
    OP
       2021-09-16 14:43:14 +08:00 via Android
    @zengxs 为什么不让 nobody 用户读取证书? nobody 读取证书后也不能做没让它去做的事情啊
    cathedrel
        11
    cathedrel  
    OP
       2021-09-16 14:43:51 +08:00 via Android
    @zengxs 我倒是想知道哪个目录可以让 nobody 读取?
    cathedrel
        12
    cathedrel  
    OP
       2021-09-16 14:44:22 +08:00 via Android
    @cz5424 系统里都没有安装 nginx
    cathedrel
        13
    cathedrel  
    OP
       2021-09-16 14:46:07 +08:00 via Android
    @pupboss Linux 默认的那些文件夹里面哪个可以直接让 nobody 读取?
    cathedrel
        14
    cathedrel  
    OP
       2021-09-16 14:54:02 +08:00 via Android
    @msg7086 之前是用这样的命令申请到证书的:

    acme.sh --server api.buypass.com/acme/directory --issue -d xxx.com --days 176 --standalone

    申请成功之后应该是自动生成了一个 cron 任务检查证书到期时间并在差不多的时候自动续期对吧?续期的证书也是放在原来的位置。如果现在要改动的话,新命令要怎么写?加上--install-cert /xxx 这一段?那个 chown 的部分应该怎么写呢?不好意思,弱手,您再指点一下
    cathedrel
        15
    cathedrel  
    OP
       2021-09-16 14:57:05 +08:00 via Android
    @ipwx 什么叫读完以后 fork ?完全不懂,setuid 也不懂,您展开说一下好嘛?
    cathedrel
        16
    cathedrel  
    OP
       2021-09-16 14:58:59 +08:00 via Android
    @oott123 服务器上专门建用户的话怎么能做到权限最小同时该有的都有?不太熟悉这块,我是觉得有个 nobody 用户就好好利用
    princelai
        17
    princelai  
       2021-09-16 15:19:05 +08:00
    @cathedrel #14 应该是写在--reload-cmd "chmod a+r xxxx",我这里通常是写 systemctl restart,没在这里写过 chmod
    msg7086
        18
    msg7086  
       2021-09-16 18:37:59 +08:00 via Android
    @princelai 对,虽然我没自己试过,但是应该可以 chown xxx && restart xxx 。

    Install cert 只要执行一次就会写入配置文件的吧,以后自动签发时也会自动安装。
    princelai
        19
    princelai  
       2021-09-16 18:40:59 +08:00
    @msg7086 #18 是的,就写在~/.acme.sh/name.server/name.server.conf 里,写错了自己手动编辑就能改
    lolizeppelin
        20
    lolizeppelin  
       2021-09-16 19:10:29 +08:00
    楼上说的 fork 以后 setuid 就是最标准的做法

    自己翻文档
    guanyin9cn
        21
    guanyin9cn  
       2021-09-16 19:18:30 +08:00
    把证书放到 /opt 下,不要放在 /root 下,这个是 root 用户的 home 目录。
    jim9606
        22
    jim9606  
       2021-09-16 19:52:53 +08:00
    用 nobody 用户跑 acme.sh 就是了。证书目录你可以手动指定一个,建议在 /etc/ssl/ 下面建。
    对于使用 http-01 和 tls-alpn-01 验证的服务器来说 webserver 和 acme 用同一个账户并不会有额外的安全问题。如果你的 webserver 被入侵了,攻击者可以利用这个申请新证书。这跟 acme.sh 的数据被窃取的影响是一样的,所以 acme.sh 不用独立账户并不会额外损失什么。
    adoal
        23
    adoal  
       2021-09-16 21:18:16 +08:00
    运维是一项专门的技能,不是拍拍脑袋就能做好的。
    ysc3839
        24
    ysc3839  
       2021-09-16 21:24:07 +08:00 via Android
    @ipwx @lolizeppelin
    setuid 不需要 fork 吧,之前见过有的程序有 drop root 功能,似乎就没有 fork,是直接调用一下 setuid 的。
    @cathedrel 就是运行时修改进程的用户。
    kaneg
        25
    kaneg  
       2021-09-16 22:33:31 +08:00
    证书 copy 一份到 nobody 能读到的地方很难吗?
    lululau
        26
    lululau  
       2021-09-16 23:31:42 +08:00
    证书应该是对全宇宙公开的啊。。。chmod o+r 就可以了。。。
    cathedrel
        27
    cathedrel  
    OP
       2021-09-17 01:27:15 +08:00
    @kaneg linux 的哪个目录是 nobody 直接可以读的?
    cathedrel
        28
    cathedrel  
    OP
       2021-09-17 07:45:35 +08:00
    @jim9606 acme..sh 没有办法用 nobody 跑起来吧?你试一下看看
    yulgang
        29
    yulgang  
       2021-09-17 09:16:03 +08:00   ❤️ 1
    应该用普通用户签证书,或者签发证书的时候指定--certpath 和--keypath 把证书写到.acme 以外的目录。


    50 0 * * * "/path/to/.acme.sh"/acme.sh --cron --home "/path/to/.acme.sh" --server letsencrypt --certpath /path/to/.cert/cert.pem --keypath /path/to/.cert/key.pem > /dev/null 2>&1
    libook
        30
    libook  
       2021-09-17 10:47:39 +08:00   ❤️ 1
    可以看一下 Linux 的权限机制 https://wiki.archlinux.org/title/Users_and_groups_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

    用户基本分为三类,root 、普通用户、nobody,分别对应所有权限、有限的权限、无权限。

    按照我个人的习惯来说,判断应该使用哪个用户:
    root:尽量不用,基本只有我需要在服务器上调整配置和安装系统软件的时候会用到;
    nobody:如果只需要让程序或脚本访问服务器上所有人( all )都能访问的资源,或者当所有资源都受权限管控的时候不想让程序或脚本访问任何本地资源,那么就用 nobody ;
    普通用户:除了上面需要用 root 和可以用 nobody 的场景以外,基本全都用普通用户。

    每个文件和目录本身会有:
    1. 归属于的用户和归属于的用户组;
    2. 权限标识,按照身份分为自己( user )、群组( group )、所有人( all ),按操作分为读、写、运行权限。
    root 不受权限标识的限制,nobody 只能访问所有人都能访问的资源,普通用户可以访问归属于自己的文件和目录,初次之外具体看权限标识的设定。

    回到题主的情境,签证书可能可以用普通用户和 nobody 来做,所以可以不用 root ;证书文件又属于需要保密的,不能让所有人都能访问,所以不用 nobody,那么最好用普通用户来做。
    即你可以创建一个普通用户,如名叫 signer,同时创建一个存放证书的目录,比如叫 ca ;
    ca 目录和 acme.sh 文件归属于 signer 所有,设定为所有人不能访问、自己可以读、写、运行;
    同时 acme.sh 脚本不需要被群组访问,所以把这个文件单独设定为群组不可访问;
    执行签证书的任务的时候使用 signer 用户来执行 acme.sh 脚本,在 ca 目录下生成证书文件。

    然后确保 ca 下的证书文件和 ca 目录所有者、权限标识一致。

    接下来就是需要用证书的程序了,它们只需要对证书的读权限,所以可以让 signer 和需要读取证书的用户在同一个用户组里,比如叫 ca_ro,并让 ca 目录及其中的证书文件属于 ca_ro 组,且权限标识设定为群组可读、不可写、不可运行。

    至此,就能确保:
    0. 除了 root 以外;
    1. 只有 signer 用户能读写运行 acme.sh 脚本;
    2. 只有 signer 用户能写 ca 目录及其子文件;
    3. 除了 signer 用户以外,所有加入到 ca_ro 群组的用户都能读取 ca 目录及其子文件。
    msg7086
        31
    msg7086  
       2021-09-17 15:56:00 +08:00
    顺带一提,用 nobody 也不算是很好的做法。
    好做法是每个单独的权限个体拥有自己的账号。
    如果你一台服务器就一个网站,那网站应该跑在 www-data 或者 www 下。
    如果你放了很多个独立的网站,那他们应该分别跑在自己的账号下。
    nobody 因为是无权限用户,那就应该以无需读取任何私密信息作为前提。
    当你把文件 chown 到 nobody 或者 chmod 给 all,仅仅是为了给 nobody 读写的时候,这做法就已经不对了。
    julyclyde
        32
    julyclyde  
       2021-09-18 12:01:08 +08:00
    证书文件本来就可读
    关键是密钥要保密
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1112 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 22:49 · PVG 06:49 · LAX 15:49 · JFK 18:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.