-
Notifications
You must be signed in to change notification settings - Fork 228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
argument to change uid/gid #927
base: develop
Are you sure you want to change the base?
Conversation
cmd/yggdrasil/main.go
Outdated
@@ -361,6 +364,13 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) { | |||
logger.Errorln("An error occurred starting TUN/TAP:", err) | |||
} | |||
n.tuntap.SetupAdminHandlers(n.admin) | |||
// Change user if requested | |||
if args.chuser != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may make sense to change to nobody:nobody
by default, so things are a little less unsafe for people who just sudo yggdrasil -autoconf
or similar. Thoughts @neilalexander?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Arceliar I think it should be noted that nobody:nobody
is not standard across Linux distros. For example, Debian and friends use nobody:nogroup
instead. We should check which group is available first or maybe use something like Dynamic Users in systemd (use a random UID/GID that's currently not in use by the system).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could just use nobody
and maybe it would just resolve primary group on its own i think?
also would need to check UID being 0 before doing chuser by default (as this can be started as own user if right caps are given).
and opting out may be kinda uglier - manually specifying empty user string, though i can't really find many reasons of opting out, other than some possible exotic distributions/installations without proper user databases - which i guess i could imagine in some sterilized docker environments or routers but i don't really know how common, and probably checking existence of nobody
user before deciding to default to chuser'ing to it would make sense - and we could just check database before setting default to nobody
, likely writing function in chuser_unix.go for that (& stub returning empty string in chuser_other.go).
Requesting opinions for this mindfuzz of mine i guess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this a bit more and probably programming in this kind of logic into daemon itself is too much of a magical behavior imo, and this should be provided in distributions' .service
files instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well there isn't any need for this to be in any distro, Debian has a pretty hardened default that runs as yggdrasil user from the start. I think all you need to get it to work is CAP_NET_ADMIN, I think this is how Debian configured their OpenVPN services too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. This packaging is indeed fairly good. This has gotten a bit offtopic, but it would be cool if one could specify default socket / config path at compile time (eg using go build -ldflags="-X defaults.defaultAdminListen=unix:///var/run/yggdrasil/yggdrasil.sock"
) so that linux distros wouldn't need patches there to achieve saner packaging.
Either way this repo's systemd files suck at running non-root, and so consequentially do vendor (not official debian's) debs and archlinux package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the whole, I'm very pro-having separate flags for UID and GID, because then it is clearer that we can do one without the other, and it is easier for packagers to do the right thing for their distribution/platform.
I'm not entirely sure whether we want to do that by default — we could certainly do some testing to see how it feels. The main thing I can think of that might break is setting up new multicast sockets when an interface disappears and reappears later but we've already dropped privileges, but maybe it'll be OK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually isn't that what #817 is doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#817 can take only numeric UID/GIDs, which is unwieldy.
because then it is clearer that we can do one without the other
why would you want do one but not another? everywhere i looked around, one either wants to set uid and also gid to primary group of uid, or uid/gid separate, which is also possible. with this implementation, one can also set gid without uid (eg -user ":groupname"
or -user ":gid"
), though it may be a little bit unobvious, but why would you want to not drop root?
if you think that instead of using -user uid:gid
syntax we should do -uid user -gid group
, i can change to that too, looks like a minimal change to me.
The main thing I can think of that might break is setting up new multicast sockets when an interface disappears and reappears later but we've already dropped privileges, but maybe it'll be OK?
that's sorta fundamentally incompatible with privilege dropping tbh. on linux, we could probably do some magic with caps and reserve the right to deal with interfaces, but on other unixes we can't. restarting daemon when new interfaces to be managed pop up could probably make sense, but i don't quite feel that's what yggdrasil should do on its own either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless multicast actually works without requiring root (i somehow confused it with managing interfaces, and using multicast aint that)
I looked around a bit, and git daemon implements this in a bit cleaner way, maybe, command line arguments wise:
Though nsd for example uses different syntax, using |
5a0470e
to
8ce7c86
Compare
rebased. does this need any further work? |
I haven't forgotten about this — I'd like to get this merged in some shape or other, but let's wait until the v0.5 branch is a bit cleaner before rebasing there. |
If you're happy to rebase one last time on top of |
@neilalexander done. |
|
||
if g != nil { | ||
gid, _ := strconv.ParseUint(g.Gid, 10, 32) | ||
err := syscall.Setgid(int(uint32(gid))) |
Check failure
Code scanning / CodeQL
Incorrect conversion between integer types High
strconv.ParseUint
} | ||
} else if u != nil { | ||
gid, _ := strconv.ParseUint(u.Gid, 10, 32) | ||
err := syscall.Setgid(int(uint32(gid))) |
Check failure
Code scanning / CodeQL
Incorrect conversion between integer types High
strconv.ParseUint
|
||
if u != nil { | ||
uid, _ := strconv.ParseUint(u.Uid, 10, 32) | ||
err := syscall.Setuid(int(uint32(uid))) |
Check failure
Code scanning / CodeQL
Incorrect conversion between integer types High
different from #817 in that it can resolve user names, automatically use user's primary gid & allows specifying gid in the same argument, with
:
egusername:groupname
.feel free to criticize & suggest different argument name & description because i didn't put much of thought to that.