Two new command groups give an AI agent the kubehz api through lo mcp (#244). A security fix keeps credentials off process command lines, in Go and bash (#253).
Added
lo kubehz spaceandlo kubehz cluster. The two groups call the kubehz api with an agent key. They need no project and no cluster spec.bashlo kubehz space list|get|create|delete|lease|kubeconfig lo kubehz cluster list|get|lease|kubeconfig- The commands read the api URL (
KUBEHZ_API_URL, HTTPS only) and the agent key (KUBEHZ_AGENT_CLIENT_ID,KUBEHZ_AGENT_CLIENT_SECRET,KUBEHZ_AGENT_TOKEN_URL,KUBEHZ_AGENT_SCOPE) from the environment. No flag sets them. Without a key, lo sendsKUBEHZ_TOKEN. lo gets the access token with the grant and the cache oflo kubehz token. - Every command takes
-o text|json|yaml. Use-o jsonin a script:-o yamlprints a string such asyeswithout quotes (#246). kubeconfigwrites the agent kubeconfig to--file(mode 0600) and prints the path. It does not replace a file that exists unless you add--force. It refuses a path in/procor/dev. The file holds no secret: its exec stanza runslo kubehz token.- The api enforces the role, the scope, the spend cap and the lease of the key. lo checks only the shape of an id and of a number before it sends a request.
The kubehz guide has a new section, "Agent tools".
- The commands read the api URL (
New
lo mcptools. The Golo mcpoffers the new commands as tools, each in the tier of its marker:- The default (read-only) tier:
lo_kubehz_space_list,lo_kubehz_space_get,lo_kubehz_cluster_listandlo_kubehz_cluster_get. --allow-mutating:lo_kubehz_space_create.--allow-destructive:lo_kubehz_space_delete,lo_kubehz_space_leaseandlo_kubehz_cluster_lease. A shorter lease brings the delete closer.- The two
kubeconfigcommands are never a tool. Their output counts as a credential.
The tiers now hold 29, 53 and 95 tools (before: 25, 49 and 88). The argsh
lo mcpthatlo chatdrives cannot run the new tools yet (#245).- The default (read-only) tier:
Security
Credentials stay off process command lines (#253). Every local user can read the command line of a process (
ps,/proc/<pid>/cmdline), and audit tools such as auditd store it. lo now gives a credential to curl in a config on stdin, to jq on stdin or through--rawfile, and to kubectl in an env file or a merge patch on stdin. Both implementations follow this rule.- The rule covers the Hetzner Cloud token, the Hetzner Robot user and password, the kubehz token, the KKP token and the AWS keys. It also covers the claim nonce of
lo kubehz claim, and the agent token, the claim code and the bind secret in the agent CronJob. - The servers get the same requests as before. In the bash tree, some JSON bodies now end with a line feed.
- In the bash tree,
lo kubehz claim --nonce -reads the nonce from stdin, as the Go binary does. - In the bash tree, the call that gives the Hetzner Cloud token to the platform (
spec.kubehz.connectHcloudToken) refuses a redirect to a URL that is not HTTPS, as the Go binary does. - curl still reads
~/.curlrcfor most calls of the bash tree and for the KKP calls of both implementations. Aconfigortraceline in that file can record what lo sends, the credentials included. Thus keep the file private. - One exception stays:
lo kubehz node joinrunskubeadm join, which takes the short-lived bootstrap token as--token(#252).
The security guide has a new section, "Credentials and command lines".
- The rule covers the Hetzner Cloud token, the Hetzner Robot user and password, the kubehz token, the KKP token and the AWS keys. It also covers the claim nonce of
The Go
lo mcprefuses a positional argument that starts with a dash (#244). Nothing runs. Thus a value such as--forcefrom the model cannot set a flag that the tool does not offer.The Go
lo mcpno longer offerschat.lo chatpasses its arguments on unread. Before v0.8.0, with--allow-mutating, a call oflo_chat --lo <path>ran any file with the environment of the server, an agent key included. The argshlo mcpstill listslo_chat, but its call gets no argument from the model.
Upgrade
- A credential in the environment that holds a control character now stops the call before any request. The error names the variable. The usual cause is a CR at the end of a value from a file with CRLF line ends. Both implementations check
HROBOT_USERandHROBOT_PASSWORD(the Hetzner provider). The bash tree also checksKUBEHZ_TOKENandHCLOUD_TOKEN. It also refuses a CR or LF inKKP_TOKENand in the CAPI credentials, as the Go binary already did. - An editor or agent that called
lo_chatthrough the Golo mcpserver now gets no such tool. A tool call with an argument that starts with a dash is refused. Run these commands yourself. - An existing cluster gets the changed CronJob
kubehz-heartbeatat its nextlo kubehz deploy. The deploy andlo kubehz claimneed no new permission. The CronJob skips a run when the agent token holds a character other than letters, digits and_.~+/=-. A token that the agent made always passes. - The Go
lo kubehz tokenno longer follows a redirect from the token URL. A 3xx answer is now a refusal, as in the bash tree. Set the final URL inKUBEHZ_AGENT_TOKEN_URLor--token-url. - A
lo mcpserver offers the new tools in its tier at once. They act only when the environment of the server holdsKUBEHZ_API_URLand a credential. Give the server an agent key, not your ownKUBEHZ_TOKEN.
Known limits
- Without
--force,kubeconfigcannot write on a file system without hard links, such as vfat or exFAT (#249). Add--forcethere. - In the bash tree,
kubeconfigneeds GNU coreutils (#250). The Go binary does not.