GitHub Blog Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

What's new in sudo 1.9: Python

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, 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

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

Basic testing

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 /etc/sudoers.

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[0]        # 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: This one is based on, 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 ModulePath=/root/ 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/ file. If you saved it to a different location, change the parameter of “ModulePath” accordingly. After /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

If you would like to be notified about new posts and sudo news, sign up for the sudo blog announcement mailing list.