Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
065933b83e | ||
|
|
b807189692 |
3 changed files with 67 additions and 2 deletions
|
|
@ -75,6 +75,17 @@ the path entry resolves to `/run/wrappers/bin/bin` instead.
|
|||
hive-c0re restarts. Without it, every restart wipes bind sources and
|
||||
existing containers fail to start.
|
||||
|
||||
### `DynamicUser` + `RuntimeDirectoryPreserve` hides the socket from nginx
|
||||
|
||||
With both set, systemd creates the runtime directory under `/run/private/`
|
||||
(`0700 root:root`) and symlinks `/run/<name>` to it (`systemd.exec(5)`,
|
||||
`RuntimeDirectoryPreserve=`). No unprivileged user can traverse that, so
|
||||
nginx's `connect()` to a socket in it fails with `EACCES` whatever the
|
||||
directory and socket modes are. A unit serving a socket to another user
|
||||
runs as a static user instead (`swarm-controller`, `swarm-logs-auth`).
|
||||
`module-eval-core-toggle` fails on any `unix:` upstream of nginx owned by
|
||||
such a unit.
|
||||
|
||||
### `RestrictAddressFamilies` fails as "Address family not supported by protocol"
|
||||
|
||||
A unit whose `RestrictAddressFamilies` omits a family gets `EAFNOSUPPORT`
|
||||
|
|
|
|||
|
|
@ -372,6 +372,13 @@ in
|
|||
# The agents' check on `/select/logsql/`. On the host rather than in the
|
||||
# store's container: it needs nothing of the store, only nginx's reach to
|
||||
# its socket and its own store identity.
|
||||
users.users.${logsAuthUnit} = {
|
||||
isSystemUser = true;
|
||||
group = logsAuthUnit;
|
||||
description = "swarm log store auth_request responder";
|
||||
};
|
||||
users.groups.${logsAuthUnit} = { };
|
||||
|
||||
systemd.services.${logsAuthUnit} = {
|
||||
description = "swarm log store auth_request responder for agent credentials";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
|
@ -391,7 +398,11 @@ in
|
|||
];
|
||||
# Paths only: `argv` is world-readable via /proc/<pid>/cmdline.
|
||||
LoadCredential = lib.mapAttrsToList (id: path: "${id}:${path}") logsAuthStoreFiles;
|
||||
DynamicUser = true;
|
||||
# ⚠️ A static user, never `DynamicUser`: with `RuntimeDirectoryPreserve`
|
||||
# systemd puts a dynamic user's runtime directory under
|
||||
# `/run/private/` (0700 root:root), which nginx cannot traverse.
|
||||
User = logsAuthUnit;
|
||||
Group = logsAuthUnit;
|
||||
RuntimeDirectory = logsAuthUnit;
|
||||
# Traverse-only for others, so nginx reaches the socket path.
|
||||
RuntimeDirectoryMode = "0751";
|
||||
|
|
@ -403,9 +414,11 @@ in
|
|||
SyslogIdentifier = logsAuthUnit;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateTmp = "disconnected";
|
||||
PrivateDevices = true;
|
||||
NoNewPrivileges = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
};
|
||||
environment = {
|
||||
BAO_ADDR = "https://${baoCfg.domain}:${toString baoCfg.port}";
|
||||
|
|
|
|||
|
|
@ -578,6 +578,47 @@ let
|
|||
&& lib.hasInfix "--socket /run/swarm-logs-auth/auth.sock" unit.serviceConfig.ExecStart
|
||||
&& l ? "= /__hive_authelia";
|
||||
}
|
||||
{
|
||||
# A `DynamicUser` unit's preserved runtime directory lives under
|
||||
# `/run/private/` (0700 root:root), which nginx cannot traverse, so a
|
||||
# socket there answers every proxied request with a 502. Each `unix:`
|
||||
# upstream under `/run/<dir>/` is matched to the units creating `<dir>`.
|
||||
# The first clause is the control: the match finds swarm-logs-auth's.
|
||||
name = "no unix socket nginx proxies to sits in a DynamicUser's preserved runtime directory";
|
||||
ok =
|
||||
let
|
||||
prefix = "http://unix:/run/";
|
||||
upstreamDirs = lib.unique (
|
||||
map (p: lib.head (lib.splitString "/" (lib.removePrefix prefix p))) (
|
||||
lib.filter (p: p != null && lib.hasPrefix prefix p) (
|
||||
lib.concatMap (vh: lib.mapAttrsToList (_: loc: loc.proxyPass) vh.locations) (
|
||||
lib.attrValues allLocal.services.nginx.virtualHosts
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
runtimeDirs =
|
||||
sc:
|
||||
let
|
||||
r = sc.RuntimeDirectory or [ ];
|
||||
in
|
||||
if lib.isList r then r else lib.splitString " " r;
|
||||
owners = lib.filterAttrs (
|
||||
_: u: lib.any (d: lib.elem d upstreamDirs) (runtimeDirs u.serviceConfig)
|
||||
) allLocal.systemd.services;
|
||||
hidden =
|
||||
sc:
|
||||
lib.elem (sc.DynamicUser or false) [
|
||||
true
|
||||
"yes"
|
||||
]
|
||||
&& !(lib.elem (sc.RuntimeDirectoryPreserve or "no") [
|
||||
false
|
||||
"no"
|
||||
]);
|
||||
in
|
||||
owners ? swarm-logs-auth && !(lib.any (u: hidden u.serviceConfig) (lib.attrValues owners));
|
||||
}
|
||||
{
|
||||
# Every agent bearer the responder has not recently granted costs a
|
||||
# store login and read, so its location carries the per-address limit.
|
||||
|
|
|
|||
Loading…
Reference in a new issue