You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A directory no longer has to be Active Directory. The integration was
built for AD and said so only in its code: bind by UPN, look accounts up by sAMAccountName, track them by objectGUID, filter on userAccountControl.
Every one of those is false for OpenLDAP, FreeIPA and Google Workspace Secure
LDAP, which is why connecting one of them could not be made to work by
configuration alone. A directory now has a type — Active Directory,
OpenLDAP, FreeIPA, Google Workspace or generic — and the type supplies both
what the protocol can do there (MS-CHAPv2 and computer sync are Active
Directory only) and the schema guesses you are free to overwrite (search
filters, attribute maps, the examples under each field). The type is chosen
once, when the configuration is created, and cannot be changed afterwards: each
directory imports accounts by its own login attribute and tracks them by its
own identifier, so switching would mean converting users already synchronised. Existing installations are untouched — a configuration with no type reads
as Active Directory, and the Active Directory defaults are the previous
literals character for character.
Directory accounts can authenticate with MS-CHAPv2. Devices that offer
nothing else — MikroTik RouterOS sends only MS-CHAPv2 for an administrator
login, has no PAP and no TACACS+ client — could not authenticate against
Taranac at all, which also made the RouterOS RADIUS template shipped in 1.2.1
unreachable. Local accounts are verified in Taranac itself; an Active Directory
account is verified by a domain controller, because its password hash is
unreadable by design. The same now works for 802.1X endpoints: a directory
account authenticates over PEAP/MSCHAPv2 and over EAP-TTLS. Nothing to switch
on — the branch is chosen by what the device sends, and a device that sends PAP
never enters it.
The node joins the domain by itself. Add an LDAP configuration with the
MS-CHAPv2 settings and the installation becomes a domain member using the
account it already binds with — no computer object created by hand, no
delegation requested from an Active Directory administrator (a domain's default
machine-account quota is what makes this possible). The machine account name is
derived so that a node re-joins its own object, and checked against the
directory so two installations in one domain cannot overwrite each other. The
automatic join happens once and never repeats.
An MS-CHAPv2 tab on the LDAP configuration — membership per node, the
feature switch, and a join dialog that asks the directory about the credentials
and the target organizational unit before spending them, so the commonest
failures (wrong password, mis-ordered OU path) are named in under a second
instead of coming back as net ads join's own diagnostics. At most one LDAP
configuration may own the domain, and the refusal names the one that already
does.
An alert when the domain trust breaks. Narrowly: MS-CHAPv2 is switched on
and this node can no longer verify a domain password. A member with the feature
deliberately switched off never pages anyone, and "never joined" is reported as
an incomplete setup rather than a broken trust.
Domain authentication failures are diagnosed, not guessed. Twenty-four
NT_STATUS codes and nine join failures each map to a cause and a next action —
expired account, logon-hours policy, a dead controller, NTLM disabled by policy,
clock skew, a broken machine-account trust — and each carries whether it counts
as a credential attempt, so a rebooting domain controller no longer looks like
password guessing.
A twelfth service, winbind, ships with every installation. It owns the
node's Active Directory machine account. Without a domain configured it starts,
reports "not joined" and does nothing — a service you must first install is a
service nobody enables, and MS-CHAPv2 is needed exactly by the administrators
who discover the need at the moment their login fails.
Certificate enrollment (EST) works end to end. It was previously
unreachable by any supported route: the frontend proxied only /api/, so /.well-known/est/ returned the web UI's HTML to an enrolling client, and the
only working path was the API's bare port with an internal-only certificate. EST
and the revocation lists are now published through the front door on the
installation's own certificate, and the CRL distribution point is filled in
automatically.
An approval queue for certificate requests. Turning on "require approval"
used to stop issuance rather than defer it — the request was stored as a
certificate with serial "0" and placeholder dates, no approval screen existed,
and every client poll appended another row. Requests are now their own records,
deduplicated by the request's fingerprint across polls, with a queue in the UI,
and an approval group that says who gets notified (deciding is nac_pki.edit,
as it always was).
Approve a certificate request from an email link. Members of the approval
group get the request by mail with what is being issued and to whom. The link
never acts on being opened: mail scanners, Safe Links and messenger previews
follow links by themselves, so the GET only shows a page and the decision needs
a deliberate confirmation.
Certificate renewal cannot be fooled by a revoked certificate. A renewal is
checked against the revocation list before it is granted, so a certificate that
has been revoked can no longer be used to obtain its own replacement. Renewal
authenticated by the client's own certificate needs a listener that verifies
client certificates, which this release does not yet ship — until then a
renewal authenticates the same way an enrollment does.
Master key rotation — ./taranac rotate-key. Runs on a stopped system in a
single transaction: the operator presents the current key, names the new one, a
backup is taken, every encrypted column is re-encrypted, the system starts
again. It can also be rehearsed on a dev stack — a tool with nowhere to practise
is a tool nobody has practised.
A backup that a disaster recovery can actually use. The archive now carries .env, the compose file and config/, because the database's secrets are
ciphertext whose key lives outside it; restoring asks for the five keys that
matter. pg_dump gained a timeout, so a hung dump no longer occupies the single
scheduler slot forever while the dashboard shows the last good archive.
The username filter matches a substring, case-insensitively. Filtering the
NAC Auth Log for ad_user1 found nothing when the account had authenticated as ad_user1@example.com or EXAMPLE\ad_user1. Applied to the NAC Auth Log, NAC
Sessions and the AAA logs alike, with trigram indexes on the seven journal
tables so it stays fast on a large archive (53 ms → 1.5 ms on a 60k-row
partition).
A VLAN filter on authorization profiles — "which profiles drop an endpoint
into VLAN 40" no longer means paging through the list.
EAP-TTLS accepts all three of its inner methods. Native EAP-TTLS/MSCHAPv2 —
what a supplicant sends with no EAP inside the tunnel — failed for everyone,
including a local account with the correct password.
Changed
The UI downloads only the languages it will show. All seven bundled
languages (3.58 MB of translations) were part of the entry chunk, so an
installation running only English still fetched about 3.2 MB it would never
display. The other languages now load when one is selected.
The Security menu section is gone. Authentication & Sessions moved to
System, and the Crypto page — which existed for a single button that broke
installations — was removed along with it (see the rotation tool above).
The RBAC list no longer shows a Type column or a System/Custom filter. No
role in a running system is ever a system role, so the column read "Custom" on
every row and one filter option returned everything while the other returned
nothing. On upgrade: a custom report dataset built on the config_rbac_roles
template that had picked the is_system column fails validation on the next run
and needs its columns re-picked; no seeded dataset uses it.
The RADIUS "authentication type" dropdown is gone. It offered PAP / CHAP /
MS-CHAPv2, and nothing read the value — the handler authenticated with PAP
regardless. It advertised a capability the product did not have, which is worse
than no control at all. MS-CHAPv2 now works off what the device actually sends,
with nothing for an operator to choose.
EAP-TEAP is gone from the log filter and the policy schema, having never
been implemented, and EAP-TTLS — which is fully supported — is finally rendered
and filterable in the log views and the session drawer.
Syslog forwarding has a ceiling and reports what it drops. The forward
window was unbounded, so after any downtime the whole missed range was loaded at
once and sent one message per record; on a large installation that is not a
slowdown but an outage, at the moment the system comes back.
The dashboard stops polling while its browser tab is hidden.
Fixed
Re-authentication no longer loses a session's identity, and a session the
NAS keeps reporting is no longer archived behind the operator's back. An 802.1X
re-authentication closes one session and opens the next milliseconds apart on
the same port, which is what made the active session show LAB\anonymous.
A CoA "session not found" no longer kills a live session. The switch's 503
answers "did I find a session matching your identifiers", not "is anybody on the
network" — it usually means the port re-authenticated in place. Taranac used to
archive the session and tell the operator the disconnect had succeeded, with no
way to bring it back.
The orphaned-session probe no longer disconnects healthy sessions. It asked
"are you still there?" with a real Disconnect-Request, and on hardware that
sends no periodic interim accounting (the Cisco default) every healthy session
eventually crossed the threshold and was torn down for being healthy. CoA is
also sent to the port configured for the device instead of a fixed one.
Reauthentication timer reaches the hardware. The value was carried
everywhere — model, UI, reports, daemon cache — and serialized nowhere: an
operator typed 3600, saw the "seconds" hint, and got nothing. It is now rendered
as Session-Timeout plus Termination-Action, per the vendor's own mapping.
A rejected reject reason is now the right one. An endpoint whose TLS
handshake dies — typically because it does not trust the RADIUS server
certificate — was logged as PEAP with auth_failed, sending the operator after
credentials for a certificate problem. The EAP method is now taken from what the
daemon reports, a rejected server certificate is named as such, and an account
that cannot use PEAP is told to use EAP-TTLS instead of being reported as a bad
password. A missing ntlm_auth helper is likewise named instead of surfacing as
a wrong password.
A MikroTik administrator's successful login no longer writes a phantom
failure. RouterOS probes the SSH "none" method by proving the empty password
before prompting the human, so every successful login produced a counted bad_password — halving the configured brute-force threshold for exactly the
devices that need MS-CHAPv2, and topping the "top failed authentications" widget
with the customer's own administrators.
Failed RADIUS MFA challenges say what actually arrived instead of reporting
an unusable fragment of the submitted value, so an expired code and a value that
was never a code are no longer the same log line.
An unreachable directory fails instead of hanging. The LDAP client reads a
boolean server pool as "retry forever", sleeping between rounds, so a directory
that did not answer never produced an error — the request simply hung, holding
the worker that made it. On every operation, including Test connection, which
is exactly where an operator goes to find out what is wrong, and inside the
RADIUS and TACACS+ daemons that loop sat in the thread serving the request.
A wrong CA file is named instead of returning a server error. The
certificate is parsed when the connection is described rather than when it is
opened, so a bad file surfaced as HTTP 500 on every operation; the connection
report now says what is wrong with it.
Computer synchronisation says which setting is missing. With no computer
search base configured it failed with "connection failure", which sent the
operator to check the network, the controller and the certificates while the
real cause sat only in the container log.
An empty attribute map no longer silently falls back to sAMAccountName,
and creating a non-Active-Directory configuration no longer reports an error after having saved it.
Group matching on FortiGate. The seeded TACACS+ template named the AV-pair member_of; a FortiGate asks for memberof, so it was silently dropped and
group matching could never succeed once an operator added a config match
block. Migration 0019 renames it in existing templates and profiles too.
A network object of type FQDN can no longer be attached to a device. Such an
object carries no network, so the device silently dropped out of the RADIUS
clients list — it was not authenticated at all — and its TACACS+ rules lost
their device restriction entirely.
Tables show an error instead of "no records". On a failed request the log
pages rendered their empty state, so an operator in an incident read an empty
authentication journal as "there were no authentications" — the worst kind of
failure, silent and pointing the wrong way. Failures now say so, and a failed
auto-refresh over live rows says the data is the last good one.
Escape closes only the topmost drawer. Pressing it in a third-level form
closed all three levels and lost what had been typed; a confirmation dialog
opened from a drawer now correctly takes the key.
A backup archive missing its declared content is no longer reported as
successful. The host-files part was never collected on any deployment, and the
only trace was a manifest field nobody reads — discovered at restore time, the
worst possible moment. An incomplete archive is still written, but it is loud:
audit, error log, and a backup:incomplete alert that clears only on the next
complete archive.
The "Rotate Master Key" button no longer destroys the installation. It
re-encrypted only the system settings, leaving device keys, enable passwords,
the internal CA's private keys, NCM credentials, TOTP secrets and the license on
the old key while swapping the key in memory — and answered 200. The endpoint
now refuses, and rotation is done by the tool described above.
Security
nginx updated to 1.30.4, and it no longer announces its version. The web
listeners ran 1.27.5 (edge, frontend) and 1.26.3 (captive portal) — branches
that ended in 2025, on tags frozen ever since, so rebuilding those images had
never brought a single fix. Nineteen and eighteen published advisories
respectively apply to those versions, including a buffer overflow in map with
a regular expression. None of them is reachable through the shipped
configuration, which uses only proxy, TLS, gzip and return — but the list
grows by itself, and an operator whose scanner flags it should not have to take
our word for why it does not matter.
Certificate enrollment could be reached without any credential. A request
carrying two invented headers and no credentials received HTTP 200 and a signed
certificate: the enrollment endpoint trusted client-identity headers that no
proxy in the deployment ever set or stripped, so anyone who could reach it
controlled them. Reproduced on a stand, now a 401.
The token issued after the password but before the second factor was accepted
as a session. It was signed with the same key and the same shape as a full
access token, and nothing checked what it was for — so a stolen password alone
was enough to enroll an attacker's own second factor over the victim's and then
log in normally. Every token now declares its purpose and every endpoint accepts
only the purposes it names, deny by default.
Removing someone else's second factor required nothing but the record's
UUID. It now requires mfa.edit.
A group's RBAC model could be assigned by anyone who could edit groups. The
model behind a privileged group was also visible to anyone who could view
groups, so an operator could grant their own group a privileged model and simply
log in again. Assigning a model, and membership of administrative groups, now
require administrator rights.
The Telegram MFA webhook accepted unauthenticated requests. The secret check
started with "if a secret was sent", so a request without the header passed it
entirely, and a forged one could make the bot disclose which Taranac accounts
are linked to a given Telegram account — into a chat of the caller's choosing. /mfa/verify is now also attempt-limited.
Fetching a CRL was an internal port scanner. Only the URL prefix was
checked: no loopback or private-range block list, no re-check after a redirect,
no size limit, TLS verification disabled outright, and the exception text handed
back verbatim — and it re-runs on a schedule. It now validates the target,
connects to the address it validated, verifies the certificate, caps the
download, and reports failures without describing what it found.
A value containing a newline could append arbitrary directives to a generated
daemon configuration. Escaping covered only quotes and backslashes, in all
three generators. Control characters are now replaced: a mangled value breaks
one device, a raw newline breaks the configuration of the whole fleet.
A TACACS+ rule whose device restriction resolved to nothing applied to every
device. An emptied device group, or a device sitting on an FQDN object, turned
a narrow rule into a fleet-wide one — and the generated ruleset is the only
place the restriction is enforced, so nothing downstream caught it. The same
rule already failed closed in RADIUS, which means one rule had opposite meanings
in the two protocols.
A domain-qualified name is no longer an alias for a local account. Over
802.1X, ANYTHING\alice and alice@whatever.invalid all authenticated as the
local account alice, and the log named the bare account either way. The name
is now tried exactly as sent, and a qualified name may only ever resolve to a
directory account.