squid blocks a runtime deny list from the controller in every egress mode, ahead of the allow list
This commit is contained in:
parent
99ab0ae77f
commit
dd5fde848f
2 changed files with 1814 additions and 24 deletions
|
|
@ -299,6 +299,9 @@ in
|
|||
HIVE_SQUID_ALLOWED_SEED_FILE =
|
||||
config.services.hyperhive.deploy.hive-controller.squid.allowedSeedFile;
|
||||
HIVE_SQUID_ALWAYS_ALLOWED = lib.concatStringsSep " " config.services.hyperhive.deploy.hive-controller.squid.alwaysAllowed;
|
||||
# The swarm's egress deny list, which `workers::squid_deny` renders into the
|
||||
# include squid reads before every allow.
|
||||
HIVE_SQUID_DENY_FILE = config.services.hyperhive.deploy.hive-controller.squid.denyFile;
|
||||
# The egress proxy facts every container is handed (`HiveFacts` in
|
||||
# `hive-priv-sock`). They sit with the users file above because that is what
|
||||
# makes squid's credential check and per-agent policy real on this host: an
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
# the swarm lists for that agent alone. A third kind, set per agent
|
||||
# (`internet_log`), reaches the same names but is also let through to any other
|
||||
# destination the deny rules leave; the request is logged as `would_deny`.
|
||||
# The swarm's deny list (rendered by hive-c0re into `denyFile`) is refused for
|
||||
# all three before any allow, and logged as `egress_denied`.
|
||||
# An agent sends its credential
|
||||
# once it has fetched it (../agent-modules/egress-proxy.nix); the exporter,
|
||||
# journal forwarding and the self-check below show the proxy works.
|
||||
|
|
@ -89,6 +91,10 @@ let
|
|||
# `deny !allowed_dst`, so it sees the same denies and only turns that last
|
||||
# refusal into an allow. The `dst` denies cost an unlisted name a lookup on
|
||||
# the host's resolver before it is refused.
|
||||
# The swarm's deny list (`denyFile`) sits right after those destination
|
||||
# denies and before `deny !authed`, so a denied name is refused before any
|
||||
# credential check and before every allow, in every mode: its rules name the
|
||||
# destination first, and a swarm-wide one names no user at all.
|
||||
squidConf = ''
|
||||
http_port ${listen}
|
||||
pid_filename /run/squid/squid.pid
|
||||
|
|
@ -110,6 +116,14 @@ let
|
|||
acl would_denied note would_deny 1
|
||||
access_log syslog:daemon.info logformat=would_deny would_denied
|
||||
|
||||
# A request one of the deny list's rules (hive-c0re's `denyFile`, below)
|
||||
# refused carries the annotation `egress_deny=1` and gets a line of its own,
|
||||
# distinct from `would_deny` and from the 403 line every refusal has, in
|
||||
# every mode.
|
||||
logformat egress_denied egress_denied user=%[un method=%rm host=%>rd port=%>rP result=%Ss/%03>Hs
|
||||
acl egress_denied_hit note egress_deny 1
|
||||
access_log syslog:daemon.info logformat=egress_denied egress_denied_hit
|
||||
|
||||
# The helper reads the users file on every request and reloads it when its
|
||||
# mtime moves. It exits when the file is missing, which is why the file is
|
||||
# created before squid starts. A positive answer is cached for a minute, so
|
||||
|
|
@ -153,6 +167,7 @@ let
|
|||
http_access deny to_linklocal
|
||||
http_access deny to_bridge
|
||||
http_access deny to_private
|
||||
include ${cfg.denyFile}
|
||||
http_access deny !authed
|
||||
${lib.optionalString (base != [ ]) "http_access allow base_dst"}
|
||||
include ${cfg.agentAllowFile}
|
||||
|
|
@ -162,9 +177,9 @@ let
|
|||
http_access deny all
|
||||
'';
|
||||
|
||||
# `squid -k parse` on the configuration with the include pointing at an empty
|
||||
# `squid -k parse` on the configuration with the includes pointing at an empty
|
||||
# file. The nixpkgs module runs the same parse on the real text, which
|
||||
# cannot open the include in the build sandbox.
|
||||
# cannot open the includes in the build sandbox.
|
||||
squidConfCheck =
|
||||
pkgs.runCommand "squid-conf-check"
|
||||
{
|
||||
|
|
@ -173,7 +188,7 @@ let
|
|||
''
|
||||
squid -k parse -f ${
|
||||
pkgs.writeText "squid.conf" (
|
||||
builtins.replaceStrings [ cfg.agentAllowFile ] [ "/dev/null" ] squidConf
|
||||
builtins.replaceStrings [ cfg.agentAllowFile cfg.denyFile ] [ "/dev/null" "/dev/null" ] squidConf
|
||||
)
|
||||
}
|
||||
touch $out
|
||||
|
|
@ -381,6 +396,24 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
denyFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "${builtins.dirOf cfg.usersFile}/deny.conf";
|
||||
readOnly = true;
|
||||
defaultText = lib.literalMD "`deny.conf`, in the directory of `usersFile`";
|
||||
description = ''
|
||||
Squid configuration that hive-c0re generates from the swarm's deny list
|
||||
(`/api/egress/denied-domains`) and the main configuration includes after
|
||||
the destination denies and before `deny !authed` and every allow: a
|
||||
`http_access deny` for the swarm-wide names, and one per agent of this
|
||||
hive the swarm lists names for. A denied name is refused for every user
|
||||
in every egress mode, whether or not an allow rule covers it. The file
|
||||
is empty, and squid configured as without it, until the swarm lists a
|
||||
name. Squid is reloaded when it changes. Owned by `hive-core` and readable
|
||||
by the `squid` group.
|
||||
'';
|
||||
};
|
||||
|
||||
allowedSeedFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = seedFile;
|
||||
|
|
@ -481,6 +514,7 @@ in
|
|||
"f ${cfg.unrestrictedFile} 0640 hive-core squid - -"
|
||||
"C ${cfg.allowedFile} 0640 hive-core squid - ${seedFile}"
|
||||
"f ${cfg.agentAllowFile} 0640 hive-core squid - -"
|
||||
"f ${cfg.denyFile} 0640 hive-core squid - -"
|
||||
];
|
||||
|
||||
# Squid reads the unrestricted list, the allow-list and the per-agent include
|
||||
|
|
@ -494,6 +528,7 @@ in
|
|||
cfg.unrestrictedFile
|
||||
cfg.allowedFile
|
||||
cfg.agentAllowFile
|
||||
cfg.denyFile
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue