The issue here is there is NO single system API for looking up user account entries on Linux.
It's implemented in libc. So you need to link to libc. Tailscale is a Go binary, and they probably prefer it to be statically-linked. glibc NSS implementation also REQUIRES you to load `.so` so you just can't emulate it in Go.
But of course there is, it's part of POSIX, implemented in libc. And if you're using a higher level language, they all have their own wrappers around libc/POSIX APIs. Here is golang's: https://pkg.go.dev/os/user
// userLookupGetent uses "getent" to look up users so that even with static
// tailscaled binaries without cgo (as we distribute), we can still look up
// PAM/NSS users which the standard library's os/user without cgo won't get
// (because of no libc hooks). If "getent" fails, userLookupGetent falls back
// to the standard library.
Others have pointed out that os/user.Lookup is a platform-independent way to resolve this, but additionally you don’t _need_ to link against glibc to use it.
If you are writing go, you usually want to set CGO_ENABLED=0 by default, to avoid inadvertently introducing nonportable code. In this way, only the pure Go implementations are used and there is no need to link (statically or dynamically) against a libc implementation to compile and run your programs.
It's implemented in libc. So you need to link to libc. Tailscale is a Go binary, and they probably prefer it to be statically-linked. glibc NSS implementation also REQUIRES you to load `.so` so you just can't emulate it in Go.
Then, "link to libc". Which libc? glibc? musl?