在 Cumulus Linux 上使用 Server 2008 Active Directory 的 LDAP

本文提供了一个关于如何在 Cumulus Linux 上使用 Active Directory 设置 LDAP 身份验证和授权的示例。它适用于任何基于 Debian Wheezy 的服务器或交换机。

本文中描述的方法仅适用于 Windows Server 2008。此方法在 Windows Server 2012 上效果不佳。

先决条件

  • Windows 2008 Active Directory
  • Cumulus Linux 2.x

Active Directory 设置

  • Base DN: CN=Cumulus Admin, DC=RTP, DC=Example, DC=test
  • Base OU: OU=Support, DC=RTP, DC=Example, DC=Test
  • 用户和组: 此示例有三个用户可以访问 Cumulus Linux 交换机。其中两个在高级网络工程师组中,一个在初级工程师组中。最后一个用户Mark Smith无法访问交换机,因为他不是cumuluslnxadm组的成员。
group layout of users

用户的 AD 组布局

layout of users and groups in AD schema

AD 架构中用户和组的布局

目标

  • 配置 LDAP 身份验证,无需更改默认 AD 架构。
  • 支持嵌套组。以下应有效
    nested group diagram
  • 用户目录在授权用户首次登录交换机时自动创建。
  • 高级网络管理员可以通过 sudo 运行交换机上的任何命令。
  • 初级网络管理员可以
    • 登录并访问任何非特权命令。
    • 运行 sudo lldpctl 而无需提示输入密码。lldpctl 是一个重要的网络故障排除工具,但需要 root 访问权限。
    • 使用所有 ip 命令 (iproute2 命令)。
    • 不通过 vtysh 或非模态 CLI (如 cl-ospf) 访问 FRR

