Repository navigation
Use the vendored k3s CA library: root CA with keyCertSign, repair of old devices - #11
Merged
Merged
Conversation
…old devices k3s v1.34.12/v1.35.9/v1.36.5/v1.37.1 and later (k3s-io/k3s#14699) drop CA bundle certificates without keyCertSign. 05_tn_install_k3s.sh copied the device certificate (never a CA with keyCertSign) verbatim to server/tls/root-ca.pem, so a new device hangs on 'CA cert validation failed' and an existing one bricks when the unpinned installer upgrades k3s. - templates/04_tn_k3s_ca_lib.sh: vendored from teknoir/cli pkg/templates/scripts/tn-k3s-ca.sh (VENDORED_FROM pins the commit), plus 04_tn_k3s_ca_guard.sh that keeps the library's stand-alone mode off in the assembled script. - 05_tn_install_k3s.sh calls tn_k3s_ca_setup: re-issues the device certificate as the root from the same key (CA:TRUE, keyCertSign, 20 years); k3s never started: PKI created; started and fine: untouched; started with the old root: repaired with rotate-ca before the installer runs. - test/k3s-ca/: the docker harness, vendored from cli (check-vendored.sh verifies it and the library against the pinned cli commit); test/check-assembly.sh and test/check-setup.sh (offline). generate-custom-ca-certs.sh (the upstream k3s example) is not part of the bootstrap flow and already issues a root with keyCertSign; unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er's info The library now logs with its own functions: on Debian/Ubuntu `info` is the GNU info reader, which a stand-alone run picked up. No change to the bootstrap flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
k3s v1.34.12, v1.35.9, v1.36.5, v1.37.1 and later (k3s-io/k3s#14699, CVE fix) prune every CA-bundle certificate without
keyCertSign.templates/05_tn_install_k3s.shcopied the device certificate (rsa_public.pem, never a CA withkeyCertSign) verbatim toserver/tls/root-ca.pemand issued the intermediate and leaf CAs below it, then installed k3s unpinned from get.k3s.io (stable= v1.36.5 since 2026-10-01). A new device hangs onCA cert validation failed ... x509: certificate signed by unknown authority; an existing device bricks when this script (or anything else) upgrades k3s.Change
templates/05_tn_install_k3s.shcallstn_k3s_ca_setup. It re-issues the device certificate as the root from the same key and subject (CA:TRUE,keyCertSign, 20 years). k3s never started: the PKI is created (a valid one is kept). k3s started and the root is fine: nothing is touched, so re-running the script is safe. k3s started with the old root: repaired first withk3s certificate rotate-ca(and a restart), before the installer below can upgrade k3s;TN_K3S_CA_AUTO_REMEDIATE=falsestops with advice instead; a failed repair stops the script.templates/04_tn_k3s_ca_lib.sh: the library, vendored byte for byte from teknoir/clipkg/templates/scripts/tn-k3s-ca.sh(fix(bootstrap): root CA with keyCertSign; tn-k3s-ca.sh setup, check and remediate cli#7, branchfix/k3s-ca-root-keycertsign) with one header line;VENDORED_FROMpins cli commitb33c6a3.04_tn_k3s_ca_guard.shkeeps the library's stand-alone mode (sh tn-k3s-ca.sh check|remediate) off in the assembled script.test/k3s-ca/: the docker harness (cli GPU Acceleration Addition #6/double quote issue when eval yaml templates #7), vendored the same way, pluscheck-vendored.sh(library and 16 harness files == cli at the pinned commit;--cli <checkout>orgh api), localgo.modfor the harness unit tests.test/check-assembly.sh(assemble the server and agent scripts,sh -n/dash -n, library embedded byte for byte and ordered guard < library < call < installer, no verbatim copy, agent has no server CA),test/check-setup.sh(setup under dash with the bootstrap options, second run keeps the PKI, initialised dir untouched).docs/development.mdexplains how to re-vendor and run it all.generate-custom-ca-certs.sh(the upstream k3s example script; not part of the bootstrap flow, and it already issues its root withkeyCertSign), the agent templates (an agent has no CA of its own; it trusts the device certificate in the OS store as before).EXITtrap is no longer overwritten (the temp dir is cleaned) and the working directory is no longerserver/tls.Evidence
Run from this branch (head
80aebda, library from clib33c6a3) withTN_K3S_CA_LIB=templates/04_tn_k3s_ca_lib.sh test/k3s-ca/run.sh --suite fresh,rerun,remediation,agent,host --gens "bs-o111 go-sha1 expired" -j 3(realrancher/k3scontainers,stable= v1.36.5): 104 / 104 PASS. agent 24 (3 certificate kinds x v1.34.11/.12/v1.36.5/v1.37.1, with and without OS trust), fresh 15, rerun 3, host 6 (remediate --phase alland sourcedtn_k3s_ca_setuprepairing an old root on the host), remediation 56: old scripts on v1.34.11 with an agent and a marker ConfigMap -> remediate -> v1.34.12 -> v1.36.5 withcheck= 0 and a no-op second run, for ubuntu:20.04 (OpenSSL 1.1.1) and debian:bookworm (3.0) helpers; bricked-by-upgrade devices repaired through the post-fix server (--forcefor the device-controller and expired roots); hung fresh bootstrap on v1.36.5 (PKI regenerated); the forced downgrade fallback. The 132-row distro/arch matrix (debian/ubuntu, arm64, armv7) ran against the same library in cli#7.Offline:
test/check-assembly.shpasses (server and agent assemble,sh -n/dash -n, library embedded byte for byte, order guard < library < call < installer);test/check-setup.shpasses;test/k3s-ca/check-vendored.shpasses (viagh api, i.e. against the pushed cli commit);(cd test/k3s-ca && go test ./...)passes. NoPRIVATE KEYin any log, no labelled containers left,k3d-teknoir-devuntouched.Review fixes
The WIP commit on this branch made
05_tn_install_k3s.shcalltn_k3s_ca_setupbut04_tn_k3s_ca_lib.shdid not exist, so any script assembled from it failed at the CA step. It had to wait for the cli library; this PR is opened only now that the library is vendored andcheck-assembly.sh,check-vendored.shand the fresh and remediation suites pass. The WIP call convention (tn_k3s_ca_setup <dir> <cert> <key> <suffix>) was replaced by the library's environment-based one (CONFIG_PATH,DATA_DIR,PRODUCT,_DEVICE_ID,_DOMAIN), andcheck-assembly.sh/check-vendored.shwere adapted (guard variableTN_K3S_CA_NO_MAIN, one header line, the agent rule: the agent adds the device certificate to the OS trust store but prepares no server CA).Second commit
80aebdare-vendors clib33c6a3: CI on cli#7 found that the first library version logged through the caller'sinfo, which on Debian/Ubuntu can be the GNU info reader when the library runs stand-alone; no change to the bootstrap flow. The suites above were run on the re-vendored state.Notes
toev3; merge cli GPU Acceleration Addition #6 and double quote issue when eval yaml templates #7 first: the vendored commit must be reachable on climain(it is on the PR branch now, socheck-vendored.shworks today). After they merge, re-vendor from the merge commit if the SHA changes.Re-review fixes (
76716eb)Re-vendored from cli
ab148da(byte for byte,test/k3s-ca/check-vendored.sh --cli ../clipasses;VENDORED_FROMupdated; the library,k3sverifyandcompat/assert.shchanged). The cli fixes, see teknoir/cli#7 "Re-review fixes":tn_ca_generate_pki: a failed openssl step is a failure (errexit does not work inside the callers'if/||); the generated PKI is validated before server/tls is replaced.tn_k3s_ca_setup: an initialised data dir with a foreign CA whose root k3s refuses (no keyCertSign, or expired) stops the bootstrap with "k3s must not be upgraded", so the unpinned k3s installer in05_tn_install_k3s.shis not reached. A foreign root that only expires soon continues with a warning.tn_ca_reissue_root: random serial for the re-issued root on OpenSSL 1.1.1 too (it ignored-set_serialinx509 -signkey); this affects Jetson Ubuntu 18.04/20.04 and Raspberry Pi bullseye.test/check-setup.sh(this repo, dash with the bootstrap shell options) now also asserts: new serial of the re-issued root, setup fails and leaves no server/tls whenopenssl cafails, setup stops on an unusable foreign CA of an initialised data dir.Results:
test/check-assembly.sh,test/check-setup.sh(17 checks),test/k3s-ca/check-vendored.sh --cli ../cli(library + 16 harness files identical atab148da),(cd test/k3s-ca && go test ./...)all pass. The docker suites ran in the cli worktree against the same library: openssl-compat 132 / 132 and fresh+remediation on v1.34.11 / v1.36.5 26 / 26 (details in cli#7). The 104-case run above was not repeated on this branch. The pinned SHA inVENDORED_FROMis nowab148dab5ea9c5b7272fe35aac64ec2ee0f2e265; re-vendor again from the merge commit if the SHA changes.🤖 Generated with Claude Code
Final fixes (
c014e40)Re-vendored from teknoir/cli
eca0ea1(VENDORED_FROM,templates/04_tn_k3s_ca_lib.sh,test/k3s-ca/;check-vendored.sh --cli ../cliis identical). What changed in the library is described in teknoir/cli#7 ("Final fixes"): data dir resolved like k3s (not hard-coded), safe regeneration, more--forcecases, clear messages after a rotation, k3s too old forrotate-cafails safe.In this repo:
TN_K3S_VERSION="${INSTALL_K3S_VERSION:-v1.36.5+k3s1}"at the top of the server and agent header;INSTALL_K3S_VERSIONis exported before the installer runs in both (stableunsets it: the installer's own choice). Agents must run the version of their server; k3s cannot be downgraded.05_tn_install_k3s.sh. Thedata-dir: /opt/k3sline (andmkdir -p /opt/k3s) is removed: theconfig.yamlwritten a few lines later replaced that file before the installer ran, so it never took effect and devices run k3s from/var/lib/rancher/k3s(the default the library finds; documented indocs/development.md). A non-defaultDATA_DIRthat the library resolved is kept inconfig.yaml, and the manifests go to${DATA_DIR}. The duplicateinfo "Prepare K3s CA Certs"line is gone (the library prints it once).test/check-assembly.sh(pin in both scripts and before the installer,stable/override logic, no dead/opt/k3sline, one CA message, manifests inDATA_DIR) andtest/check-setup.sh(data dir from config.yaml, config.yaml.d, unit ExecStart, under dash) pass;(cd test/k3s-ca && go test ./...)passes.docker_server-style scripts do not exist here. The pin must be kept equal toDefaultK3SVersionin teknoir/cli.