systemd 的网络绑定功能

Mac*_*fli 6 networking security systemd vault

我正在部署Goldfish,它是Vault 的一个接口,在专用于机密管理的服务器上进行生产。因此,安全是这里的首要问题。

我正在尝试在 Unbuntu 16.04 系统上使用 systemd 部署服务,为其提供尽可能少的权限。我希望它以非 root 用户身份运行goldfish并侦听端口 443。我尝试了多种选择。


解决方法1:使用systemd插座,在多个帖子建议我发现如这一个(金鱼后端写在去,因为在后)。这似乎是最精确和最安全的,因为它完全由 systemd 管理并为单个服务打开一个端口。我的单元文件如下所示:

  • /etc/systemd/system/goldfish.socket

    [Unit]
    Description=a Vault interface
    
    [Socket]
    ListenStream=443
    NoDelay=true  # Tried with false as well
    
    Run Code Online (Sandbox Code Playgroud)
  • /etc/systemd/system/goldfish.service

    [Unit]
    Description=a Vault interface
    After=vault.service
    Requires=goldfish.socket
    ConditionFileNotEmpty=/etc/goldfish.hcl
    
    [Service]
    User=goldfish
    Group=goldfish
    ExecStart=/usr/local/bin/goldfish -config=/etc/goldfish.hcl
    NonBlocking=true  # Tried with false as well
    
    [Install]
    WantedBy=multi-user.target
    
    Run Code Online (Sandbox Code Playgroud)

不幸的是,我得到一个“listen tcp 0.0.0.0:443: bind: permission denied”。所以看起来它仍然没有得到想要的权限,这似乎违背了为服务创建套接字的目的。我在这里缺少什么?


解决方案 2:为服务提供 CAP_NET_BIND_SERVICE 能力。这次我没有使用 systemd 套接字,而是使用AmbientCapabilities服务中的设置(也尝试使用CpabilityBoudingSetCapabilities,后者令人惊讶地未在 中记录systemd.exec)。向服务添加 CAP_NET_BIND_SERVICE 功能应该赋予服务绑定到任何特权端口的权利。

  • /etc/systemd/system/goldfish.service

    [Service]
    User=goldfish
    Group=goldfish
    ExecStart=/usr/local/bin/goldfish -config=/etc/goldfish.hcl
    
    # Tried combinations of those:
    AmbientCapabilities=CAP_NET_BIND_SERVICE
    #CapabilityBoundingSet=CAP_NET_BIND_SERVICE
    #Capabilities=CAP_NET_BIND_SERVICE+ep
    
    Run Code Online (Sandbox Code Playgroud)

仍然没有运气,我总是以“listen tcp 0.0.0.0:443: bind: permission denied”结束。使用 systemd 进行功能管理时我遗漏了什么?


解决方案 3:为可执行文件提供 CAP_NET_BIND_SERVICE 功能。这次我直接将 CAP_NET_BIND_SERVICE 能力赋予了金鱼可执行文件,而在 systemd 服务中没有任何内容

sudo setcap cap_net_bind_service=+ep /usr/local/bin/goldfish
Run Code Online (Sandbox Code Playgroud)

万岁,它有效!该服务正确绑定到端口 443,我可以使用它。但是,我现在有一个可以由任何用户执行并绑定到任何特权端口的二进制文件,我不太喜欢它。可执行能力和systemd服务能力是什么关系?systemd 不应该允许实现与我在这里获得的结果相同的结果,但仅限于特定过程吗?


解决方案 4:将服务置于代理之后。我现在考虑的解决方案是将 Goldfish 放在一个 nginx 代理后面,该代理将是唯一一个从外部可见并监听端口 443 的代理。这似乎是一个很好的折衷方案,因为它保持严格的权限,但它增加了一个新的部分设置,增加了复杂性和潜在错误。在安全性和系统管理方面,它似乎是一个更好的选择还是更差的选择?


所以我实际上在这里有多个问题,但所有问题都与使 systemd 服务在侦听特权端口时以非特权用户身份运行以及它具有的安全隐患有关。有人已经遇到过同样的问题吗?

谢谢你的帮助!

小智 4

我知道这并不完全是您想要的,并为难题添加了“另一块”,但您可以考虑创建一个 systemd .service 文件并将应用程序侦听端口移动到> 1023(这允许非 root 绑定到它),然后创建一条 iptables 规则,将所有流量从端口 443 重定向到新的自定义端口,如下所示:

iptables -t nat -A PREROUTING -i <incoming_interface> -p tcp --dport 443 -j REDIRECT --to-port 8443
Run Code Online (Sandbox Code Playgroud)

在此示例中,到端口 443 的所有 tcp 流量都将透明地重定向到端口 8443。