配置 Cumulus Linux

  1. 更新 PAM 以支持自动创建目录 (可选)。

    此信息来自 Debian wiki。另一种方法是在 AD 中为用户设置 homeDirectory 属性为 /home/cumulus,并且所有用户都映射到预定义的用户帐户。

    创建以下文件 /usr/share/pam-configs/mkhomedir

    Name: Create home directory during login
    Default: yes
    Priority: 900
    Session-Type: Additional
    Session:
            required        pam_mkhomedir.so umask=0022 skel=/etc/skel
    
  2. 将 Debian backports 添加到 apt 源列表 (可选)。

    您需要 libnss-ldapd 版本 0.9 及更高版本才能获得嵌套组支持。对于 Wheezy,以及 Cumulus Linux 2.x,请将 Debian Wheezy backports 添加到 apt 源列表

  3. 使用适当的值 Seed debconf (推荐)。

    Seeding debconf 很有用,因为它在各种应用程序中添加了大多数重要的配置值,并防止应用程序在安装期间询问问题。

    虽然可以在非交互模式下执行 apt-get,但您需要在以后更改大多数必要的配置。

    对于 libnss-ldapd,有特定于 CPU 架构的问题需要回答。

    root# apt-get install debconf-utils
    
    root# debconf-set-selections <<'zzzEndOfFilezzz'
    
    # LDAP database user. Leave blank will be populated later!
    # This way of setting binddn and bindpw doesn't seem to work.
    # So have to manually do it. But interactive apt-get mode works.
    nslcd nslcd/ldap-binddn  string 
    
    # LDAP user password. Leave blank!
    nslcd nslcd/ldap-bindpw   password 
    
    # LDAP server search base:
    nslcd nslcd/ldap-base string  ou=support,dc=rtp,dc=example,dc=test
    
    # LDAP server URI. Using ldap over ssl.
    nslcd nslcd/ldap-uris string  ldaps://myadserver.rtp.example.test
    
    # New to 0.9. restart cron, exim and others libraries without asking
    nslcd libraries/restart-without-asking: boolean true
    
    # LDAP authentication to use:
    # Choices: none, simple, SASL
    # Using simple because its easy to configure. Security comes by using LDAP over SSL
    # keep /etc/nslcd.conf 'rw' to root for basic security of bindDN password
    nslcd nslcd/ldap-auth-type    select  simple
    
    # Don't set starttls to true
    nslcd nslcd/ldap-starttls     boolean false
    
    # Check server's SSL certificate:
    # Choices: never, allow, try, demand
    nslcd nslcd/ldap-reqcert      select  never
    
    # Choices: Ccreds credential caching - password saving, Unix authentication, LDAP Authentication , Create  home directory on first time login, Ccreds credential caching - password checking
    # This is where "mkhomedir" pam config is activated that allows automatic creation of home directory
    libpam-runtime        libpam-runtime/profiles multiselect     ccreds-save, unix, ldap, mkhomedir , ccreds-check
    
    # for internal use; can be preseeded
    man-db        man-db/auto-update      boolean true
    
    # Name services to configure:
    # Choices: aliases, ethers, group, hosts, netgroup, networks, passwd, protocols, rpc, services,  shadow
    libnss-ldapd  libnss-ldapd/nsswitch   multiselect     group, passwd, shadow
    libnss-ldapd  libnss-ldapd/clean_nsswitch     boolean false
    
    
    zzzEndOfFilezzz
    

    验证 debconf 配置

    root# debconf-show nslcd
    * nslcd/ldap-bindpw: (password omitted)
      nslcd/restart-failed:
      nslcd/ldap-sasl-authcid:
      nslcd/restart-services:
      nslcd/ldap-sasl-realm:
    * nslcd/ldap-sasl-mech:
    * nslcd/ldap-starttls: false
    * nslcd/ldap-base:  ou=support,dc=rtp,dc=example,dc=test
      nslcd/ldap-sasl-krb5-ccname: /var/run/nslcd/nslcd.tkt
    * nslcd/ldap-auth-type: none
      nslcd/disable-screensaver:
    * libraries/restart-without-asking: true
    * nslcd/ldap-reqcert: never
      nslcd/ldap-cacertfile: /etc/ssl/certs/ca-certificates.crt
      nslcd/ldap-sasl-authzid:
    * nslcd/ldap-uris:  ldaps://myadserver.rtp.example.test
    * libraries/restart-without-asking:: true
      nslcd/ldap-sasl-secprops:
      nslcd/xdm-needs-restart:
    * nslcd/ldap-binddn:
    
    root# debconf-show libpam-runtime
      libpam-runtime/override: false
      libpam-runtime/profiles: mkhomedir, unix, ldap, capability, auditd
      libpam-runtime/title:
      libpam-runtime/conflicts:
      libpam-runtime/no_profiles_chosen:
    
    root# debconf-show man-db
    * man-db/auto-update: true
      man-db/install-setuid: false
    
    root# debconf-show libnss-ldapd
    * libnss-ldapd/nsswitch:     group, passwd, shadow
    * libnss-ldapd/clean_nsswitch: false
    
  4. 安装 LDAP 应用程序。

    来自 Wheezy main repo 的 libnss-ldapd 不支持嵌套组。从 backports 加载 libnss-ldapd 应用程序以获取最新的可用版本。

    不要安装 libnss-ldap。这是错误的应用程序,这解释了原因

    root# apt-get -t wheezy-backports install libnss-ldapd ldap-utils
    
  5. 获取 Active Directory 域 SID。

    在 Windows 服务器上使用 dsquery 命令来获取域 SID。有关更多信息,请阅读 关于对象 SID 的这篇优秀参考资料

    dsquery output
  6. 配置 nslcd.conf

    使用以下内容更新 /etc/nslcd.conf

    • 指定 Bind DN 路径。
    • 指定 Bind DN 密码。
    • 配置 LDAP 搜索过滤器。过滤器声明只有 cumuluslnxadm 组中的用户才能登录。搜索过滤器执行嵌套组查找。
    • 配置 Unix 到 AD 的映射。
    • 配置嵌套组支持。

    这是带有注释的 /etc/nslcd.conf 配置

    # /etc/nslcd.conf
    # nslcd configuration file. See nslcd.conf(5)
    # for details.
    
    # The user and group nslcd should run as.
    uid nslcd
    gid nslcd
    
    # The location at which the LDAP server(s) should be reachable.
    # If planning to use secure LDAP, use fqdn that matches name 
    # in the server SSL cert sent during negotiation. Debugging 
    # nslcd will show this error if found
    uri ldap://myadserver.rtp.example.test
    
    # The search base that will be used for all queries.
    base ou=support,dc=rtp,dc=example,dc=test
    
    # The LDAP protocol version to use.
    #ldap_version 3
    
    # The DN to bind with for normal lookups.
    # defconf-set-selections doesn't seem to set this. so have to manually set this.
    binddn CN=cumulus admin,CN=Users,DC=rtp,DC=example,DC=test
    bindpw 1Q2w3e4r!
    
    # The DN used for password modifications by root.
    #rootpwmoddn cn=admin,dc=example,dc=com
    
    # SSL options
    #ssl off (default)
    # default tls setting of 'demand' requires CA public cert
    #  for AD server be defined in "tls_cacertfile"
    # use PEM format for CA cert, not DER format.
    tls_reqcert never
    #tls_cacertfile /etc/ssl/certs/ca-certificates.crt
    
    # The search scope.
    #scope sub
    
    # Add nested group support
    # Supported in nslcd 0.9 and higher.
    # default wheezy install of nslcd supports on 0.8. wheezy-backports has 0.9
    nss_nested_groups yes
    
    # Mappings for Active Directory
    # (replace the SIDs in the objectSid mappings with the value for your domain)
    # "dsquery * -filter (samaccountname=testuser1) -attr ObjectSID" 
    pagesize 1000
    referrals off
    idle_timelimit 1000
    
    # Do not allow uids lower than 100 to login (aka Administrator)
    # not needed as pam already has this support
    #  nss_min_uid 1000
    
    # This filter says to get all users who are part of the cumuluslnxadm group. Supports nested groups search filter.
    # Example, mary is part of the snrnetworkadm group which is part of cumuluslnxadm group
    # Ref: http://msdn.microsoft.com/en-us/library/aa746475%28VS.85%29.aspx (LDAP_MATCHING_RULE_IN_CHAIN)
    filter passwd (&(Objectclass=user)(!(objectClass=computer))(memberOf:1.2.840.113556.1.4.1941:=cn=cumuluslnxadm,ou=groups,ou=support,dc=rtp,dc=example,dc=test))
    map    passwd uid           sAMAccountName
    map    passwd uidNumber     objectSid:S-1-5-21-1391733952-3059161487-1245441232
    map    passwd gidNumber     objectSid:S-1-5-21-1391733952-3059161487-1245441232
    map    passwd homeDirectory "/home/$sAMAccountName"
    map    passwd gecos         displayName
    map    passwd loginShell    "/bin/bash"
    
    # Filter for any AD group or user in the baseDN. the reason for filtering for the
    # user to make sure group listing for user files don't say '<user> <gid>'. instead will say '<user> <user>'
    # So for cosmetic reasons..nothing more.
    filter group (&(|(objectClass=group)(Objectclass=user))(!(objectClass=computer)))
    map    group gidNumber     objectSid:S-1-5-21-1391733952-3059161487-1245441232
    map    group cn            sAMAccountName
    
  7. 启用安全 LDAP (可选)。

    • 将 LDAP CA 证书 (PEM 格式) 复制到客户端设备上 nslcd.conf tls_cacertfile 选项中指定的目录。确保指定的文件与复制的文件名匹配。
    • tls_reqcert 选项设置为 demand
    • 更改 URI 以使用 ldaps://
  8. 确认 LDAP 身份验证有效。

    • 使用 service nscd restart 重启 nscd 服务以清除缓存。这可能会缓存错误,然后您可能会花费数小时来排除不存在的问题。或者,使用以下命令清除 nscd 缓存中的 passwdgroup

      root# nscd --invalidate=group
      root# nscd --invalidate=passwd
      
    • 在调试模式下运行 nslcd

      root# service nslcd stop
      root# nslcd -d
      
    • 当它工作时,应输出如下内容: 用户列表: UID 和 GID 是用户 AD 对象 SID 的最后 4 位数字。请注意,“Mark Smith”支持经理不在那里。这是因为该用户不是 cumuluslnxadm 组的成员。

       root# getent passwd
       root:x:0:0:root:/root:/bin/bash
       daemon:x:1:1:daemon:/usr/sbin:/bin/sh
       ...
       ..........
       _lldpd:x:105:107::/var/run/lldpd:/bin/false
       joechen:*:1121:1121:Joe Chen:/home/joechen:/bin/bash
       marydiho:*:1124:1124:Mary Diho:/home/marydiho:/bin/bash
       obidia:*:1128:1128:Obi Dia:/home/obidia:/bin/bash
      

      组列表: 每个用户的 GID 都应该存在。由于您启用了嵌套组支持,因此所有嵌套组都会映射到正确的用户。

       root# getent group
       ..
       .....
       ssh:x:105:
       nslcd:x:106
       _lldpd:x:107:
       joechen:*:1121:
       marydiho:*:1124:
       marksmith:*:1125:
       obidia:*:1128:
       jnrnetworkadm:*:1118:obidia
       cumuluslnxadm:*:1120:obidia,marydiho,joechen
       snrnetworkadm:*:1126:marydiho,joechen
      
  9. 设置命令授权 (可选)。

    要使用 nslcd 进行授权,请在客户端设备上创建条目以与缓存的 LDAP 信息进行匹配。要完成此操作,您必须从 Wheezy repo 安装 sudo-ldap 软件包。

    在此示例中,您创建以下授权

    • 高级工程师可以运行任何特权和非特权命令。
    • 初级工程师可以运行 lldpctl 而无需密码。默认情况下,lldpctl 需要 root 访问权限。

    /etc/sudoers.d 目录添加两个文件,一个用于高级工程师,另一个用于初级工程师。您可以在 /etc/sudoers 文件中配置此项,但这可以使事情保持模块化。

    /etc/sudoers.d/snrnetworkadm:

    # allow any senior engineer root privilege after they type their password
    %snrnetworkadm ALL=(ALL) ALL
    

    /etc/sudoers.d/jnrnetworkadm:

    Cmnd_Alias LLDP_CMDS = /usr/sbin/lldpctl
    
    # allow any junior network engineer to run lldpctl without root permission
    %jnrnetworkadm ALL=(ALL) NOPASSWD: LLDP_CMDS
    

使用 Ansible 自动化

GitHub 上提供了 Ansible Playbook,GitHub,可自动化本文中显示的配置。