-
Notifications
You must be signed in to change notification settings - Fork 246
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
[Security] do not run as root. #816
Conversation
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.
Looks fine
@@ -7,7 +7,7 @@ package defaults | |||
func GetDefaults() platformDefaultParameters { | |||
return platformDefaultParameters{ | |||
// Admin | |||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock", | |||
DefaultAdminListen: "unix:///var/run/yggdrasil/yggdrasil.sock", |
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.
This breaks running if the /var/run/yggdrasil
folder doesn't exist, so the default depends on the systemd package (or otherwise creating the folder). The binary produced by ./build
needs to be able to run with default settings (i.e. -autoconf
) with no further changes to the OS/environment.
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 didn't test this and indeed if yggdrasil does not try to create the directory in which it wants to place the socket (which IMOHO is a bug) then this will fail.
An actual go progammer is required to make ygg create the directory before it attempts to create a file in it. I am not a Go programmer, would appreciate a patch. I guess its not too complex.
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.
No problem, default socket path can be different if run with -autoconf
. Probably, it should be created in user's home directory if run this way.
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.
good point. Likely best to use /run/user/{UID}/ which is where Linux by default makes those.
For instance wayland creates its sockets there.
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.
No, it's bad to hardcode this path. The better way would be to use contents XDG_RUNTIME_DIR
environment variable if it's present, otherwise something like .yggdrasil.sock
in user's home directory. I presume, this will be a good default for those who still insist on not using systemd
.
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, defaults should be dependent on whether config is generated by regular user or root
(not on -autoconf
option).
Regular user should have everything in the home directory (and socket $XDG_RUNTIME_DIR
if this variable is present).
But for root
user everything should be in LSB-conforming directories (config in /etc/yggdrasil
, socket in /run/yggdrasil
).
To followup after the discussion on matrix.
I would be very sad if yggdrasil would turn off the admin interface before there is a replacement as that makes deployment and sysadmin-jobs much harder. |
One more thing to add: Running as an unprivileged user means the old EDIT: One more thing to add. We can make the |
Yes, this is one of those problems: what is the ideal time to do this? Before 0.4.0, the second best time to do this? Now. The solution there is for packagers to add an 'upgrade' line. Ygg does not have to do anything as the problem does not exist for people using its compiled binary.
That is possible. Sounds complicated compared to simply doing a makedir. This has the advantage that your second systemd config file is the one that actually calls genconf and thus this change has lower impact. |
Why not just drop root privileges after socket file setup? |
Here are some suggestions to make this work better: Don't create a yggdrasil sysusers file, and instead use the DynamicUser option:
(Note: User must not match yggdrasil here, since it isn't defined statically) Also, set:
ProtectSystem=strict prevents it from modifying basically anything on the filesystem, so therefore we have to specify the possible locations for the runtime directory under ReadWritePaths. |
@jgoerzen sounds like an interesting idea. Seems to make the systemd deployment one file, which is nice. Would you be able to comment on the minimum version of systemd needed for all the features your idea uses? |
Sure. Per the systemd NEWS file:
As far as I can tell, this is supported by all major distributions that are under active support. Versions of systemd in Debian that are still under standard or Long-Term Support (LTS):
Versions of systemd in Ubuntu that are still under general support:
Versions of systemd in Fedora that are still under general support:
RHEL/CentOS forks RockyLinux and AlmaLinux are both shipping version 239, as did CentOS 8. Various version comparisons can be found at https://pkgs.org/download/systemd |
An Internet accessible service should aim to have as little as possible attack surface, which is much easier to do when running with the absolute minimum number of priviledges. This makes the systemd setup run the service as a user 'yggdrasil' and uses the systemd feature `RuntimeDirectory` to auto-create the /var/run/yggdrasil dir so our non-elevated client can still create the socket. The sysusers file will cause the user be created on first install using the sysusers subsystem.
The `AdminListen` option and `yggdrasilctl` now default to `unix:///var/run/yggdrasil/yggdrasil.sock` on Linux This allows yggdrasil to be run as its own user. Closes yggdrasil-network#802
I tested this new idea on my archlinux (i.e. latest) and also on my server which is debian old-stable (v 9).
I'll push an update shortly. |
Also use some stricter security features systemd provides. This change from github user John Goerzen @jgoerzen as provided in his comment: yggdrasil-network#816 (comment) ProtectSystem=strict prevents it from modifying basically anything on the filesystem, so therefore we have to specify the possible locations for the runtime directory under ReadWritePaths.
An update: Per discussion in Matrix, CAP_NET_RAW is no longer necessary. You may be interested in the service file I'm shipping with the package that will go into Debian; it's linked at #874 (comment) |
I removed |
5a0470e
to
8ce7c86
Compare
Closing in favour of #927. |
An Internet accessible service should aim to have as little as
possible attack surface, which is much easier to do when running
with the absolute minimum number of priviledges at all times.
This makes the systemd setup run the service as a user 'yggdrasil'
and uses the systemd feature
RuntimeDirectory
to auto-createthe /var/run/yggdrasil dir so our non-elevated client can still
create the socket. (see #802)
The sysusers file will cause the user be created on first install
using the sysusers subsystem, this can be used by packagers as well.