Watch
0
0
Fork
You've already forked hyperhive
0

squid blocks a runtime deny list from the controller in every egress mode, ahead of the allow list

This commit is contained in:
atlas 2026-11-04 22:00:42 +01:00 • committed by mara
commit dd5fde848f

View file

@ -253,6 +253,7 @@ pkgs.testers.runNixOSTest {
LIST = "/var/lib/hive-squid/unrestricted"
ALLOWED = "/var/lib/hive-squid/allowed"
AGENT_ALLOW = "/var/lib/hive-squid/agent-allow.conf"
DENY = "/var/lib/hive-squid/deny.conf"
UNRESTRICTED = ["uma", "selfcheck-unrestricted.squid"]
start_all()
@ -304,6 +305,14 @@ pkgs.testers.runNixOSTest {
f"&& chmod 640 {path}.new && mv {path}.new {path}"
)
def write_deny(body):
# What hive-c0re does for the deny list: written aside and renamed into
# place, in squid's group; the reload is squid-unrestricted-reload's.
proxy.succeed(
f"printf '%s' {shlex.quote(body)} > {DENY}.new && chown hive-core:squid {DENY}.new "
f"&& chmod 640 {DENY}.new && mv {DENY}.new {DENY}"
)
def wait_status(host, cred, want):
# The reload that follows a list write is asynchronous.
got = None
@ -328,6 +337,8 @@ pkgs.testers.runNixOSTest {
assert proxy.succeed(f"stat -c '%U:%G %a' {ALLOWED}").strip() == "hive-core:squid 640"
assert proxy.succeed(f"stat -c '%U:%G %a' {AGENT_ALLOW}").strip() == "hive-core:squid 640"
assert proxy.succeed(f"stat -c %s {AGENT_ALLOW}").strip() == "0"
assert proxy.succeed(f"stat -c '%U:%G %a' {DENY}").strip() == "hive-core:squid 640"
assert proxy.succeed(f"stat -c %s {DENY}").strip() == "0", "no deny list, no rule"
# The allow-list file starts as the hive's own allowedDomains.
proxy.succeed(f"grep -Fx forge.t.local {ALLOWED}")
assert connect("forge.t.local", ATLAS) == "407", "no such user"
@ -573,6 +584,53 @@ pkgs.testers.runNixOSTest {
write_allow(seeded, "")
wait_status("other.t.local", RUTH, "403")
with subtest("the swarm's deny list is refused before any allow, in every mode, with or without a credential, and logged as egress_denied"):
# What hive-c0re renders: `forge.t.local` and `other.t.local` for every
# agent, `api.t.local` (a base-list name) for atlas alone. `ruth` is in
# log mode, so her rule follows. The names are allowed or reachable
# without the list, which the controls establish first.
assert connect("forge.t.local", ATLAS) == "200", "control: allowed by the hive"
assert connect("forge.t.local", UMA) == "200", "control: allowed, unrestricted"
assert connect("other.t.local", UMA) == "200", "control: unrestricted reaches it"
assert connect("api.t.local", ATLAS) == "200", "control: base list"
write_allow(
seeded,
"# source: swarm\n"
"acl log_mark annotate_transaction would_deny=1\n"
"acl agent_log_ruth proxy_auth ruth\n"
"http_access allow agent_log_ruth !allowed_dst log_mark\n",
)
wait_status("other.t.local", RUTH, "200")
write_deny(
"acl deny_hit_mark annotate_transaction egress_deny=1\n"
"acl deny_swarm_dst dstdomain forge.t.local other.t.local\n"
"http_access deny deny_swarm_dst deny_hit_mark\n"
"acl deny_agent_atlas_dst dstdomain api.t.local\n"
"acl deny_agent_atlas proxy_auth atlas\n"
"http_access deny deny_agent_atlas_dst deny_agent_atlas deny_hit_mark\n"
)
wait_status("forge.t.local", ATLAS, "403")
assert connect("forge.t.local", RUTH) == "403", "a listed name, log mode"
assert connect("forge.t.local", UMA) == "403", "a listed name, unrestricted"
assert connect("other.t.local", UMA) == "403", "unrestricted"
assert connect("other.t.local", RUTH) == "403", "log mode"
assert connect("forge.t.local") == "403", "no credential: refused, not challenged"
assert connect("api.t.local", ATLAS) == "403", "a base-list name, denied for atlas"
assert connect("api.t.local", RUTH) == "200", "control: another agent keeps the base name"
assert connect("api.t.local") == "407", "control: a per-agent deny does not answer a client it cannot name"
proxy.wait_until_succeeds(
"journalctl -u squid.service -o cat | grep -E "
"'egress_denied user=atlas method=CONNECT host=api\\.t\\.local port=443 result=TCP_DENIED/403'"
)
assert squid_saw(r"egress_denied user=- method=CONNECT host=forge\.t\.local port=443 "), "the anonymous client's hit"
assert not squid_saw(r"egress_denied .* host=loop\.t\.local"), "another refusal is not a deny-list hit"
assert not squid_saw(r"egress_denied user=ruth .* host=api\.t\.local"), "another agent's name is not a hit"
write_deny("")
write_allow(seeded, "")
wait_status("forge.t.local", ATLAS, "200")
assert connect("api.t.local", ATLAS) == "200", "the list emptied"
assert connect("other.t.local", UMA) == "200", "the list emptied, unrestricted"
with subtest("squid starts on a missing list, treats every user as restricted, and recovers when it appears"):
proxy.succeed(f"rm {LIST}")
proxy.succeed("systemctl restart squid.service")