Linux 和 Windows:Kerberos、SSSD、DFS 和黑魔法的故事
Linux and Windows: A tale of Kerberos, SSSD, DFS, and black magic (2018)

原始链接: http://www.draeath.net/blog/it/2018/03/13/DFSwithKRB/

## Linux 与 Active Directory 集成:摘要 本文档详细介绍了一种轻量级的 Linux 系统与 Active Directory (AD) 集成方法,仅用于身份验证,不包括 GPO 或打印服务等功能。该过程涉及几个关键步骤: **1. 准备:** 为了与 `adcli` 等工具兼容,建议将主机名设置为大写 FQDN。 **2. 包安装:** 必需的软件包包括 `krb5-users`、`adcli`、`realmd`、`sssd`、OpenLDAP 客户端以及 Kerberos 和 SSSD 的 PAM 模块,以及用于 DFS 挂载的 CIFS 工具。 **3. Kerberos & 域加入:** 配置 `krb5.conf`(使用区分大小写的 realm 名称)并获取 Kerberos 票据至关重要。然后,`realmd` 会将系统加入域,利用现有的票据——如果权限不足,则会静默失败。 **4. SSSD 配置:** SSSD 处理来自 AD 的用户和组信息。提供的示例配置需要自定义,尤其要注意 Kerberos realm 条目的区分大小写。 **5. DFS 挂载:** 通过 `sec=krb5` 在 `fstab` 中挂载 DFS 共享需要修改 `/etc/request-key.conf` 或 `/etc/request-key.d/*`,将 `-t` 添加到 `cifs.upcall` 命令中,以信任 DNS 进行准确的身份验证。 作者指出由于复杂性原因,省略了通过 DFS 进行 autofs 主目录挂载,但建议使用 autofs 的“program”映射类型作为潜在解决方案。 域管理员密码的安全凭证管理(例如 Hashicorp Vault)也被强调为重要事项。

相关文章

原文

Linux and Windows: A tale of Kerberos, SSSD, DFS, and black magic.

Posted on March 13, 2018

Overview

Interfacing with Active Directory is kind of a pain in the rear. Here’s what I’ve implemented. This is somewhat lightweight, in that AD is only used for authentication - it is not used (directly) for access control, GPO is not utilized, no print services, etc. I do not go over autofs configuration, because it’s pretty straightforward.

  1. Confirm hostname
  2. Install packages
  3. Configure Kerberos
  4. Initialize Kerberos ticket
  5. Join to domain
  6. Configure SSSD
  7. Configure DFS mounts

Details

Hostname

You should set your hostname to be your FQDN, uppercased. This doesn’t have to look ugly, if you have systemd! This will fix it to uppercase FQDN where it matters, but for display purposes you should see a lowercase short name.

You don’t have to do this, but you may have problems with adcli later on, for example when it attempts to update the machine account in AD.

hostnamectl --static set-hostname "FOO.AD.EXAMPLE.COM"
hostnamectl --pretty set-hostname "foo"
hostnamectl --transient set-hostname ""

Packages

This depends on your distribution, of course. You will need the krb5 userspace, adcli, realmd, sssd, the openldap client, and the PAM modules for krb5 and sssd. For mounting DFS, you’ll need the CIFS tools.

Kerberos Configuration

This is pretty straightforward. Note that realm names in Kerberos are case-sensitive and should be uppercased - contrary to DNS. Example /etc/krb5.conf file follows.

[libdefaults]
default_realm = AD.EXAMPLE.COM
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h
renew_lifetime = 7d
rdns = false
forwardable = true
default_ccache_name = KEYRING:persistent:%{uid}

[domain_realm]
.ad.example.com = AD.EXAMPLE.COM
ad.example.com = AD.EXAMPLE.COM

Kerberos Ticket

This is also pretty straightforward - the complexity comes with automation, if you want to do that. Here’s an example ansible task, for inspiration. You can also see how to do it manually, if you don’t care about automating it. Note that GetDomainAdminPassword is left as an exercise for your imagination. Something like Hashicorp Vault may be ideal. Either way, you should take care with the credential. Again, the Kerberos realm is case sensitive!

