Skip to content

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 space and lo kubehz cluster. The two groups call the kubehz api with an agent key. They need no project and no cluster spec.

    bash
    lo 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 sends KUBEHZ_TOKEN. lo gets the access token with the grant and the cache of lo kubehz token.
    • Every command takes -o text|json|yaml. Use -o json in a script: -o yaml prints a string such as yes without quotes (#246).
    • kubeconfig writes 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 /proc or /dev. The file holds no secret: its exec stanza runs lo 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".

  • New lo mcp tools. The Go lo mcp offers 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_list and lo_kubehz_cluster_get.
    • --allow-mutating: lo_kubehz_space_create.
    • --allow-destructive: lo_kubehz_space_delete, lo_kubehz_space_lease and lo_kubehz_cluster_lease. A shorter lease brings the delete closer.
    • The two kubeconfig commands 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 mcp that lo chat drives cannot run the new tools yet (#245).

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 ~/.curlrc for most calls of the bash tree and for the KKP calls of both implementations. A config or trace line in that file can record what lo sends, the credentials included. Thus keep the file private.
    • One exception stays: lo kubehz node join runs kubeadm join, which takes the short-lived bootstrap token as --token (#252).

    The security guide has a new section, "Credentials and command lines".

  • The Go lo mcp refuses a positional argument that starts with a dash (#244). Nothing runs. Thus a value such as --force from the model cannot set a flag that the tool does not offer.

  • The Go lo mcp no longer offers chat. lo chat passes its arguments on unread. Before v0.8.0, with --allow-mutating, a call of lo_chat --lo <path> ran any file with the environment of the server, an agent key included. The argsh lo mcp still lists lo_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_USER and HROBOT_PASSWORD (the Hetzner provider). The bash tree also checks KUBEHZ_TOKEN and HCLOUD_TOKEN. It also refuses a CR or LF in KKP_TOKEN and in the CAPI credentials, as the Go binary already did.
  • An editor or agent that called lo_chat through the Go lo mcp server 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-heartbeat at its next lo kubehz deploy. The deploy and lo kubehz claim need 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 token no longer follows a redirect from the token URL. A 3xx answer is now a refusal, as in the bash tree. Set the final URL in KUBEHZ_AGENT_TOKEN_URL or --token-url.
  • A lo mcp server offers the new tools in its tier at once. They act only when the environment of the server holds KUBEHZ_API_URL and a credential. Give the server an agent key, not your own KUBEHZ_TOKEN.

Known limits ​

  • Without --force, kubeconfig cannot write on a file system without hard links, such as vfat or exFAT (#249). Add --force there.
  • In the bash tree, kubeconfig needs GNU coreutils (#250). The Go binary does not.

Released under the MIT License.