systemd与DynamicUser UID未知

4

问题

systemd有一个DynamicUser功能,请参见https://www.freedesktop.org/software/systemd/man/systemd.exec.html#DynamicUser=

我还使用了:PermissionsStartOnly=true更改权限,因为这需要root。

然而,尽管 ExecStart 知道该动态用户的正确UID,但是 ExecStartPostExecStartPre 不会知道它,因为它们以root(UID=0)身份运行,所以我不知道如何改变它的所有权。

希望:我想使用systemd的动态用户方面,但是如果不知道UID,我无法将文档的所有权修改为动态用户可以访问。

问题

是否有其他在systemd中可以用来将文件权限映射到此临时用户的方法?

带“静态”用户的代码:

acmeSupplied = fold (identifier: con: if (config.nixcloud.TLS.certs.${identifier}.mode) == "ACME" then con ++ [
  (nameValuePair "nixcloud.TLS-acmeSupplied-${identifier}" (let
    c = config.nixcloud.TLS.certs.${identifier};
    allDomains = concatMapStringsSep " " (x: "--domains=${x}") ( [ c.domain ] ++ c.extraDomains);
    email = if (isString c.email) then c.email else "info@${c.domain}";
    hash = hashIdentifierACMEOptions identifier;
  in {
    description = "nixcloud.TLS: create acmeSupplied certificate for ${identifier}";
    preStart = ''
      mkdir -p ${stateDir}/${identifier}/acmeSupplied/${hash}
      chmod 0750 ${stateDir}/${identifier}/acmeSupplied -R
      chown nc-lego:${filterIdentifier identifier} ${stateDir}/${identifier} -R
    '';
    script = ''
      cd ${stateDir}/${identifier}/acmeSupplied
      ${pkgs.nixcloud.lego}/bin/lego ${allDomains} --email=${email} --exclude=dns-01 --exclude=tls-alpn-01 --webroot=/run/nixcloud/lego/${identifier}/challenges --path=${stateDir}/${identifier}/acmeSupplied/${hash} --accept-tos --server=${c.acmeApiEndpoint} run
      ${pkgs.nixcloud.lego}/bin/lego ${allDomains} --email=${email} --exclude=dns-01 --exclude=tls-alpn-01 --webroot=/run/nixcloud/lego/${identifier}/challenges --path=${stateDir}/${identifier}/acmeSupplied/${hash} --accept-tos --server=${c.acmeApiEndpoint} renew --days 15
    '';
   postStart = ''
      chown nc-lego:${filterIdentifier identifier} ${stateDir}/${identifier} -R
      chmod 0750 ${stateDir}/${identifier}/acmeSupplied -R
    '';
    serviceConfig = {
      #DynamicUser = true;
      User = "nc-lego";
      ReadWritePaths = "-${stateDir}/${identifier}/acmeSupplied";
      SupplementaryGroups = "${filterIdentifier identifier}";
      PermissionsStartOnly = true;
      Type = "oneshot";
      RuntimeDirectory = "nixcloud/lego/${identifier}/challenges";
    };
    before = [ "nixcloud.TLS-acmeSupplied-certificates.target" ];
    wantedBy = [ "nixcloud.TLS-acmeSupplied-certificates.target" ];
  }))
] else con) [] (attrNames config.nixcloud.TLS.certs);

使用“DynamicUser”进行编码:

acmeSupplied = fold (identifier: con: if (config.nixcloud.TLS.certs.${identifier}.mode) == "ACME" then con ++ [
  (nameValuePair "nixcloud.TLS-acmeSupplied-${identifier}" (let
    c = config.nixcloud.TLS.certs.${identifier};
    allDomains = concatMapStringsSep " " (x: "--domains=${x}") ( [ c.domain ] ++ c.extraDomains);
    email = if (isString c.email) then c.email else "info@${c.domain}";
    hash = hashIdentifierACMEOptions identifier;
  in {
    description = "nixcloud.TLS: create acmeSupplied certificate for ${identifier}";
    preStart = ''
      mkdir -p ${stateDir}/${identifier}/acmeSupplied/${hash}
      chmod 0750 ${stateDir}/${identifier}/acmeSupplied -R
      chown nixcloud.TLS-acmeSupplied-mail.nix.lt:${filterIdentifier identifier} ${stateDir}/${identifier} -R
    '';
    script = ''
      cd ${stateDir}/${identifier}/acmeSupplied
      ${pkgs.nixcloud.lego}/bin/lego ${allDomains} --email=${email} --exclude=dns-01 --exclude=tls-alpn-01 --webroot=/run/nixcloud/lego/${identifier}/challenges --path=${stateDir}/${identifier}/acmeSupplied/${hash} --accept-tos --server=${c.acmeApiEndpoint} run
      ${pkgs.nixcloud.lego}/bin/lego ${allDomains} --email=${email} --exclude=dns-01 --exclude=tls-alpn-01 --webroot=/run/nixcloud/lego/${identifier}/challenges --path=${stateDir}/${identifier}/acmeSupplied/${hash} --accept-tos --server=${c.acmeApiEndpoint} renew --days 15
    '';
   postStart = ''
      chown nixcloud.TLS-acmeSupplied-mail.nix.lt:${filterIdentifier identifier} ${stateDir}/${identifier} -R
      chmod 0750 ${stateDir}/${identifier}/acmeSupplied -R
    '';
    serviceConfig = {
      DynamicUser = true;
      ReadWritePaths = "-${stateDir}/${identifier}/acmeSupplied";
      SupplementaryGroups = "${filterIdentifier identifier}";
      PermissionsStartOnly = true;
      Type = "oneshot";
      RuntimeDirectory = "nixcloud/lego/${identifier}/challenges";
    };
    before = [ "nixcloud.TLS-acmeSupplied-certificates.target" ];
    wantedBy = [ "nixcloud.TLS-acmeSupplied-certificates.target" ];
  }))
] else con) [] (attrNames config.nixcloud.TLS.certs);

