How to configure SUDO via OpenLDAP server

Well, in this guide, we will demonstrate how to configure SUDO through OpenLDAP Server. In addition to being able to provide sudo permissions on the local system, sudo can also be configured via LDAP . Providing SUDO through OpenLDAP eliminates the need to provide users with sudo privileges through the local system sudoers file.

How to configure SUDO via OpenLDAP server

In order to configure SUDO through the OpenLDAP server, you need to load and enable OpenLDAP sudo mode. We have addressed this issue in a previous guide on how to install and set up OpenLDAP on CentOS 8.

Install and set up OpenLDAP on CentOS 8

Assuming you have enabled OpenLDAP support for sudo as described in the guide above, proceed with the configuration.

Create OpenLDAP SUDOers organizational unit (ou)

Create SUDOers ou on your organization’s directory structure.

                      vim sudoersou.ldif
                    

Replace your domain components and instructions accordingly.

                      dn: ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectclass: organizationalunit
ou: SUDOers
description: Kifarunix-demo LDAP SUDO Entry
                    

Update the OpenLDAP database with the above SUDOers organizational unit entry.

                      ldapadd -Y EXTERNAL -H ldapi:/// -f sudoersou.ldif
                    

Create default entry on SUDOers OpenLDAP OU

According to sudoers.ldap Man page, sudo looks first cn=defaults Entry in SUDOers OU. If found, multivalued sudoOption Attributes are resolved in the same way as global attributes Defaults Line up /etc/sudoers .

Convert sudoers file to LDAP LDIF

So, how do I create a SUDOers default entry with all the necessary sudo attributes? Okay, for your convenience, please convert your local sudoers file, /etc/sudoers , Convert to OpenLDAP format, and modify it to your satisfaction. OpenLDAP usually comes with a perl script, sudoers2ldif For converting sudoers files to OpenLDAP LDIF files.

Find sudoers in the OpenLDAP ldif perl script.

                      find / -iname sudoers2ldif
                    

Well, if you can’t find it, you can pull it out of it Github repository . Click Check original version and download as follows;

                      wget https://raw.githubusercontent.com/lbt/sudo/master/plugins/sudoers/sudoers2ldif
                    

The script looks like;

                      less sudoers2ldif
                    
                      
                        #!/usr/bin/env perl
#
# Copyright (c) 2007, 2010-2011, 2013 Todd C. Miller <[email protected]>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

use strict;

#
# Converts a sudoers file to LDIF format in prepration for loading into
# the LDAP server.
#

# BUGS:
#   Does not yet handle multiple lines with : in them
#   Does not yet remove quotation marks from options
#   Does not yet escape + at the beginning of a dn
#   Does not yet handle line wraps correctly
#   Does not yet handle multiple roles with same name (needs tiebreaker)
#
# CAVEATS:
#   Sudoers entries can have multiple RunAs entries that override former ones,
#	with LDAP sudoRunAs{Group,User} applies to all commands in a sudoRole

my %RA;
my %UA;
my %HA;
my %CA;
my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefinedn";
my @options=();

my $did_defaults=0;
my $order = 0;

# parse sudoers one line at a time
while (<>){

  # remove comment
  s/#.*//;

  # line continuation
  $_.=<> while s/\s*$//s;

  # cleanup newline
  chomp;

  # ignore blank lines
  next if /^s*$/;

  if (/^Defaultss+/i) {
    my $opt=$';
    $opt=~s/s+$//; # remove trailing whitespace
    push @options,$opt;
  } elsif (/^(S+)s+([^=]+)=s*(.*)/) {

    # Aliases or Definitions
    my ($p1,$p2,$p3)=($1,$2,$3);
    $p2=~s/s+$//; # remove trailing whitespace
    $p3=~s/s+$//; # remove trailing whitespace

    if ($p1 eq "User_Alias") {
      $UA{$p2}=$p3;
    } elsif ($p1 eq "Runas_Alias") {
      $RA{$p2}=$p3;
    } elsif ($p1 eq "Host_Alias") {
      $HA{$p2}=$p3;
    } elsif ($p1 eq "Cmnd_Alias") {
      $CA{$p2}=$p3;
    } else {
      if (!$did_defaults++){
        # do this once
        print "dn: cn=defaults,$basen";
        print "objectClass: topn";
        print "objectClass: sudoRolen";
        print "cn: defaultsn";
        print "description: Default sudoOption's go heren";
        print "sudoOption: $_n" foreach @options;
        printf "sudoOrder: %dn", ++$order;
        print "n";
      }
      # Definition
      my @users=split /s*,s*/,$p1;
      my @hosts=split /s*,s*/,$p2;
      my @cmds= split /s*,s*/,$p3;
      @options=();
      print "dn: cn=$users[0],$basen";
      print "objectClass: topn";
      print "objectClass: sudoRolen";
      print "cn: $users[0]n";
      # will clobber options
      print "sudoUser: $_n"   foreach expand(%UA,@users);
      print "sudoHost: $_n"   foreach expand(%HA,@hosts);
      foreach (@cmds) {
	if (s/^(([^)]+))s*//) {
	  my @runas = split(/:s*/, $1);
	  if (defined($runas[0])) {
	    print "sudoRunAsUser: $_n" foreach expand(%RA, split(/,s*/, $runas[0]));
	  }
	  if (defined($runas[1])) {
	    print "sudoRunAsGroup: $_n" foreach expand(%RA, split(/,s*/, $runas[1]));
	  }
	}
      }
      print "sudoCommand: $_n" foreach expand(%CA,@cmds);
      print "sudoOption: $_n" foreach @options;
      printf "sudoOrder: %dn", ++$order;
      print "n";
    }

  } else {
    print "parse error: $_n";
  }

}

