如何通过OpenLDAP服务器配置SUDO

现在,本指南将向您展示如何通过OpenLDAP服务器配置SUDO。除了能够在本地系统上提供sudo特权外, sudo也可以通过LDAP配置。通过OpenLDAP提供SUDO服务无需再通过本地系统上的sudoers文件向用户授予sudo特权。

如何通过OpenLDAP服务器配置SUDO

要通过OpenLDAP服务器配置SUDO,您需要加载并启用OpenLDAP sudo模式。之前的指南介绍了如何在CentOS 8上安装和设置OpenLDAP。

在CentOS 8上安装和设置OpenLDAP

假设您已按照上述指南中的说明启用了sudo的OpenLDAP支持,请继续进行配置。

创建OpenLDAP SUDOers组织单位(ou)

在组织的目录结构中创建SUDOers或ou。

vim sudoersou.ldif

相应地替换域组件和描述。

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

使用上面的SUDOers组织单位条目更新OpenLDAP数据库。

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

在SUDOers OpenLDAP OU中创建默认条目

sudoers.ldap 手册页,sudo首先 cn=defaults SUDOers OU条目。如果找到,则有多个值 sudoOption 属性的解析方式与全局变量解析方式相同 Defaults 线入 /etc/sudoers

将sudoers文件转换为LDAP LDIF

那么,如何为具有所有必需sudo属性的SUDOers创建默认条目?为了简化操作,请转换您的本地sudoers文件, /etc/sudoers,更改为OpenLDAP格式并根据需要进行更改。 OpenLDAP通常带有一个perl脚本, sudoers2ldif用于将sudoers文件转换为OpenLDAP LDIF文件。

在OpenLDAP ldif perl脚本中找到sudoers。

find / -iname sudoers2ldif

好吧,如果找不到它,可以将其拉出 Github仓库。单击检查原始版本,然后下载,如下所示:

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

该脚本如下所示:

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;
}

创建一个bash环境变量,该变量定义上面创建的SUDOers组织单位条目。

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

然后转换 /etc/sudoers 将文件放入LDAP ldif文件中,并创建所需的SUDOer或默认条目。

perl sudoers2ldif /etc/sudoers > sudoers_defaults.ldif

内容是什么 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

如您所见,LDAP ldif格式的sudoers文件包含一个多值SUDOers OU sudoOption 定义了属性,root用户cn,车轮组。

上面使用的sudo属性:

  • sudoOption:与默认选项相同 /etc/sudoers 文件
  • sudoUser:用户名,用户ID(“#)),Unix组名或ID(“%“或”%#)),用户网络组(“+))或非Unix组名称或ID(“%:“或”%:#每个)
  • sudo主机:主机名,IP地址,IP网络或主机网络组(“+´)或 ALL 与任何主机匹配的值。
  • sudoRunAsUser:用户名或UID(“#))命令是Unix组(“%))或用户网络组(“+’)包含可以执行命令的用户列表。 ALL 该值匹配所有用户。
  • sudoCommand:使用可选的命令行参数指定标准的Unix命令名称。使用方法 ALL 匹配任何命令。

因此,您可以在使用SUDOers配置更新OpenLDAP数据库之前,修改上述SUDOers LDAP ldif文件。

例如,删除预定义的root用户和wheel组,然后添加用户以通过LDAP在远程客户端上分配SUDO特权。

也偏远 sudoOrder 属性。

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

在上面的代码中,在SUDOers ou下创建一个名为sudo的条目,并分配以下用户: 简·多伊 具有SUDO权限,可以在任何系统上以任何用户身份执行所有命令。这类似于以下行: /etc/sudoers 文件

janedoe ALL=(ALL:ALL) ALL

更新OpenLDAP数据库

接下来,将SUDOers配置加载到OpenLDAP数据库中。

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

如果您需要将其他用户添加到上述角色中;

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

要创建另一个sudo角色,例如允许用户执行某些命令,请参阅:角色名称可以是任何描述性的名称。

例如,要允许名为mibeyam的用户仅使用sudo执行useradd命令,请创建ldif文件并按如下所示更新OpenLDAP数据库:

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

要列出SUDOers OU,只需执行以下操作:

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

配置OpenLDAP客户端

要使用OpenLDAP测试和验证SUDO设置,请设置客户端以通过OpenLDAP进行身份验证。在本演示中,我们在Ubuntu 18.04系统上使用SSSD提供LDAP身份验证。

因此,首先登录到Ubuntu 18.04系统并按照以下步骤设置客户端身份验证:

apt update

安装SSSD和其他必需的软件包。

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

创建具有以下内容的SSSD配置文件:

vim /etc/sssd/sssd.conf

替换值 ldap_default_bind_dnldap_default_authtok 使用绑定DN及其密码。还要相应地替换基本DN,LDAP URI,SUDOers搜索基本和LDAP过滤器。

[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)

从LDAP服务器复制CA证书。

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

保存在上面指定的文件中, /etc/ssl/certs/ldapcert.crt。您可以根据需要使用其他文件。

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

开门 /etc/ldap/ldap.conf 设置从OpenLDAP服务器复制的CA证书文件的位置。

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

定义LDAP SUDOers搜索库。

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

设置读写权限 /etc/sssd/ 所有者(根)。

chmod 600 -R /etc/sssd

重新启动SSSD服务

systemctl restart sssd

启用自动创建用户主目录

配置,设置 可插拔身份验证模块(PAM) 首次登录时自动创建用户的主目录。

这是 /etc/pam.d/common-session 配置文件,例如:

vim /etc/pam.d/common-session

在该行之后立即添加以下行, 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

保存设置并退出。

还有 /etc/nsswitch.conf 有这条线。

sudoers:        files sss

在Ubuntu 18.04上测试OpenLDAP身份验证

要验证您可以使用SSSD通过LDAP用户登录系统,请使用OpenLDAP用户执行本地ssh身份验证。查看上述OpenLDAP设置指南,了解如何添加用户。

ssh [email protected]

登录时,请注意以下行: 创建目录“ / 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)

检查SUDO特权

现在,您可以使用sudo运行各种命令,以验证您实际上是否具有OpenLDAP提供的sudo特权。

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

然后以没有sudo特权的用户身份再次登录。

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]:~$

万岁!您已成功配置OpenLDAP服务器以提供SUDO。告别需要为本地系统上的用户分配sudo特权。总结了有关如何通过OpenLDAP服务器配置SUDO的指南。

请参阅:

sudoers ldap手册页

Sidebar