Do root stuff while not root



  • As a part of a new management feature, I need to perform certain root level actions: update some files inside the /etc directory, call service restart and similar. I'm intentionally keeping it vague to avoid the usual "why don't you use the existing utility/library xxx". There are good reasons why I'm writing this code myself.

    Anyway, as I mentioned in an earlier threads, I always run my production code as an unprivileged user. So, that's a problem if you need to do the aforementioned root-level tasks.

    I came up with 3 scenarios of getting this done.

    ###1. Group with elevated rights

    Add my app's account into a special purpose group. Make the target files and processes owned by that group.

    Upsides: The canonical Linux way? Administration level fix, no coding needed
    Downsides: Maybe too much administration? Not comfortable with that. What if groups overlap? Can I do this for commands like service restart?

    ###2. Sudoers
    I didn't look into this, but I vaguely recall hearing you can make an account into a sudoer with very specific rights.

    Upsides: Maybe a bit less administration than 1?
    Downsides: Is it even possible? Can I isolate the rights sufficiently? Can I do application level stuff using sudo (eg. move file) without reaching into shell interop? Even less comfortable with this.

    ###3. Manager script
    The solution closest to my programmer heart. Write a separate script and put it in root's cron. My unprivileged program prepares an update and saves it in a directory. Cron script detect there is a new job, executes the update and clears the files.

    Upsides: I'm most comfortable with this. Seems the most secure. Deployment is not an issue with the kind of scripts I have.
    Downsides: Additional coding needed. Code smell (feels WTF-y).


    Thoughts? How do YOU handle stuff like this? Something I'm missing? Is there a better way to do this?


  • FoxDev

    @cartman82 said:

    2. Sudoers

    I didn't look into this, but I vaguely recall hearing you can make an account into a sudoer with very specific rights.

    Upsides: Maybe a bit less administration than 1?Downsides: Is it even possible? Can I isolate the rights sufficiently? Can I do application level stuff using sudo (eg. move file) without reaching into shell interop? Even less comfortable with this.

    you can do this. it's the preferred wau of allowing users to access some parts of a comand but not others (for example being able to so service httpd restart but not service network restart)

    it's actually really straightforward to set up, but the syntax is a little arcane and can take a while to grok. when editing always use visudo (which runs $EDITOR so you don't have to use vim) to do the edits, it won't let you save a malformed sudoers file that way.



  • @accalia said:

    you can do this. it's the preferred wau of allowing users to access some parts of a comand but not others (for example being able to so service httpd restart but not service network restart)

    Hmm... ok, I can imagine using this for the execute command part. I'd still have to use some other method to update files.

    Unless I write a bash script to handle that. But then, we're back into the territory of approach #3.

    @accalia said:

    it's actually really straightforward to set up, but the syntax is a little arcane and can take a while to grok. when editing always use visudo (which runs $EDITOR so you don't have to use vim) to do the edits, it won't let you save a malformed sudoers file that way.

    I know this, I've messed around with visudo before. I've just never tinkered with the fine-grained access rights.



  • @cartman82 said:

    Hmm... ok, I can imagine using this for the execute command part. I'd still have to use some other method to update files.

    You can specify which file the user is allowed to edit as part of the sudo command, e.g. in /etc/sudoers

    cartman82 ALL=/usr/bin/rvim /etc/foo.conf

    That said, I'd do Option 1 for editing and option 2 for restarting. Option 1 may or may not work for restarting, it depends heavily on the exact behavior of the application in question.

    Edit: straght vi allows escaping to a shell.



  • @cartman82 said:

    How do YOU handle stuff like this?

    Combination of 1 and 2.

    addgroup systemfuckers
    adduser myappaccount systemfuckers
    visudo /etc/sudoers.d/50-systemfuckers
    

    Understanding man sudoers involves trying to make sense of syntax specified in EBNF without enough examples, so here's an example:

    In /etc/sudoers.d/50-systemfuckers:

    # Members of the systemfuckers group may fuck the system
    # without supplying a password
    
    Cmnd_Alias FUCKSYSTEM = \
            /bin/cp * /etc/iptables/rules.v4, \
            /usr/sbin/service iptables-persistent restart
    
    %systemfuckers ALL = NOPASSWD: FUCKSYSTEM
    

    The last line can be read as "members of group systemfuckers can invoke sudo on any host, with no password required and no restriction on target user or group selected via -u and -g options, to run any command matching one from the FUCKSYSTEM alias definition".

    Things to note about the sudoers file:

    1. If you leave the % off the front, the permission entry refers to a user account rather than a group.
    2. Yes, Cmnd_Alias really does need to be spelt that way, and case matters, and aliases should be all-uppercase (can't remember if that last one is requirement or convention. Do it anyway).
    3. The command alias definition is a comma-separated list. Whitespace before each command in the list is ignored. The \ at the end of each of the lines above escapes the immediately-following newline to form a line continuation. The * wildcard above is matched by sudo, not by the shell, so this entry gives the systemfuckers group permission to copy anything to /etc/iptables/rules.v4.
    4. Careful sysadmins always use absolute paths to commands listed in sudoers files. Sudo does do some sanity filtering on the PATH variable but caution is a good thing.

    The shitty man page is the reason most people go looking for over-complicated ways to avoid using sudo, a tool invented specifically to deal with the use case you're asking about. It's worth ploughing through the shitty man page, because sudo really is well engineered. Not using it for this job is the moral equivalent of rolling your own date and time library.

    Edit: the systemfuckers group exists solely to give sudo something to match against the process that invokes it. The group you'd actually use for file access control depends on the -g option you pass to sudo. I've never used -u and -g because if you leave them out they default to root:root but that's probably slack.



  • @cartman82 said:

    Can I do application level stuff using sudo (eg. move file) without reaching into shell interop?

    You should be able to execve() sudo directly without going through a shell, and have it invoke mv for you. As long as the arguments you pass it match something a sudoers file says it's allowed to do, it will do it.


  • Discourse touched me in a no-no place

    @flabdablet said:

    addgroup systemfuckers
    adduser myappaccount systemfuckers

    I've never dealt with this much, but can't you addgroup systemfuckers, and NOT add yourself to that group, and then chgrp systemfuckers when you want to do something that requires group systemfuckers perms?



  • @FrostCat said:

    I've never dealt with this much, but can't you addgroup systemfuckers, and NOT add yourself to that group, and then chgrp systemfuckers when you want to do something that requires group systemfuckers perms?

    Only if you set a password for the group, which almost never happens. Either way, adding the users to the group means they get the group membership without needing to explicitly request it.

    It would be better security to do the chgrp, since you only have permission for the group when you request it, but it adds an arcane prerequisite step that the user needs to execute. Users will frequently fail to do so, and then complain about the permissions not working. Unless your security profile is really tight, better to just add the users to the group.

    ETA: Shared passwords (for the group) suck to manage, such as when someone gets fired and someone needs to change (and everyone else needs to receive) the new password. OTOH, if the list of users changes frequently, you probably don't want to be in the business of manually updating the group membership.

    Edit 2: I think you meant newgrp, not chgrp. If you actually meant chgrp, I don't know how to parse your question.



  • @jello said:

    You can specify which file the user is allowed to edit as part of the sudo command, e.g. in /etc/sudoers

    cartman82 ALL=/usr/bin/vi /etc/foo.conf

    Don't do this! It's not safe. cartman82 will still have vi running with elevated privileges. Though the only thing you've given cartman82 the right to do is run /usr/bin/vi /etc/foo.conf as root, he can then get a root shell by typing :!bash into vi.

    There are programs for which this functionality is useful, but vi certainly isn't one!


  • Discourse touched me in a no-no place

    @jello said:

    Edit 2: I think you meant newgrp, not chgrp. If you actually meant chgrp, I don't know how to parse your question.

    I thought 'chgrp x' meant 'temporarily join group x'. I haven't done this kind of stuff in ten years.



  • @flabdablet said:

    Combination of 1 and 2.

    Thanks for the excellent info.

    The problem with both #1 and #2 approach is that they're administration heavy. In my use-case, I'm trying to make as much of administration as possible automated. How would I even test if this sudo will work other than actually doing the thing?

    I'm sure it's possible. I'll just have to sit down and dig into it. Too tired now. Tomorrow.

    @flabdablet said:

    You should be able to execve() sudo directly without going through a shell, and have it invoke mv for you. As long as the arguments you pass it match something a sudoers file says it's allowed to do, it will do it.

    What I meant was, right now I can move files using nice (for example) node.js libraries. If I move to sudo approach, I'll have to do everything using hand crafted commands. Don't like.

    @marinus said:

    Don't do this! It's not safe. cartman82 will still have vi running with elevated privileges. Though the only thing you've given cartman82 the right to do is run /usr/bin/vi /etc/foo.conf as root, he can then get a root shell by typing :!bash into vi.

    There are programs for which this functionality is useful, but vi certainly isn't one!

    These will all be automated operations. I wouldn't use vi anyway.

    But that's a good point. Need to make sure sudoed commands can't actually be used to cause mischief.



  • @marinus said:

    Don't do this! It's not safe. cartman82 will still have vi running with elevated privileges. Though the only thing you've given cartman82 the right to do is run /usr/bin/vi /etc/foo.conf as root, he can then get a root shell by typing :!bash into vi.

    Ouch. This is why you don't do quick and dirty security rules. Or blindly follow something you found on the internet.

    @FrostCat said:

    I thought 'chgrp x' meant 'temporarily join group x'. I haven't done this kind of stuff in ten years.

    chgrp changes file permissions. newgrp joins a user to a group.


  • Discourse touched me in a no-no place

    @jello said:

    chgrp changes file permissions. newgrp joins a user to a group.

    Then I definitely meant newgrp.

    You wound up understanding what I was trying to convey, anyway: put the permissions on a group, and then have the user temporarily join the group when they need to run a command. I understand the disadvantages you mentioned, but this does let you make things fairly fine-grained, and you don't have to worry about "one group being used for two different permissions:" use two groups.



  • @FrostCat said:

    you don't have to worry about "one group being used for two different permissions:" use two groups.

    The newgrp isn't required to use two groups for different permissions. Users can be members of multiple groups at the same time. Maybe I'm misunderstanding you.


  • Discourse touched me in a no-no place

    @jello said:

    The newgrp isn't required to use two groups for different permissions. Users can be members of multiple groups at the same time. Maybe I'm misunderstanding you.

    Nah: one group for each permission, and then newgrp as required when you need to run a given command. I guess you could do the opposite of a newgrp if there's such a thing, once you were done for a permission.

    Someone upthread mentioned a problem where you could logically have two permissions under the same umbrella; whether it was the same group or sudo command or something I don't recall. I was just saying, you can be as fine-grained as you want, by making as many groups as you needed.


  • Discourse touched me in a no-no place

    Late to the party, but other options, possibly/probably not suitable for your particular problem, but listed for completeness:

    • suid/guid? Think passwd - it does stuff that needs root permissions, but can be run by any user.

    • capabilities? Think wireshark - there's (admin, admitedly) things you can do to allow users to access network interfaces (usually root/elevated) without giving them access to everything.


  • Java Dev

    @PJH said:

    - capabilities? Think wireshark - there's (admin, admitedly) things you can do to allow users to access network interfaces (usually root/elevated) without giving them access to everything.

    AFAIK, there is no 'set capabilities' flag you can put on a binary/script, though it's been a while since I looked into it. At the time the only way to get capabilities was to go up to full root first. I even think setuid() to non-root made you lose all capabilities...



  • @PleegWat said:

    AFAIK, there is no 'set capabilities' flag you can put on a binary/script, though it's been a while since I looked into it.

    On somewhat recent systems there is setcap(8) which does this. Not sure if it works on shell scripts, tough.

    @PleegWat said:

    At the time the only way to get capabilities was to go up to full root first. I even think setuid() to non-root made you lose all capabilities...

    Yes, I’ve learned that the hard way... Not sure why it does this.


Log in to reply