错误信息:
mailserver-nix-lt> updating GRUB 2 menu...
mailserver-nix-lt> activating the configuration...
mailserver-nix-lt> setting up /etc...
mailserver-nix-lt> setting up tmpfiles
mailserver-nix-lt> reloading the following units: dbus.service
mailserver-nix-lt> warning: the following units failed: nixcloud.TLS-acmeSupplied-mail.nix.lt.service
mailserver-nix-lt> 
mailserver-nix-lt> ● nixcloud.TLS-acmeSupplied-mail.nix.lt.service - nixcloud.TLS: create acmeSupplied certificate for mail.nix.lt
mailserver-nix-lt>    Loaded: loaded (/nix/store/i4nxkvw8bf9vs2brhj3lyjakxklq0rxg-unit-nixcloud.TLS-acmeSupplied-mail.nix.lt.service/nixcloud.TLS-acmeSupplied-mail.nix.lt.service; enabled; vendor preset: enabled)
mailserver-nix-lt>    Active: failed (Result: exit-code) since Thu 2018-10-11 10:55:46 CEST; 22ms ago
mailserver-nix-lt>   Process: 20613 ExecStartPre=/nix/store/c69ccjnc2n5y6g1p9q168kjlgf2w3l10-unit-script/bin/nixcloud.TLS-acmeSupplied-mail.nix.lt-pre-start (code=exited, status=1/FAILURE)
mailserver-nix-lt>  Main PID: 20243 (code=exited, status=0/SUCCESS)
mailserver-nix-lt> 
mailserver-nix-lt> Oct 11 10:55:46 mail.nix.lt systemd[1]: Starting nixcloud.TLS: create acmeSupplied certificate for mail.nix.lt...
mailserver-nix-lt> Oct 11 10:55:46 mail.nix.lt nixcloud.TLS-acmeSupplied-mail.nix.lt-pre-start[20613]: chown: invalid user: ‘nixcloud.TLS-acmeSupplied-mail.nix.lt:nc-mail-nix-lt’
mailserver-nix-lt> Oct 11 10:55:46 mail.nix.lt systemd[1]: nixcloud.TLS-acmeSupplied-mail.nix.lt.service: Control process exited, code=exited status=1
mailserver-nix-lt> Oct 11 10:55:46 mail.nix.lt systemd[1]: nixcloud.TLS-acmeSupplied-mail.nix.lt.service: Failed with result 'exit-code'.
mailserver-nix-lt> Oct 11 10:55:46 mail.nix.lt systemd[1]: Failed to start nixcloud.TLS: create acmeSupplied certificate for mail.nix.lt.
mailserver-nix-lt> error: Traceback (most recent call last):
  File "/nix/store/ixarqxfbhr06fp8y8pj5dcm1rhar2j15-nixops-1.6/lib/python2.7/site-packages/nixops/deployment.py", line 731, in worker
    raise Exception("unable to activate new configuration")
Exception: unable to activate new configuration

根据文档对于DynamicUser的说明:
If these options are not used and
           dynamic user/group allocation is enabled for a unit, the name of
           the dynamic user/group is implicitly derived from the unit name.
           If the unit name without the type suffix qualifies as valid user
           name it is used directly, otherwise a name incorporating a hash
           of it is used.

但是这个哈希是什么呢?
1个回答

4
然而,虽然 ExecStart 知道该动态用户的正确 UID,但是由于 ExecStartPost 和 ExecStartPre 作为 root(UID=0)运行,它们不知道该 UID,因此我不知道如何进行 chown。我认为这不是真的 - ExecStartPre 和 ExecStartPost 与主要可执行文件使用相同的 User 和 Group(以及相同的 CapabilityBoundingSet、SystemCallFilter 等等),除非以不同的方式配置(使用 +、! 或 !! 前缀 - 参见 man 5 systemd.service)。我用这个测试服务 进行了测试
希望:我想使用 systemd 的动态用户特性,但是由于不知道 UID,我无法进行 chown,以便动态用户可以访问这些文档
这不是必需的。您的服务应该将状态存储在其StateDirectory=中,运行时文件存储在其RuntimeDirectory=中,缓存数据存储在其CacheDirectory=中,日志存储在其LogsDirectory=中(如果它有自己的日志记录-但考虑使用journal),并从其ConfigurationDirectory=读取配置(但无论如何都不能向服务写入)。systemd会自动为您管理这些目录的所有权,并遵循标准UNIX约定(它们是/var/lib/run/var/cache/var/log/etc的子目录-请参见man 5 systemd.execthis blog post了解详细信息)。
如果您的守护程序不能限制在这些标准目录中,那么最简单的解决方案可能是不使用DynamicUser= - 对于更复杂的设置,使用静态分配的用户没有问题。但是请考虑通过systemd-sysusers创建用户(参见man 5 sysusers.d),而不是直接调用adduser/useradd,特别是如果您正在编写一个发行包,这样可以通过检查哪个包拥有相应的systemd-sysusers配置文件来确定安装了哪个包。

所涉及的服务执行了Let's Encrypt ACME客户端“lego”,而nginx(反向代理)必须能够读取文件。因此,我们按照您推荐的方式实现了它:新用户称为“nixcloud-lego-user”。感谢您的帮助! - qknight
为了使文件在服务之间可访问,我有时会设置UMask=0002(这样文件默认是组可写的),然后将两个服务都设为同一组的成员。也许你也可以尝试这样做? - Lucas Werkmeister

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接