#
# recursively expand hash elements
sub expand{
  my $ref=shift;
  my @a=();

  # preen the line a little
  foreach (@_){
    # if NOPASSWD: directive found, mark entire entry as not requiring
    s/NOPASSWD:s*// && push @options,"!authenticate";
    s/PASSWD:s*// && push @options,"authenticate";
    s/NOEXEC:s*// && push @options,"noexec";
    s/EXEC:s*// && push @options,"!noexec";
    s/SETENV:s*// && push @options,"setenv";
    s/NOSETENV:s*// && push @options,"!setenv";
    s/LOG_INPUT:s*// && push @options,"log_input";
    s/NOLOG_INPUT:s*// && push @options,"!log_input";
    s/LOG_OUTPUT:s*// && push @options,"log_output";
    s/NOLOG_OUTPUT:s*// && push @options,"!log_output";
    s/[[:upper:]]+://; # silently remove other tags
    s/s+$//; # right trim
  }

  # do the expanding
  push @a,$ref->{$_} ? expand($ref,split /s*,s*/,$ref->{$_}):$_ foreach @_;
  @a;
}


                      
                    

Create a bash environment variable that defines the SUDOers organizational unit entry you created above.

                      export SUDOERS_BASE="ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com"
                    
                      echo $SUDOERS_BASE
                    

Next, will /etc/sudoers The file is converted to an LDAP ldif file to create the required SUDOers or default entries.

                      perl sudoers2ldif /etc/sudoers > sudoers_defaults.ldif
                    

So what is the content sudoers_defaults.ldif ?

                      cat sudoers_defaults.ldif
                    
                      
                        dn: cn=defaults,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: top
objectClass: sudoRole
cn: defaults
description: Default sudoOption's go here
sudoOption: !visiblepw
sudoOption: always_set_home
sudoOption: match_group_by_gid
sudoOption: always_query_group_plugin
sudoOption: env_reset
sudoOption: env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
sudoOption: env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
sudoOption: env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
sudoOption: env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
sudoOption: env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
sudoOption: secure_path = /sbin:/bin:/usr/sbin:/usr/bin
sudoOrder: 1

dn: cn=root,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: top
objectClass: sudoRole
cn: root
sudoUser: root
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: ALL
sudoOrder: 2

dn: cn=%wheel,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: top
objectClass: sudoRole
cn: %wheel
sudoUser: %wheel
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: ALL
sudoOrder: 3
                      
                    

As you can see, the sudoers file in LDAP ldif format contains SUDOers OU, multi-valued sudoOption Properties, root user cn and defined wheel group.

