Is this just me, or the remote HTTP API only works as root?
Example, I only want to create an email forwarding on an account or modify it sporadically, this does not work using the account credentials but only works as root which seems very, but very, well, something nobody in their right mind would use, pass root details on an API request.
I don’t want to believe this is the case and that I’m just overlooking something regarding giving the user the proper API permissions.
Unfortunately, you’re not wrong. The credentials don’t have to be the actual root user, I don’t think, but the operations of the API are root-level actions. You pretty much have to consider it a root user. This isn’t ideal, but somewhat hard to avoid; by that, I mean, everything related to creating users, configuring Apache/nginx, etc. are operations that require root permissions, so to make it not root, there would need to be a completely abstraction layer that passes the actions back and forth; and, it’d be extremely difficult to prevent escape (and some Virtualmin operations would be impossible, even with such an abstraction layer, to make “safe” enough to pretend it’s not a root level API).
I’m not saying we shouldn’t do it. We should, and it’s been on Jamie’s radar for some time. It’s a monumental undertaking, though.
Personally, I wrap the CLI with my own APIs for just the handful of operations I need (and I know some other users do, too) rather than use the HTTP API. That may even be the easiest safe-ish way to implement a non-root variant of the HTTP API. e.g. make it a separate process that isn’t running as root, but can pass messages to a local service that does and is able to call the CLI for the granted subset of operations.
Thanks, I will then create a wrapper around it or just create my own API that does not run as root for these specific limited commands I required, exposing an API that receives commands as root seems like a horrible idea from a security standpoint.
Normally, if someone is interested in an HTTP API is because they need to run something externally, but It’s not really useless if it requires the full root account, at that point you might just log into the server and use the CLI and execute the same locally.
The benefit of using the API was that the abstraction layer, sanitization, security, etc. was already taken care of. Being able to automate something externally without actually passing the authentication details or using a limited account that can only run those specific commands.
Here comes my interested findings.
If you create a Webmin user and then edit the webmin.acl, for example, and add the permission for that user for the proper module, example, virtualmin-server it can execute the API request.
Now here comes the strange part. This works both for privileged or safe user. Those are the 2 options in Webmin to create users. Except that safe user does require an existing Unix account to work, which makes no sense at least in our API situation.
Assuming you want to give the least privileges possible to the API user since the logins could be exposed, you would not allow it to log in with SSH or have any file permission or group access, which means the privileged Webmin user seems actually a better option here since the Unix account does not exist. But then you are now giving it privileged access on Webmin…ouch…
It seems the API can be run as another user with this method, just tested it. It just requires a webmin user and then the proper permission to the API you want to run, in my test virtual-server
The million-dollar question is which user to pick here and give the least possible privileges. That way, you can just use that username and password on the API calls without using root. A safe user and then disable SSH and all possible commands or just a privileged admin user with only the module permission required, that does not even have access to the operating system since no Unix user exists but at least in the naming and permission has way more access for Webmin which probably runs as root for most of it pages and modules.
OK, after testing I assume (not sure) that privileged Webmin user does not require a system account because it’s actually using root, which is what we are trying to avoid in this scenario. Hence, you can just create a webmin user without any account system.
If that is true, I guess the second approach would be better. Creating a very unprivileged account in the system, such as:
sudo useradd -r -M -s /sbin/nologin -g nobody api-user
We lock it just in case:
sudo passwd -l api-user
We now create a safe Webmin user, no settings are required to be checked, but it would be wise to restrict the login to the IP from which you are going to execute the API calls.
Now edit webmin.acl and add the new user with the virtual-server module permission. This runs as root but we assume Webmin is now doing the privilege escalation as the wrapper similar to how it would do if logged in.
That allows you to have a login for the API that, if exposed, cannot log into the system and is not root and is very limited in permissions.
Suggestions are welcome