Scripts That Need (some) Root Access
I have a general question about system administration scripts that require "some" commands to be executed with root access, and other as a normal non-root user (ie myusername, etc.). I should mention I'm using Ruby 1.8.6 on a Linux Red Hat 4 system. The suggestions I've seen so far are:
- Allow access from sudoers:
USERNAME = NOPASSWD: /path/to/script, /etc/init.d/httpd, /path/to/somethingelse
Is this syntax correct? If so, am I correct that I would want to list all the specific commands needed in the script where I did not want to be prompted for password?
- Set suid
http://www.wellho.net/mouth/733_Perl-for-Systems-Admin-suid-scripts.html
To run a Perl script with root privilage:
a) Set the owner of the script to root
b) Set the suid bit on the file on (chmod u+s filename)
c) Turn off read permission, and on execute permission to the file to everyone except root (chmod go=x)
But other research suggests that you can only set suid on binaries for later Linux systems (my script will actually run on an older version of RH4 but we may end up upgrading so I'd like to be forward compatible). I don't think I want to create a binary just for this!
- 'Use ssh with generated public/private keys. The key can be configured to allow only certain commands to be execute with it.'
- Leave in sudo for any scripted commands that require root:
system 'sudo rake ts:rebuild' (of course this has the drawback of having all those password prompts!)
- Execute script as root
But what about commands I want ran as a normal user?
- Execute as root su username (for tasks that need to be ran as the normal user)
'Run script as root, do a bunch of tasks as root, su newUser do a bunch of tasks as newUser, exit (exits back to the root user) do a bunch more tasks as root.' (proposed by James below)
I feel ashamed to not have a better grasp of this topic, but I'm a bit surprised at how many Ruby "scripting books" I referred to that do not address this! I guess it's more of a 'nix thing, but it seems that to do any thing of substantial use, you'd likely run into this.
Edit: Some things like mysql I can use options in the command like --password so I've used this to do that:
puts "Remote Password: "
system('stty -echo')
password = STDIN.gets.chomp
puts "Mysql Password (local): "
mysql_local_password = STDIN.gets.chomp
system('stty echo')
And then I can use those passwords from within the script but they never get seen as clear text. But this doesn't work for everything of course.
The other thing I should mention is that there commands that need to be ran as different users (in addition to just root and one normal user, there may be a 'build' user, etc.,etc)
Question: Please help me to understand the pros and cons of these (and any other proposed or better solutions). Also, if there's a definitive book, links, man pages, etc., that addresses how scripts interact with the underlying system's permissions that you can refer me to that would be great as well.
Thanks all!
Solution 1:
Did you ever looked into things like capistrano, puppet, ansible or chef for your tasks?
You don't mention what's the scope of you work is, so I have no idea if they are of any use to you.
I would avoid "suid" at any cost. There is no point of using it having sudo installed, which seems to be the best choice for your requirements of running commands with different permissions/user ids ('sudo -u user2 command2', etc) .
Also you might want to run some sudo commands password-less as permitted commands in you key-based ssh session (ssh sshkeyaccessonlyuser@yourhost 'sudo command'). This can take care of the caching problem if you don't want to have longer password caches in sudo, and your script will not finish running a sudo command in time.
Solution 2:
Yes, you can su to any user in a script as root without requiring a password. This is a bit of a hack, but it will work. You might have some hiccups along the way (your environment changes when you su, for instance), but you'll be able to make it work. I don't think it's "right". Also, root can do everything, so you can always find a way to do everything as root.
I recommend using sudo for everything.
For interactive stuff, sudo with password prompts is OK. I prefer it to prompt you for your own password, not root's. This way you can grant limited administrative rights without giving away root's password (and thus, full privileges). Having to type your password is good for the "hey! I'm typing my password, this means I'm doing something potentially dangerous, let's check before I type". You can also set sudo not to prompt repeatedly for passwords (i.e. once you type it in, sudo invocations within n minutes do not prompt).
Also, you can make sudo let a user perform any action as root, not just a limited set of commands. I use this on boxes I admin; it's nicer than "su -", gives you some audit stuff out of the box, you can always "sudo -i" (or "-s", sometimes) to get a root shell, etc.
For noninteractive stuff, there's more choice.
I'm not very fond of suid binaries. This should be used only for very commonly used binaries which need root privileges, which are very simple and which have been thoroughly audited. ping, for instance, requires root privileges to do its work. However, any security flaw in a suid binary is potentially very dangerous.
Using ssh is a very complex way of achieving this.
Use sudo, set it up to not require a password for the specific commands the script requires. "man sudoers" is a long read, but definitely interesting- there's so much stuff you can do with sudo...
Solution 3:
I'd go with #4:
Leave in sudo for any scripted commands that require root: system 'sudo rake ts:rebuild'
You don't need to worry too much about repeated password prompts; sudo will cache the fact that you authenticated with a password for a short while (around 5 minutes by default. From the man page:
Once a user has been authenticated, a timestamp is updated and the user may then use sudo without a password for a short period of time (5 minutes unless overridden in sudoers).
from man sudoers
:
timestamp_timeout
Number of minutes that can elapse before sudo will ask for a passwd again. The default is 5. Set this to 0 to always prompt for a password. If set to a value less than 0 the user's timestamp will never expire. This can be used to allow users to create or delete their own timestamps via sudo -v and sudo -k respectively.
So as long as the script is going to take <5 minutes to run, the user should only see one password prompt - none at all if they've authenticated recently.