fix(daemon): use numeric uid/gid when creating tap to avoid silent skip

user.Current() can return an error under hardened systemd units / static
builds, causing the user/group flags to be silently dropped on
`ip tuntap add` and leaving the tap root-owned. The child QEMU then
runs as spinifex-daemon, fails the tun_chr_open owner check, and exits
with "could not configure /dev/net/tun: Operation not permitted" before
writing its PID file — the LB microvm never boots and the load balancer
sticks in failed/provisioning state.

Reproduced in E2E nightly cell-17 (single/static/debian-13/tofu-examples)
run 26047315237 on the nginx-alb workbook at commit 4ae2a4a (the
microvm-elbv2 merge that introduced the prior user.Current() fix).

Pass os.Geteuid() and os.Getegid() numerically instead — always available,
no NSS lookup, no silent fallthrough.

Closes mulga-siv-110
This commit is contained in:
joshsiv-mulga
2026-05-19 13:16:56 +10:00
parent a7a1222495
commit fcb17db4ab
+8 -6
View File
@@ -6,8 +6,8 @@ import (
"net"
"os"
"os/exec"
"os/user"
"sort"
"strconv"
"strings"
"github.com/mulgadc/spinifex/spinifex/utils"
@@ -55,12 +55,14 @@ func (p *OVSNetworkPlumber) SetupTap(spec vm.TapSpec) error {
// (drivers/net/tun.c: tun_chr_open + TUNSETIFF perm check). Without the
// `user` flag the tap defaults to root:root and qemu's TUNSETIFF fails
// with EPERM ("could not configure /dev/net/tun: Operation not permitted").
// Root daemons skip this — they have CAP_NET_ADMIN ambient.
// Pass numeric uid/gid directly — user.Current() can fail silently under
// hardened systemd units / static builds, dropping the flags and leaving
// the tap root-owned (LB microvm in cell-17/tofu-examples). Numeric values
// always work and skip the NSS lookup. Root daemons skip this — they have
// CAP_NET_ADMIN ambient.
addArgs := []string{"tuntap", "add", "dev", spec.Name, "mode", "tap"}
if os.Geteuid() != 0 {
if u, err := user.Current(); err == nil {
addArgs = append(addArgs, "user", u.Username, "group", u.Gid)
}
if uid := os.Geteuid(); uid != 0 {
addArgs = append(addArgs, "user", strconv.Itoa(uid), "group", strconv.Itoa(os.Getegid()))
}
if out, err := sudoCommand("ip", addArgs...).CombinedOutput(); err != nil {
return fmt.Errorf("create tap %s: %s: %w", spec.Name, strings.TrimSpace(string(out)), err)