For anyone using LDAP authentication on Linux hosts, controlling who can be SUDO on VMs via LDAP makes it much easier, control becomes centralised and not host to host, imagine doing this with hundreds or thousands of hosts?

In this post I will show how to create the SUDO schema in OpenLDAP and the specific configuration on clients (VMs). For this, the premise is that the VMs are already using LDAP authentication (Explained in another post) and SSSD.

sudo-ldap

First step, install sudo-ldap:

export SUDO_FORCE_REMOVE=yes
apt install -y sudo-ldap 

Check if the SUDO schema is already available in the OpenLDAP installation.

$ find /usr/share/doc/ -iname schema.openldap

/usr/share/doc/sudo-ldap/schema.OpenLDAP

Then copy the file to the OpenLDAP schema folder.

cp /usr/share/doc/sudo-ldap/schema.OpenLDAP  /etc/ldap/schema/sudo.schema

Now to create the structure of the SUDO LDIF file, we will have to create a structure of temporary folders, files can be deleted, but it will be necessary to generate and change some files.

mkdir -p /work/ldap-sudo/config
cd /work/ldap-sudo

echo "include /etc/ldap/schema/sudo.schema" > ldapsudo.conf
cd /work/ldap-sudo/config

Run slaptest pointing to the file created in the previous step. The file is nothing more than a simple conf that includes the SUDO schema.

slaptest -f ../ldapsudo.conf -F .

You will notice that slaptest will create a folder and file structure, as shown below:

.
├── config
│   ├── cn=config
│   │   ├── cn=schema
│   │   │   └── cn={0}sudo.ldif
│   │   ├── cn=schema.ldif
│   │   ├── olcDatabase={0}config.ldif
│   │   └── olcDatabase={-1}frontend.ldif
│   └── cn=config.ldif
└── ldapsudo.conf

Let’s work with the file created for the sudo schema:

vi cn\=config/cn\=schema/cn\=\{0\}sudo.ldif

Remove the first lines (2), which are commented (not necessary).

Change the lines below:

From:
dn: cn={0}sudo
objectClass: olcSchemaConfig
cn: {0}sudo


To:
dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo

Also remove the last lines, from structuralObjectClass downwards:

structuralObjectClass: olcSchemaConfig
entryUUID: 431580bc-67ab-103e-932b-a1c41a5943c1
creatorsName: cn=config
createTimestamp: 20240224215609Z
entryCSN: 20240224215609.360408Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20240224215609Z

In the end, the file must have +/- this structure.

dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo
olcAttributeTypes: {0}( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s)
 who may  run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMa
 tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {1}( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s)
 who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMat
 ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: {2}( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Comma
 nd(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1
 466.115.121.1.26 )
olcAttributeTypes: {3}( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s)
  impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1
 .4.1.1466.115.121.1.26 )
olcAttributeTypes: {4}( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Option
 s(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115
 .121.1.26 )
olcAttributeTypes: {5}( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'Use
 r(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466
 .115.121.1.26 )
olcAttributeTypes: {6}( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Gr
 oup(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14
 66.115.121.1.26 )
olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Sta
 rt of time interval for which the entry is valid' EQUALITY generalizedTimeMat
 ch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
  )
olcAttributeTypes: {8}( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End
 of time interval for which the entry is valid' EQUALITY generalizedTimeMatch
 ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
olcAttributeTypes: {9}( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an int
 eger to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrd
 eringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
olcObjectClasses: {0}( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer En
 tries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand $ s
 udoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotB
 efore $ sudoNotAfter $ description ) )

Then, import the schema:

$ ldapadd -Q -Y EXTERNAL -H ldapi:/// -f 'cn=config/cn=schema/cn={0}sudo.ldif'

adding new entry "cn=sudo,cn=schema,cn=config"

After importing the schema, it is necessary to enable sudoUser and sudoHost.

cat << EOL > /work/ldap-sudo/ldap-sudo.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: sudoUser,sudoHost pres,eq
EOL

ldapadd -Y EXTERNAL -H ldapi:/// -f /work/ldap-sudo/ldap-sudo.ldif

Check if they are all being indexed.

$ slapcat -n 0 | grep olcDbIndex

olcDbIndex: objectClass eq
olcDbIndex: cn,uid eq
olcDbIndex: uidNumber,gidNumber eq
olcDbIndex: member,memberUid eq
olcDbIndex: sudoUser,sudoHost pres,eq

Sudoers OU

To control users who may be Sudores, I will just use the previously created group “ou=AdminGroups,dc=ldap,dc=devops-db,dc=info“, in a more complex environment, subgroups should help.

cat << EOL > /work/ldap-sudo/sudoers_defaults.ldif
dn: cn=defaults,ou=AdminGroups,dc=ldap,dc=devops-db,dc=info
objectClass: top
objectClass: sudoRole
cn: defaults
sudoOption: !visiblepw
sudoOption: !authenticate
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=AdminGroups,dc=ldap,dc=devops-db,dc=info
objectClass: top
objectClass: sudoRole
cn: sudo
sudoUser: fbranco
sudoHost: ALL
sudoRunAsUser: ALL
sudoCommand: ALL
EOL

The options above are automatically applied to the Host for the authenticated user, there is a simple table with the options for this sudoOption.

/etc/sudoersLDAP Sudoers
NOPASSWD!authenticate
PASSWDauthenticate
NOEXECnoexec
EXEC!noexec
SETENVsetenv
NOSETENV!setenv
LOG_INPUTlog_input
NOLOG_INPUT!log_input
LOG_OUTPUTlog_output
NOLOG_OUTPUT!log_output

Import the defaults:

$ ldapadd -v -x -H ldaps://ldap.devops-db.info:636 -f /work/ldap-sudo/sudoers_defaults.ldif  -D "cn=admin,dc=ldap,dc=devops-db,dc=info" -w "JbBmKx#lK@ZX4*amqd5l" 

SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=defaults,ou=AdminGroups,dc=ldap,dc=devops-db,dc=info"

adding new entry "cn=sudo,ou=AdminGroups,dc=ldap,dc=devops-db,dc=info"

To add other users in SUDO, use the example below.

cat > add-otheruser.ldif << 'EOL'
dn: cn=sudo,ou=AdminGroups,dc=ldap,dc=devops-db,dc=info
changetype: modify
add: sudoUser
sudoUser: otheruser
EOL

ldapmodify -Y EXTERNAL -H ldapi:/// -f add-otheruser.ldif

At this point, the Schema has been created, enabled and the permissions to the group have been made.

Configuration on the Client

As mentioned above, this part of the configuration on clients/VMs/Hosts is only to be validated and applied to Sudos according to LDAP, all LDAP configuration on VMs must already be ready and functional with SSSD.

Install the SSD lib to handle the Sudo:

apt-get install -y libsss-sudo

Add the following line to the SSSD configuration file, it is the sarch base for the sudoers group we created above.

vi /etc/sssd/sssd.conf

ldap_sudo_search_base = ou=AdminGroups,dc=ldap,dc=devops-db,dc=info

In the same sense, add the search base in the ldap configuration file.

vi /etc/ldap/ldap.conf

sudoers_base ou=AdminGroups,dc=ldap,dc=devops-db,dc=info

Reconfigure and restart SSSD.

chmod 600 -R /etc/sssd
systemctl restart sssd 

systemctl status sssd

Test access and permissions.

vagrant@srv-hostldap-01:~$ su fbranco
Password:
fbranco@srv-hostldap-01:/home/vagrant$ sudo -s
root@srv-hostldap-01:/home/vagrant#

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.