From df6aca888c8a1611383cfaaaaa34a834b18bf6eb Mon Sep 17 00:00:00 2001 From: root Date: Wed, 20 May 2026 17:48:32 +0200 Subject: [PATCH] homelab: re-exec 'secret' via sudo for non-root users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /etc/age/key.txt is 0600 root and /etc/age is 0700 root, so the CLI's Path.exists() check was returning False under regular users — making the subcommand look broken when bootstrap had actually written the key fine. Re-exec via sudo preserves the existing UX (one password prompt, then plaintext) without loosening the key's perms. Co-Authored-By: Claude Opus 4.7 (1M context) --- bin/homelab | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/homelab b/bin/homelab index a5d4835..d3fe674 100755 --- a/bin/homelab +++ b/bin/homelab @@ -263,6 +263,15 @@ def cmd_secret(args: argparse.Namespace) -> int: path = CONTEXT / "secrets" / f"{name}.yaml" if not path.exists(): die(f"no secret '{name}' (looked for {path})") + # The age key lives at /etc/age/key.txt (root:root 0600) so non-root + # users can't read it — or even stat it, since /etc/age is 0700 root. + # Re-exec via sudo when invoked as a regular user. + if os.geteuid() != 0: + return subprocess.call([ + "sudo", "-E", + "env", f"SOPS_AGE_KEY_FILE={AGE_KEY}", + "sops", "-d", str(path), + ]) if not AGE_KEY.exists(): die(f"no age key at {AGE_KEY} — has bootstrap run?") env = {**os.environ, "SOPS_AGE_KEY_FILE": str(AGE_KEY)}