A loom makes cloth from two sets of threads. The long threads — the warp — are put on first and stay in place. The cross threads — the weft — go through them one row at a time. The cloth is strong because the two sets cross each other.
Most companies already have their long threads: a corporate PKI, with its own root certificate and its own rules. Until now Taranac’s PKI stood next to it. In 1.3.4 it becomes part of it.
- Your PKI — an Internal CA can be a SubCA signed by your corporate root: imported, or requested by a CSR whose key never leaves Taranac, then renewed with the same key. Its chain goes wherever a chain is needed and never into EAP-TLS trust.
- SCEP beside EST — for the Cisco IOS and MikroTik devices that cannot do anything else, configured on its own.
- TACACS+ — only inventoried devices log in, and a refused connection is in the Authentication Log with its reason. TLS clients are checked for revocation.
- IPv6 — every client is seen by its own address, not the Docker gateway’s.
- RADIUS and NAC — a new configuration is applied without a restart, a waiting MFA push holds one worker instead of the node, and CRL and OCSP apply per CA.
Several of these change what an existing setup does, and 1.3.4 needs Docker 28. Read the first section before you update.
What’s in 1.3.4
Before you update
The warp: your PKI
- An Internal CA signed by your corporate root
- Requested by CSR, renewed with its own key
- SCEP beside EST
- Who may enroll, and who enrolled
The weft: what crosses it
- TACACS+ accepts the inventory, and says why it refused
- TACACS+ over TLS checks revocation
- IPv6 clients are seen by their own address
The loom never stops
- FreeRADIUS applies a configuration without a restart
- A waiting MFA push holds one thread
- CRL and OCSP, per CA
Fixes worth knowing
What to do when updating
Read this list before you run ./taranac update. Most items are one line of work;
skipping them is what hurts.
Before anything else
- Docker 28 or newer, and IPv6 in the kernel. The stack network now carries IPv6.
bootstrap.sh,install.shand the update refuse — before changing anything — on an older Docker, on Podman answering thedockercommand, or on a kernel without IPv6, and say what to do. - HA: update Docker on every database node before updating the first one. The update checks it node by node; a node that fails the check is left untouched, but the members updated before it are already on 1.3.4 and the rollout stops half-way. The witness is not checked.
- The stack goes down and comes up once during the update: the stack network is recreated with IPv6.
TACACS+
- Devices outside the inventory no longer log in with the global key. The global
key is still the fallback for inventoried devices. The update lists the addresses
that logged in without an inventory entry in the last 30 days (and keeps the list in
.taranac-update.log): add them, or enable their entry. - Over TLS too, a device must be in the inventory, whatever its certificate. EST and SCEP enrollment do not need an inventory entry; TLS login does — add the device before it logs in over TLS.
- The check is per address: an entry for
0.0.0.0/0,::/0or any subnet lets every address it covers in, with that entry’s key.
IPv6
- IPv6 devices are matched by their own address — check their keys. Until now every
IPv6 device reached TACACS+ and RADIUS from the Docker gateway (
10.255.255.225in the bundle), so an entry covering that address matched all of them. Each one now needs its own entry. If such entries exist and the inventory has no IPv6 entry at all, the update refuses, names them and says what to add (::/0for all); to go on anyway, runTARANAC_IPV6_OWN_ADDRESS_OK=1 ./taranac update. - IPv6 to the client-facing ports no longer passes the host’s ufw INPUT rules, as
IPv4 already did not. Filter it in the
DOCKER-USERchain.
New port, new defaults
- Port 8446 (plain HTTP) is published on every installation — the SCEP listener,
whether SCEP is on or not. If you do not use SCEP, filter it in
DOCKER-USER, or move it withSCEP_HTTP_PORT. - Every RADIUS Access-Reject is answered 1 s later. The Reject Delay setting was never read; now it is, with its default of 1 s. Set it to 0 to answer at once.
- NAC: an OCSP responder URL saved on a Trusted CA now takes effect. The field did nothing until now; a stale URL saved there will refuse every client of that CA. Check it, or clear it.
PKI
- EST Device binding becomes a list of Device accounts. Accounts that have already enrolled are put on it; an account that has not enrolled yet now gets a certificate in its own name — add it to the list first.
- An Internal CA’s certificate field takes exactly one certificate. A certificate pasted with its chain is refused; the chain has its own field now.
Going back
- Going back to 1.3.3 needs
python -m alembic downgrade 0030in this release’s api container (on HA, on the leader) before switching images — or the backup taken before the update — and loses what only 1.3.4 stores: issuing chains, pending CA requests, SCEP settings and more.
An Internal CA signed by your corporate root
NAC → PKI → Import CA takes an intermediate whose issuer is outside Taranac: choose
External CA (issuing chain) and paste every certificate above it, up to and
including the self-signed root, in any order. Taranac keeps the chain with the CA and
hands it out wherever a chain is needed — EST /cacerts, SCEP GetCACert, downloads,
the TACACS+ client-CA bundle and server certificates, child CAs created under it.
The chain never joins EAP-TLS trust: FreeRADIUS verifies clients against the CA alone, so your corporate root does not suddenly admit every domain laptop. A chain that does not reach a self-signed root, holds a certificate off the path, an expired member or a mismatched key identifier is refused with the certificate named. Legal but risky properties — a restricted EKU, name constraints, pathLen 0, an upper certificate that expires before the CA — are shown as warnings.
Around it:
- Upper-chain CRLs are downloaded from the distribution point each certificate names, and can be edited or cleared in place on the issuing-chain card.
- Internal CA chain expires — a daily alert at 90 and 30 days for the earliest expiry in the chain, naming that certificate.
- Replace chain gives a CA signed outside Taranac a new chain. It is also the repair for a corporate SubCA that could only be imported as a root before: it becomes an intermediate and keeps its key, its certificates and its EST setup. Server certificates issued from it pick up the new chain on every node within 30 seconds.
Requested by CSR, renewed with its own key
NAC → PKI → Request (CSR) generates the CA key and a CSR inside Taranac — the key never leaves it. Have your corporate CA sign it (in AD CS, the Subordinate Certification Authority template); the request waits in the CA tree as Awaiting signature until you paste the signed certificate and its chain. It then becomes an Internal CA exactly as an import would make it.
When that CA nears its end, Renew certificate generates a renewal CSR from the same key. The CA keeps its record, its key, every certificate it issued and its CRL; a certificate with another key or subject is refused, because everything already issued would stop verifying. NAC and TACACS+ server certificates send the renewed CA certificate on every node within 30 seconds, with no redeploy.
SCEP beside EST
NAC → PKI Settings has a SCEP card next to EST. Switch it on and devices that speak
SCEP enroll at http://<host>:8446/scep — plain HTTP, because the SCEP clients of Cisco
IOS and MikroTik cannot do HTTPS. /scep/pkiclient.exe and /cgi-bin/pkiclient.exe
work too, AES and 3DES envelopes are accepted (IOS-XE sends 3DES), single DES is
refused.
SCEP is configured on its own: its own CA, validity, approval and networks. Devices authenticate with one shared challenge password, generated when SCEP is switched on; renewal needs none — the device signs it with its current certificate. A certificate issued by EST can be renewed over SCEP and the reverse.
EST got easier to set up as well: the card shows one device enrollment URL with a copy button instead of two ports, every field can be set before EST is switched on, and Device accounts decide which accounts may request a certificate in the device’s own name.
Who may enroll, and who enrolled
- Networks devices may request certificates from — on the EST and SCEP cards, each on its own. A request from anywhere else is refused before its password is checked.
- Wrong EST passwords no longer lock the account. Routers share one, so five wrong passwords could lock out the whole fleet. They now count against the source address: five in 15 minutes block that address for 15 minutes, with an alert and an Unblock button on the card.
- Used by on a CA lists where new certificates come from it — EST, SCEP, Certificate Defaults. A CA in use cannot be deleted.
- Source on issued certificates — Manual, EST, SCEP renewal, NAC server and so on — with a link from a renewal to the certificate it renews.
TACACS+ accepts the inventory, and says why it refused
A device that is not in the inventory no longer logs in with the global key. Its connection is refused, logged as Not in the inventory, and raises an Unknown TACACS+ device alert — for IPv4 and IPv6 alike. Over TLS the same holds whatever certificate the device presents: without it, importing a SubCA would let every holder of a certificate under your corporate root reach the TLS port.
Every connection the daemon refuses before a login can be tried is now a row on the Authentication Log’s TACACS+ tab, in plain words:
- a key mismatch — and whether the key was wrong or none was sent;
- an address not in the inventory;
- a failed TLS handshake — the device does not trust the server’s CA, sent no certificate, sent an expired one or one from an untrusted CA, no common TLS version — with OpenSSL’s own reason in the details.
Repeated refusals from one address are folded into one row per minute, and they do not count as failed logins in the dashboard or the reports. Until now the only trace of a TLS refusal was a syslog line that could not tell an untrusted certificate from an expired one.
Also in TACACS+:
- Applying a change no longer drops connections. The port used to close for a few
milliseconds on every reload; it now stays open (
tac_plus-ngbuilt from thetaranac-2026.10.9tag of our fork). - An MFA push is waited for at most 50 seconds, and a push that failed for a reason outside the person is answered as a failed login, so the device does not fall through to its next server or to local accounts.
- Server certificates: Restore previous, a confirmation before Deploy switches to another CA, an issue form that starts from this node’s addresses and name, and a card that names the node addresses the certificate does not cover.
TACACS+ over TLS checks revocation
A client certificate revoked by an Internal CA — or listed in the CRL of a trusted CA or of an upper-chain certificate — is refused within one 30-second cycle, logged as certificate revoked, without reloading the daemon. A CA without a CRL is simply not checked; the TLS Client Trust card shows where each CA’s revocations come from. A certificate whose AKI names no key identifier no longer crashes a worker.
IPv6 clients are seen by their own address
Until now an IPv6 client arrived from the Docker gateway’s address. RADIUS ignored it as an unknown client — no answer, no log line — unless an inventory entry covered the gateway, which then answered every IPv6 device with one key. The EST gateway did not listen on IPv6 at all.
Now TACACS+, RADIUS, NAC, EST and SCEP, the MFA service, the web interface and the captive portal record, match and rate-limit an IPv6 client by its own address. The stack network carries a ULA /64 for the services clients dial; every other container stays IPv4-only.
- Per-address limits count an IPv6 client by its /64, so walking through the addresses of one network does not escape a limit. Logs keep the full address.
- “Login from a new IP” means a new network: an IPv6 /64 or an IPv4 address.
- A host that takes its IPv6 route from router advertisements keeps it —
install.shand the update setaccept_ra=2where Docker’s IPv6 forwarding would have silenced them.
FreeRADIUS applies a configuration without a restart
A new radiusd starts next to the running one on the same ports. Once it is ready, traffic moves to it; the previous one finishes the requests it already has and exits. No request is lost, and every change is applied this way.
That fixes more than it sounds like. Adding, removing or disabling a CA used to reach FreeRADIUS as a reload it partly ignored: a removed CA kept letting its clients in and a new one was refused until some unrelated restart. A configuration the new radiusd cannot start with is not applied — the previous one keeps serving and the alert RADIUS/NAC configuration not applied gives the reason. Dynamic RADIUS clients now work from their first packet, without a restart.
FreeRADIUS stays at 3.2.10, now built from the taranac-2026.10.4 tag of our fork, with
fixes from the upstream 3.2 branch.
A waiting MFA push holds one thread
While one user’s push waited for approval, the node answered no other RADIUS request — logins, accounting and every 802.1X/MAB request — for up to two minutes. A push approved after the NAS had given up was even recorded as a successful login.
Requests are now served in parallel: a waiting push occupies one worker and nothing else. The answer always leaves in time for the NAS (Max Request Time minus 3 seconds); a push not approved by then is rejected and cancelled, so a late tap is recorded as expired. One user has at most one pending push, at most 16 wait per node (8 in NAC), and the RADIUS log now says why a push failed — denied, not confirmed in time, replaced by a newer login, MFA service unreachable.
CRL and OCSP, per CA
CRL. Enable CRL Check used to make FreeRADIUS require a current CRL from every trusted CA, so a single CA without one had all its clients rejected. Now a certificate is checked against a CRL when some CA of its chain has one configured — an Internal CA always, a Trusted CA or LDAP EAP-TLS CA once it has a CRL URL or an uploaded CRL. Saving a CRL URL downloads the CRL in the same save, or refuses with the reason.
OCSP. Check revocation with OCSP turned OCSP on for every trusted CA at once, and
an unreachable responder held a FreeRADIUS thread for about two minutes — a few such
attempts stopped all NAC authentication on the node. Now OCSP applies to that CA and
its sub-CAs only, with an optional OCSP responder URL that is tested when you save.
A dead responder holds at most 16 of NAC’s now 32 worker threads, for about three
seconds each. OCSP works with Microsoft’s Online Responder (no nonce), and refusals
are logged as tls_ocsp_revoked, tls_ocsp_unknown or tls_ocsp_failed.
./taranac diagnose --protocol nac shows which CAs are checked, how, and which clients
would be refused.
Security
- An emptied TACACS+ global key no longer lets an outside device in. With the global key cleared, requests from addresses outside the inventory were processed with no key at all. The catch-all now always has a key of its own that no device is given.
- RADIUS MFA required by a policy rule is no longer skipped where the MFA mode setting was missing.
- A chain pasted into an Internal CA’s certificate field no longer joins EAP-TLS trust — a corporate root among it would admit every domain laptop. A CA imported that way before keeps those anchors until you take them out with Replace chain, which lists them first.
- FreeRADIUS fixes from the upstream 3.2 branch: EAP-TLS no longer takes an earlier EAP-Identity response as a TLS fragment, and secret attributes are zeroed in memory when freed.
NAC and CoA
- EAP-TLS accepts clients of an issuing sub-CA uploaded as a whole chain; Taranac’s own check refused them as untrusted although the chain had verified.
- A refused client certificate is logged with its real cause — revoked, expired, not
yet valid, untrusted, CRL expired or missing — instead of
auth_failed. - Supplicants get the intermediates:
server.pemis now the leaf followed by its chain. - CoA and Disconnect name the session the way the NAS holds it and carry Event-Timestamp — ArubaOS-Switch dropped or NAK’d them before.
- Profiling: OUI rules match devices that never sent DHCP, a deleted default endpoint group stays deleted, and a group’s scan exclusion stays on when the group is saved.
PKI and EST
- A disabled CA no longer vanishes from CA pickers: it is greyed out with the reason, and issuance refuses with the same reason.
- Every certificate gets a random serial number and names its CA by the CA’s own key identifier, so corporate CAs whose SKI was made another way verify.
- Certificates start one hour in the past, for devices whose clock runs behind.
- EST works with Cisco IOS-XR 25.4.2 (case-sensitive header names) and with requests whose attributes are not in canonical order; the approval queue no longer hides new requests behind 50 old ones.
Collection, SNMP, the dashboard and HA
- NCM collects devices whose output ends in NUL bytes (seen on a D-Link DGS-3130), and a failed collection says which stage failed. Bulk onboarding tells a slow device from an unreachable one, with a probe timeout in the wizard — thanks to @jirilazorcak (#16). Config Tracker names the recipe step that changed the CLI prompt — thanks to @raypnman (#17).
- SNMP fills a device’s OS version and Location, recognises Aruba CX, and a device group’s SNMP profile can be read and set.
- The Palo Alto PAN-OS TACACS+ template matches
service == PaloAltoon new installations — thanks to @beabaul (#26). - The dashboard activity charts draw quiet hours as zero instead of skipping them.
- HA:
cluster verify --rehearsetakes each replica in turn,cluster statusnames a removed witness that is still running at once, andwitness-join.sh --leaveremoves the witness’s images. - Appliance: the 1.3.3 OVA shipped two preloaded images cut short, which broke
add-witness. The update now checks every image’s files against its layers before changing anything and replaces a damaged one — updating cures those appliances. The appliance itself is now built on Ubuntu 26.04 LTS and asks for time servers; see the appliance, on a disc.
1.3.4 is available now through ./taranac update — read
What to do when updating first, and update Docker to 28
before you start. The full list of changes is in the release’s CHANGELOG.md.
Questions about weaving Taranac into your own PKI are welcome through
support.