authelia: a user outside a rule's group is denied instead of falling through to one_factor
authelia takes the first matching rule, and a rule with a `subject` does not match a subject outside it. The swarm domain's and the bao UI's `group:admins` rules had nothing after them, so an account in no group skipped them and landed on `default_policy = one_factor`: any authenticated account reached the swarm UI, its `/api/` (by cookie or by bearer) and the bao UI. Each of the two group rules is now an `operatorsOnly` pair: the group allow, then a subject-less `deny` for the same domain, the shape `collectorOnly` already gives the collector's metrics rules. `default_policy` stays `one_factor`, which the forge and chat rely on. module-eval-swarm-otel-identity gains two cases on `allLocal`: an account in no group is refused the swarm domain (four paths) and the bao UI while `group:admins` passes and the forge stays open; and a predicate, `autheliaSubjectRulesClosed` in lib.nix, holds over the rendered list: every subject-scoped allow is closed by a later subject-less `deny` on its domain with no subject-less allow in between, and nothing follows a domain-wide `deny` on its domain. Fixes #5120
This commit is contained in:
parent
b99ce2b572
commit
4a9acd1d0c
4 changed files with 194 additions and 15 deletions
|
|
@ -43,6 +43,21 @@ let
|
|||
# failing the check it was supposed to pass.
|
||||
operatorGroup = "admins";
|
||||
|
||||
# `target`, for `operatorGroup` and nobody else. The `deny` is what makes
|
||||
# the group rule exclusive, for the reason `collectorOnly` gives: a subject
|
||||
# outside the group skips the first rule and would otherwise land on
|
||||
# `default_policy`.
|
||||
operatorsOnly = target: [
|
||||
(
|
||||
target
|
||||
// {
|
||||
policy = "one_factor";
|
||||
subject = [ "group:${operatorGroup}" ];
|
||||
}
|
||||
)
|
||||
(target // { policy = "deny"; })
|
||||
];
|
||||
|
||||
# Whether the swarm collector's client is actually registered here.
|
||||
#
|
||||
# Asked of the client list rather than re-derived from the conditions
|
||||
|
|
@ -1137,9 +1152,10 @@ in
|
|||
# user", which is authentication, not authorisation. The
|
||||
# swarm UI is operator-only, and agents are getting
|
||||
# authelia accounts of their own — so the day that lands,
|
||||
# a session alone would be enough to open it. The rule
|
||||
# below is what makes the distinction real; without it
|
||||
# the vhost's `auth_request` is a check nobody fails.
|
||||
# a session alone would be enough to open it. The
|
||||
# `operatorsOnly` pairs below are what make the distinction
|
||||
# real; without them the vhost's `auth_request` is a check
|
||||
# nobody fails.
|
||||
#
|
||||
# The group is a constant rather than an option: it is the
|
||||
# value an operator types into `swarmctl user add --group`,
|
||||
|
|
@ -1149,7 +1165,9 @@ in
|
|||
default_policy = "one_factor";
|
||||
# ⚠️ ORDER MATTERS — authelia takes the FIRST matching rule.
|
||||
# The metrics rules are listed first so they cannot be
|
||||
# shadowed by a broader domain rule added later.
|
||||
# shadowed by a broader domain rule added later. A `deny` with
|
||||
# no `resources` ends its domain: a rule for that domain
|
||||
# listed after it is never reached.
|
||||
rules =
|
||||
# The collector's client where one is registered, then
|
||||
# `deny` — see `collectorOnly` above, which is where the
|
||||
|
|
@ -1158,19 +1176,15 @@ in
|
|||
++ metricsStoreRules
|
||||
# Also guarded on the domain being set: without it a null
|
||||
# apex would render a rule matching the string "null".
|
||||
++ lib.optional (deployCfg.swarm-controller.enable && swarmDomain != null) {
|
||||
++ lib.optionals (deployCfg.swarm-controller.enable && swarmDomain != null) (operatorsOnly {
|
||||
domain = swarmDomain;
|
||||
subject = [ "group:${operatorGroup}" ];
|
||||
policy = "one_factor";
|
||||
}
|
||||
})
|
||||
# The store's browser UI. Not keyed to a deploy flag: its
|
||||
# vhost is on the store's host, which need not be this
|
||||
# one, and without this rule any session passes it.
|
||||
++ lib.optional (swarmDomain != null) {
|
||||
# one, and without these rules any session passes it.
|
||||
++ lib.optionals (swarmDomain != null) (operatorsOnly {
|
||||
domain = hyperhiveCfg.swarm.bao.ui.domain;
|
||||
subject = [ "group:${operatorGroup}" ];
|
||||
policy = "one_factor";
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
# The cookie domain is the SWARM's domain, NOT authelia's
|
||||
|
|
|
|||
Loading…
Reference in a new issue