Sudo attributes used above:

  • sudoOption : Similar to the default option in /etc/sudoers file.
  • sudoUser : Define username and user ID (prefixed with ‘ # “, Unix group name or ID (prefixed with” % ‘Or’ %# “, User network group (prefixed with” + “) Or non-Unix group name or ID (prefixed with” %: ‘Or’ %:# ‘Respectively)
  • sudo host : Hostname, IP address, IP network or host network group (prefixed with “ + ‘) Or ALL Value to match any host.
  • sudoRunAsUser : Username or uid (prefixed with ‘ # “), The command can be either a Unix group or a Unix group (with‘ % “Or user network group (prefixed with” + ’), Which contains a list of users who can run commands. ALL The value matches any user.
  • sudoCommand : Specify a standard Unix command name with optional command line arguments. Adopt ALL Matches any command.

So before updating the OpenLDAP database with the SUDOers configuration, you can modify the SUDOers LDAP ldif file above.

For example, delete the defined root user and wheel group, and then add a user on the remote client who wants to assign SUDO permissions through LDAP.

In addition, remote sudoOrder Attributes.

                      vi modified-sudoer2ldif.ldif
                    
                      
                        dn: cn=defaults,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: top
objectClass: sudoRole
cn: defaults
description: Kifarunix-demo SUDO via LDAP
sudoOption: !visiblepw
sudoOption: always_set_home
sudoOption: match_group_by_gid
sudoOption: always_query_group_plugin
sudoOption: env_reset
sudoOption: env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
sudoOption: env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
sudoOption: env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
sudoOption: env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
sudoOption: env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
sudoOption: env_keep+=SSH_AUTH_SOCK
sudoOption: secure_path = /sbin:/bin:/usr/sbin:/usr/bin

dn: cn=sudo,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: top
objectClass: sudoRole
cn: sudo
sudoUser: janedoe
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: ALL
                      
                    

In the above code, we created an entry named sudo under SUDOers ou and assigned an entry named Jenny SUDO has the right to run all commands as any user on any system, similar to the following: /etc/sudoers file.

                      janedoe ALL=(ALL:ALL) ALL
                    

Update OpenLDAP database

Next, load the SUDOers configuration into the OpenLDAP database.

                      ldapadd -Y EXTERNAL -H ldapi:/// -f modified-sudoer2ldif.ldif
                    

If you need to add other users to the above roles:

                      vim add-to-sudo-role.ldif
                    
                      dn: cn=sudo,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
changetype: modify
add: sudoUser
sudoUser: johndoe
                    
                      ldapmodify -Y EXTERNAL -H ldapi:/// -f add-to-sudo-role.ldif
                    

To create other sudo roles, such as allowing users to run specific commands, see below. The role name can be any descriptive name.

For example, to allow a user named mibeyam to run the useradd command using only sudo, create an ldif file as shown below and update the OpenLDAP database.

                      vim sudo-specific-cmd.ldif
                    
                      
                        dn: cn=cmdrole,ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
objectClass: top
objectClass: sudoRole
cn: cmdrole
sudoUser: mibeyam
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: /usr/sbin/useradd
                      
                    
                      ldapadd -Y EXTERNAL -H ldapi:/// -f sudo-specific-cmd.ldif
                    

To list SUDOers OU, just run;

                      export SUDOERS_BASE=ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
                    
                      ldapsearch -b "$SUDOERS_BASE" -D cn=admin,dc=ldapmaster,dc=kifarunix-demo,dc=com -W -x sudoUser
                    

Configure OpenLDAP client

To test and confirm the SUDO provided by OpenLDAP, set the client to authenticate through OpenLDAP. In this demo, we provide LDAP authentication using SSSD on an Ubuntu 18.04 system.

So, first login to Ubuntu 18.04 system and follow the steps to set up client authentication.

                      apt update
                    

Install SSSD and other required packages.

                      apt install sssd libpam-sss libnss-sss vim sssd-tools
                    

Create an SSSD configuration file with the following contents.

                      vim /etc/sssd/sssd.conf
                    

Replaced value ldap_default_bind_dn with ldap_default_authtok Bind your DN and its password. In addition, replace the base DN, LDAP URI, SUDOers search base and ldap filters accordingly.

                      
                        [sssd]
services = nss, pam, sudo
config_file_version = 2
domains = default

[sudo]

[nss]

[pam]
offline_credentials_expiration = 60

[domain/default]
ldap_id_use_start_tls = True
cache_credentials = True
ldap_search_base = dc=ldapmaster,dc=kifarunix-demo,dc=com
id_provider = ldap
auth_provider = ldap
chpass_provider = ldap
access_provider = ldap
sudo_provider = ldap
ldap_uri = ldaps://ldapmaster.kifarunix-demo.com:636
ldap_default_bind_dn = cn=readonly,ou=system,dc=ldapmaster,dc=kifarunix-demo,dc=com
ldap_default_authtok = [email protected]
ldap_tls_reqcert = demand
ldap_tls_cacert = /etc/ssl/certs/cacert.crt
ldap_tls_cacertdir = /etc/ssl/certs
ldap_search_timeout = 50
ldap_network_timeout = 60
ldap_sudo_search_base = ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com
ldap_access_order = filter
ldap_access_filter = (objectClass=posixAccount)
                      
                    

Copy the CA certificate from the LDAP server.

                      openssl s_client -connect ldapmaster.kifarunix-demo.com:636 -showcerts < /dev/null | openssl x509 -text
                    

Store it in the specified file above, /etc/ssl/certs/ldapcert.crt . You can use other files as needed.

                      vim /etc/ssl/certs/cacert.crt
                    
                      
                        -----BEGIN CERTIFICATE-----
MIID0TCCArmgAwIBAgIUQnXoL0eVw1STAXFBjKwNobOMtJ8wDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCS0UxEDAOBgNVBAgMB05haXJvYmkxEDAOBgNVBAcMB05h
....
...
FG4/H6F0CAD/ksl4w8aEP0JrdZsDxwmGv8GoM6fVI/3qcv2pD/+Fjif0GRcb7V6g
NsyGrEWBFOD+IrMDIm7KvTBEBJbc
-----END CERTIFICATE-----
                      
                    

turn on /etc/ldap/ldap.conf And set the location of the CA certificate file copied from the OpenLDAP server.

                      vim /etc/ldap/ldap.conf
                    
                      ...
# TLS certificates (needed for GnuTLS)
#TLS_CACERT     /etc/ssl/certs/ca-certificates.crt

                      
                        TLS_CACERT       /etc/ssl/certs/cacert.crt
                      
                    

Define the LDAP SUDOers search library.

                      echo "sudoers_base ou=SUDOers,dc=ldapmaster,dc=kifarunix-demo,dc=com" >> /etc/ldap/ldap.conf
                    

Set read / write access to /etc/sssd/ As owner (root).

                      chmod 600 -R /etc/sssd
                    

Restart the SSSD service

                      systemctl restart sssd
                    

Enable automatic home user creation

Configuration Pluggable Authentication Module (PAM) The user's home directory is created automatically on first login.

This can be edited by /etc/pam.d/common-session The configuration file is as follows;

                      vim /etc/pam.d/common-session
                    

Add the following line after the line, session optional pam_sss.so .

                      session required        pam_mkhomedir.so skel=/etc/skel/ umask=0022
                    
                      ...
# since the modules above will each just jump around
session required pam_permit.so
# and here are more per-package modules (the "Additional" block)
session required pam_unix.so 
session optional pam_sss.so 

                      
                        session required        pam_mkhomedir.so skel=/etc/skel/ umask=0022
                      
                      
session optional pam_systemd.so 
# end of pam-auth-update config
                    

Save and exit the configuration.

Also, make sure /etc/nsswitch.conf Have this line

                      sudoers:        files sss
                    

Testing OpenLDAP authentication on Ubuntu 18.04

To confirm that you can now log in to the system with an LDAP user using SSSD, simply run local ssh authentication with your OpenLDAP user. In the OpenLDAP setup guide provided above, check how to add users.

                      ssh [email protected]
                    

When logging in, note the following lines: Create directory "/ home / janedoe" .

                      [email protected]'s password: 

                      
                        Creating directory '/home/janedoe'
                      
                      .
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Last login: Sun Dec  8 11:52:56 2019 from ::1
[email protected]:~$
                    
                      pwd
                    
                      /home/janedoe
                    
                      id
                    
                      uid=10010(janedoe) gid=10010(janedoe) groups=10010(janedoe)
                    

Verify SUDO privileges

Now you can try running various commands with sudo to confirm that you actually have sudo permissions provided by OpenLDAP.

                      sudo su -
                    
                      [email protected]:~$ sudo su -
 [sudo] password for janedoe: 
 [email protected]:~#
                    

Now log in again as a user who has not been granted sudo permissions.

                      ssh [email protected]
                    
                      [email protected]:~$ sudo su -
[sudo] password for johndoe: 
johndoe is not allowed to run sudo on ubuntu18.  This incident will be reported.
[email protected]:~$
                    

cheer! !! You have successfully configured the OpenLDAP server to provide SUDO. Farewell to having to assign sudo permissions to users on the local system. This brings us to the end of our guide on how to configure SUDO with an OpenLDAP server.

reference:

sudoers ldap man page

.

Related Posts