feat(kanidm): declare the account policy and gate on drift #277
Inga granskare
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra!277
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "feat/275-kanidm-account-policy-gate"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Part of #275 — the account-policy half. The OAuth2 half is separate (see below).
Production's
credential_type_minimumismfa: Kanidm's upstream default, inherited rather thanchosen. This declares it and asserts it against the live server.
Why declared-and-asserted rather than applied
It cannot be applied.
kanidm-provisionv1.3.0 has no account-policy support —Statecarriesonly
groups,persons,systems, andGrouponly membership/unix fields. AndStatehas no#[serde(deny_unknown_fields)], so anaccountPolicykey would be parsed and silentlydiscarded: a state file that looks declarative and changes nothing.
That is the same trap this role already documents for the dead
service-accountsblock. Adding itwould have been worse than the gap it appeared to close, so the naive implementation was abandoned
after reading upstream rather than shipped.
And a write here should not be automatic. The CLI ships no
reset-credential-type-minimum, andKanidm restricts downgrading the attribute, so setting it is close to one-way. A gate that reports
drift and leaves the decision to a human is the right shape; a playbook that silently forces a value
it cannot undo is not.
Safety properties
vault_kanidm_reconciler_token, so the gate cannot mutate identitystate even if the task is wrong. No new privileged token had to be bootstrapped.
check_mode: falseso it runs during dry-runs. Without it the gate would be dead in exactlythe pass operators rely on before applying.
lacking the attribute), a 404, or an unexpected body shape is reported via
debugand tolerated —a drift gate that breaks unrelated applies is worse than no gate.
changed_when: false,no_log: true(token in headers).Verified against production, both directions
Match —
--check --tags kanidm:Drift — same run with
-e kanidm_account_policy_credential_type_minimum=passkey:The failure message names the live value, the declared value, the ordering, the one-way caveat, and
the file to edit.
Also recorded
Why the credential UX behaves as it does, since it caused real confusion: ordering is
any < mfa < passkey < attested_passkey, so a password alone ranks belowmfaand Kanidm demandsTOTP alongside it, while a passkey ranks above
mfaand satisfies the policy by itself. Apasskey-only person needs no TOTP; only choosing a password pulls in a second factor. That is the
intended posture, not a bug.
Not in this PR
The OAuth2 half of #275, which is now the more urgent part. The live client list shows the
production
bitborg-webclient carrieshttps://localhost:4321/auth/callbackas a registeredorigin alongside the real callback, and the stray
bitborg-web-devclient is scope-mapped toforgejo_users— i.e. visible to every user. Both want fixing, andpresent: falseplus explicitorigin_url/scope_mapscan do it declaratively. Kept separate because a mistake there breaks SSO.