One of the most interesting new features of the upcoming sudo version 1.9 is Python support. While version 1.8 introduced plugin support, Python support means that you can extend sudo using the same APIs but write plugins in Python instead of C. Version 1.9 is still under development but you are encouraged to test it and provide feedback about your experiences. From this blog, you can learn how to install ready to use beta quality packages from the sudo website, how to compile it yourself (on CentOS) and how to test Python support using a very simple example script.
Before you begin
Note: while I did not run into any serious problem during the testing of different git snapshot builds, I do not recommend running beta quality software in a production environment. As with any experimenting with sudo: make sure that you can log in as root before you start working. The example Python code replaces the policy engine of sudo with a very simplistic one so you will definitely need the root password even if sudo otherwise works perfectly.
Installing a binary package
Ready to use binary packages are available for many platforms on the sudo website. Go to https://www.sudo.ws/dist/beta/packages/index.html, download and install the package for your platform.
Compile it from source
You can also easily compile sudo 1.9 for yourself. I tested it on CentOS 7 but other platforms should work as well. To compile sudo, first you need to install development tools and dependencies for the application. Your mileage may vary depending on your platform. This is what I had to install on CentOS 7 in order to compile sudo:
yum install git yum groupinstall "Development Tools" yum install python3-devel yum install pam-devel yum install openldap-devel yum install openssl-devel
You are now ready to download sudo sources from git:
git clone https://github.com/sudo-project/sudo.git
Now change to the freshly checked-out directory, configure sources with Python support enabled, compile sudo and create an installable RPM package from it:
cd sudo ./mkpkg --enable-python
The package should be ready in a few minutes. The advantage of using a package is that you can easily delete it and return to the sudo version included on your platform. You can now install the freshly built sudo package with a command such as:
yum install sudo-1.9.0-1.el7.x86_64.rpm
Before going on to test Python support, do some basic sudo testing. The default configuration allows you to use sudo to root and to members of the wheel group. Test that you can run commands as a user, experiment with settings in
Python sample code
You can find a very simple example Python script below, which implements a sudo policy. It only accepts “id” as a valid command and executes it as root. Any other command is rejected with an error message.
import sudo class SudoPolicyPlugin(sudo.Plugin): def check_policy(self, argv, env_add): cmd = argv # the first argument is the command name if cmd != "id": # Example for a simple reject: sudo.log_error("You are not allowed to run this command!") return sudo.RC_REJECT command_info_out = ( # setup command to execute "command=/usr/bin/id", # Absolute path of command "runas_uid=0", # The user id "runas_gid=0") # The group id return(sudo.RC_ACCEPT, command_info_out, argv, env_add)
As you can see, the script starts by importing the sudo module. It does not exist as a separate file on your file system, only within the sudo Python plugin itself.
Next, we define a class. Name it however you like, the only important thing is that it is inherited from the sudo.Plugin class. You will use the name of the class in
sudo.conf, where you configure sudo plugins.
In the policy plugin there is a single mandatory method: check_policy. It receives two arguments from sudo; “argv” describes the command the user wants to run and “env_add” contains the environment variables defined by the user. The first argument of “argv” contains the command to be executed. If it is different from “id”, an error message is printed on screen and the command is rejected. Otherwise we fill out the command_info_out variable with some hard-coded information about the command to be executed. Finally, we return that the command is accepted and the information necessary to execute it.
Testing the Python plugin
As I mentioned earlier in the introduction: this Python code replaces the sudo policy engine. Instead of using
/etc/sudoers, the sudo policy will be based on this Python code. Make sure that you can log in as root before enabling the above code!
There are many more Python examples in the sudo repository on GitHub: https://github.com/sudo-project/sudo/tree/master/plugins/python. This one is based on
example_policy_plugin.py, but has been simplified to a bare minimum.
Once you understand the consequences, you are ready for testing. Open
/etc/sudo.conf in your favorite text editor and add the following line to it:
Plugin python_policy python_plugin.so ModulePath=/root/policy.py ClassName=SudoPolicyPlugin
If an existing policy plugin is present, such as
sudoers_policy, it must be commented out.
As you can see, I stored the sample code in the
/root/policy.py file. If you saved it to a different location, change the parameter of “ModulePath” accordingly.
/etc/sudo.conf is saved, you are ready for testing. Login as a regular user and execute “ls” with sudo. Then run “id” with it. The result should look similar to the following:
[czanik@centos7 ~]$ sudo ls You are not allowed to run this command! [czanik@centos7 ~]$ sudo id uid=0(root) gid=0(root) groups=0(root)
You should now login as root and remove (or comment out) the line loading the Python-based policy plugin. Once you save the file,
/etc/sudoers will be used again.
What is next?
You can learn more about the Python plugin at https://www.sudo.ws/man/1.9.0/sudo_plugin_python.man.html.
If you would like to be notified about new posts and sudo news, sign up for the sudo blog announcement mailing list.