- name: initialize Kerberos ticket
  shell: |
    set timeout 300
    spawn /usr/bin/kinit -V [email protected]
    expect -exact "Password for adminuser"
    send -- "{{ lookup('pipe', '/usr/local/bin/GetDomainAdminPassword') }}\r"
    expect eof
    catch wait result
    exit [lindex $result 3]
  args:
    executable: /usr/bin/expect
  changed_when: false
  no_log: true

Domain Join

This next step, using realmd to join the domain, should not require authentication. If it asks, something is wrong! It should use the previously created Kerberos ticket. Note, that if the user does not have permissions to create the computer account, it will silently fail and realmd will ask for a password on the TTY. You should use an uppercase computer name (FQDN, not hostname!), but the domain argument (the last one) can be lowercase. Also note the “static” hostname you set back in step 1 should match the computer name supplied here.

The following example is a single command, I have broken the arguments out to individual lines for clarity.

/usr/sbin/realm
  --unattended
  join
  --automatic-id-mapping=no
  --client-software=sssd
  --computer-name=FOO.AD.EXAMPLE.COM
  --computer-ou='OU=Linux,OU=Servers,DC=ad,DC=example,DC=com'
  ad.example.com

SSSD Configuration

This part will need some customization on your part. I’m not going to go into all the details, rather I’m going to show you a working example. Note that some of the domain name entries are uppercase - in those cases it’s referring to the Kerberos realm (and as such are case sensitive - thanks, MIT!), so keep them uppercase.

[sssd]
config_file_version = 2
domains = ad.example.com
reconnection_retries = 3
services = nss, pam

[nss]
entry_cache_nowait_percentage = 75
filter_groups = root
filter_users = root
reconnection_retries = 3

[pam]
reconnection_retries = 3

[domain/AD.EXAMPLE.COM]
access_provider = simple
account_cache_expiration = 7
ad_domain = ad.example.com
auth_provider = ad
cache_credentials = True
default_shell = /bin/bash
dns_discovery_domain = AD.EXAMPLE.COM
dyndns_update = false
enumerate = true
fallback_homedir = /home/%u
id_provider = ad
krb5_realm = AD.EXAMPLE.COM
krb5_store_password_if_offline = True
ldap_id_mapping = False
ldap_schema = ad
realmd_tags = manages-system joined-with-samba
simple_allow_groups = AdminGroup, DevelGroup, OpsGroup
simple_allow_users = bob, alice, charlie
use_fully_qualified_names = False

DFS Mounts with KRB5

The /etc/fstab config is pretty self-explanatory. Note that sec=krb5 only uses Kerberos for authentication. Traffic is not necessarily private or guaranteed integrity. Check man mount.cifs for possible settings (ignore the non-Kerberos items)

//domain/root/path /mnt/path cifs noauto,nofail,rw,user,sec=krb5 0 0

However, unless your AD/DNS admins have gone out of their way to set up a bunch of normally-useless DNS records, you will not have much luck with DFS without a further tweak. This is because authentication will use the provided target hostname, which is probably not the name of the host actually responding. The secret sauce? cifs.upcall needs an additional argument, -t, which tells it to trust DNS and perform a PTR lookup, and authenticate against that hostname. Don’t do this if you don’t trust your DNS servers (trust as in authentic, not reliable).

Find the create cifs.spnego line(s) calling cifs.upcall in /etc/request-key.conf and/or /etc/request-key.d/* and add the -t argument. It should look something like this:

create  cifs.spnego    * * /usr/sbin/cifs.upcall -t %k

Bonus: this works for standalone server shares, too, not just DFS!

Things Left Undone

If there is one thing that stands out as not implemented, it’s using a DFS share for an autofs home mount. It’s certainly doable - but there’s two gotchas that come to mind. First, the user would need to have a kerberos ticket. Second, the mount command would need to be executed as the user, not as root. Fortunately, autofs has available a concept of a “program” map type that may be abused for the purpose. This is simply a map file that’s been set with executable permissions (be sure to include a shebang). The program should accept a single argument (the “key” - the first field in a normal map) and should output via STDOUT the remaining fields of a normal map. Of course, nothing stops you from doing other things in the script/program, and it does run as root…

联系我们 contact @ memedata.com