ops kubectl: self-elevate for mutating verbs the same way systemctl does #23
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally filed by @coilysiren on 2026-05-19T09:22:46Z - https://github.com/coilysiren/coily/issues/254
Problem -
coily ops kubectl ...on kai-server fails witherror loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied. The k3s kubeconfig is root-owned on the host (--write-kubeconfig-modedefault), so any kubectl invocation needs to run as root to read it.Bare
coily ssh kai-server -- sudo k3s kubectl apply ...doesn't work either: coily ssh wraps the remote argv intocoily <args>on the destination, so it lands ascoily sudo k3s kubectl ...which trips the policy gate ("flag provided but not defined: -f").This is the same shape as coily#203 -
coily systemctl <mutating-verb>had the same "needs sudo, no audited path through coily" gap. The fix landed in coily#244 (forward outer--commit-scope) and coily#245 (forward outer--cwd): when the verb runs as non-root for a mutating subcommand, re-exec the coily binary undersudo --non-interactive <coily-path> ops kubectl <verb> <args...>, relying on the broad(ALL) NOPASSWD: <coily-path>sudoers grant on hosts that have it.Proposed shape - When
coily ops kubectlis invoked as non-root AND the verb is a mutating one (apply,delete,create,replace,patch,scale,rollout,set,cordon,uncordon,drain,taint,label,annotate,edit):["sudo", "--non-interactive", coilyPath, "--cwd=" + outerCwd, "ops", "kubectl", verb, args...]. Forward--cwdso the inner can resolve scope from the same git toplevel the outer is bound to (mirrors coily#245).r.Runner.Exec(ctx, argv[0], argv[1:]...). No inner sudo.coily systemctlproduces two rows on a self-elevated invocation.Read-only verbs (
get,describe,logs,top,explain,api-resources,api-versions,config view) stay unprivileged. On hosts with--write-kubeconfig-mode 0644they work as-is; on stricter hosts they trip the same permission-denied as the mutating verbs, but the right fix there ischmod 0644on the kubeconfig (or a per-user copy at~/.kube/config), not self-elevation of every read.Cross-links
--commit-scopeso the inner doesn't trip the strict-mode scope gate.--cwdso the inner resolves the same git toplevel.brew servicesmutating verbs. Closed by thecoily brew serviceswrapper (commit61272f3).Test plan - Extend
cmd/coily/ops_kubectl_test.go(or add it if it doesn't exist) with aTestBuildOpsKubectlSelfElevateArgvmirroring the systemctl test shape: each mutating verb produces the right argv (outer sudo, coily binary,--cwd=<toplevel>,ops kubectl, verb, args); read-only verbs produce no sudo prefix; an inner-sudo at argv[1+] trips a security-claim test the same wayTestSecurityClaim_SystemctlSelfElevatesNotInnerSudodoes.Blocks
coily ssh kai-server -- coily ops kubectl apply -f deploy/repo-recall.ymlfirst-apply step that brings the k3s deploy up. Right now the user has to dictatesudo k3s kubectl apply ...directly on kai-server.shipjob in coilysiren/repo-recall/docker.yml once the deploy-user issue (infrastructure#TBD) is resolved -kubectl set imageruns over tailscale ssh today, but acoily ops kubectlpath with self-elevation would let the homelab's audit trail capture the deploy directly.