使用 pam_krb5 的 PAM 来验证 nginx 请求

使用 pam_krb5 的 PAM 来验证 nginx 请求

我知道这里和“Unix/Linux”上的 gazzilion pam / nginx 问题,但它们要么没有答案,要么与我的设置无关 - 所以我再试一次:)

总结

虽然设置与Apache+mod_kerb_auth组合完美配合,但使用时我无法使自动票证转发正常工作nginx+pam_krb5- 但是针对 Kerberos 的基本身份验证却有效。问题是,可能是什么原因以及/或者如何进一步调试它。

以下是所有详细信息、配置和环境


我的设置:

  • 实验室中的 Windows 2012 DC(全新安装并配置 KDC)
  • Debian Stretch Linux 作为我们的“服务”
  • 在那个 Debian 盒子上我有:kerb-client MIT、Apache2+mod_kerb_auth 和 nignx+nginx_pam+pam
  • MacOS 客户端

正在运行的是:

  • 我有通常的设置,包括 keytab-file、/etc/krb5.conf 以及所有的 realm/default_realm 部分。(见下文)
  • 我可以使用 keytab 文件和我的 SPN 进行 kinit:(HTTP/wiki.kwtest.local见下文)
  • 在同一个 Debian 服务器上使用 Apache2 + mod_kerb_auth,它完全可以工作,包括票证转发(我猜这确认了 krb5.conf / keytab / KDC /infra 设置可以工作)。因此,我可以在我的 OSX 上使用kinit+curl --negotiate或 Safari 并立即获得访问权限。
  • 添加 pam auth(见下文)和 pam 设置后,我可以通过 safari 访问时输入 AD 用户凭据进行身份验证(由于 curl 立即获得 401 -u)...但票证转发/验证不起作用

设置详情:

Kerberos 客户端配置/etc/krb5.conf

[libdefaults]
  default_realm = KWTEST.LOCAL
  kdc_timesync = 1
  # https://web.mit.edu/kerberos/krb5-1.12/doc/basic/ccache_def.html
  # we do not want the keyring due to docker
  ccache_type = 3
  forwardable = true
  proxiable = true
  # no reverse lookup
  rdns = false

[realms]
  KWTEST.LOCAL = {
    kdc = kdc.kwtest.local
    admin_server = kdc.kwtest.local
  }

[login]
  krb4_convert = true
  krb4_get_tickets = false

[logging]
  default = FILE:/var/log/kdc.log:SYSLOG
  kdc = FILE:/var/log/kdc.log:SYSLOG

# https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html?highlight=appdefaults#appdefaults
[appdefaults]
  forwardable = true
  # https://manpages.debian.org/stretch/libpam-heimdal/pam_krb5.5.en.html
  pam = {
    ignore_k5login=true
    debug=true
    forwardable = true
    proxiable = true
    minimum_uid = 0
    realm = KWTEST.LOCAL
    keytab = /mnt/config/kerberos/drupalwiki.keytab
  }

Pam 配置/etc/pam.d/dw-kerb-nginx

cat /etc/pam.d/dw-kerb-nginx

auth  required  pam_krb5.so keytab=/mnt/config/kerberos/drupalwiki.keytab minimum_uid=20 forwardable=true realm=KWTEST.LOCAL trace=/var/log/pamtrace silent=false debug=true
account  required  pam_unix.so keytab=/mnt/config/kerberos/drupalwiki.keytab minimum_uid=20 forwardable=true realm=KWTEST.LOCAL trace=/var/log/pamtrace silent=false debug=true

该默认服务器的 Nginx 配置为/etc/nginx/sites-enabled/default

cat /etc/nginx/sites-enabled/default

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    index index.html index.htm index.nginx-debian.html;

    server_name _;

        error_log /var/log/nginx/error.log debug;
        location / {
          auth_pam              "Secure Zone";
          auth_pam_service_name "dw-kerb-nginx";
          try_files $uri $uri/ =404;
    }
}

KVNO 数字匹配

#kdc KVNO
kvno HTTP/[email protected]
HTTP/[email protected]: kvno = 16

#client KVNO
klist -ke /mnt/config/kerberos/drupalwiki.keytab
Keytab name: FILE:/mnt/config/kerberos/drupalwiki.keytab
KVNO Principal
---- --------------------------------------------------------------------------
  16 HTTP/[email protected] (arcfour-hmac)

服务 Keytab 文件/mnt/config/kerberos/drupalwiki.keytab列出了 SPN

klist -ke /mnt/config/kerberos/drupalwiki.keytab
Keytab name: FILE:/mnt/config/kerberos/drupalwiki.keytab
KVNO Principal
---- --------------------------------------------------------------------------
  16 HTTP/[email protected] (arcfour-hmac)

keytab使用 SPN登录文件

kinit -k -t /mnt/config/kerberos/drupalwiki.keytab HTTP/[email protected]

klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: HTTP/[email protected]

Valid starting       Expires              Service principal
01/07/2019 12:50:18  01/07/2019 22:50:18  krbtgt/[email protected]
    renew until 01/08/2019 12:50:18

问题(不起作用):

票证转发,即现有的客户端票证,不经过验证,而是提供基本身份验证表单以输入凭据 - 如果我这样做,我就可以进行身份​​验证。因此,基本 krb 身份验证已经起作用,只是票证转发/验证不起作用。

请注意,完全相同的客户端(OSX Safari、OSX curl、Linux Curl)和完全相同的 Debian Stretch 服务器都可以使用。因此,这几乎不可能是服务文件或的Apache2+mod_ker_auth直接问题,否则 apache2 也无法工作,对吗?keytab/etc/krb5.conf

我如何测试

使用我的 OSX 客户端进行测试

# wikiuser is an user in the same AD/KDC ( not the user of the SPN)
kinit [email protected]

# ticket exists
klist
Credentials cache: API:34173A61-DFBB-4191-A39C-62EF67F1AC39
        Principal: [email protected]

  Issued                Expires               Principal
Jan  7 13:26:38 2019  Jan  7 23:26:20 2019  krbtgt/[email protected]

# the actual test
curl -u : --negotiate http://wiki.kwtest.local/index.html
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.10.3</center>
</body>
</html>

做同样的测试,同时停止 nginx 并启动 apache2

# on the Debian Service box
service nginx stop && service apache2 start

现在在我的 OSX 盒子上

kinit
curl -u : --negotiate http://wiki.kwtest.local/index.html
worked!%

我尝试修复它

  • 尝试使用 rsyslog 和 debug=true / trace=/var/log/pamtrace 设置尽可能详细地记录 pam,但我从未在其中得到任何输出。PAM 似乎根本无法记录身份验证尝试。只有当我填写基本表单并实际成功验证时,我才会在日志中看到此尝试 - 但使用现有票证的失败尝试根本没有记录任何内容
  • 尝试了各种pam_krb5参数和设置realm,但还是无法让它工作
  • 使用 Linux 客户端通过 curl 进行测试,结果相同

如果我忘记了设置细节或信息中的任何内容,请告诉我,我完全清楚 Kerberos 很复杂,而且对所有这些事情都很敏感,我希望已经包含了所有的点点滴滴

答案1

这个问题的简短回答是,nginx_pam 根本不可能做到这一点。

我要求的技术术语/协议是“GSSAPI”或基于 SPENGO 的 Kerberos 票证认证,因此如果用户有现有的 Kerberos 票证,他就会自动登录。

nginx_pam 不实现 SPENGO/GSSAPI,因此这永远不会起作用。应该发生的是

  1. 客户端在第一次请求时请求资源(尚未发送任何身份验证标头)

  2. 我们的 nginx 会通过 nginx_pam 将其传递给 pam,然后 pam 应该返回“未授权”(不存在身份验证标头)。Nginx 现在应该向浏览器返回带有标头“WWW-Authorize:negotiate”的“401”(然后浏览器会自动发送带有“Authorization”标头中的 kerb 票证的新请求

  3. nginx 现在应该解压该票证(based64 解码等)并将票证传递给 pam(pam_krb)

  4. pam 将返回“ok”或“forbidden”(不允许此用户)。前者是 200,后者是 403,用于传递给客户端的 nginx

步骤 2 不是由 nginx_pam 实现的。另外,我猜(不确定),pam 只支持“授权”或“未授权”,所以是布尔值,而不是“未经身份验证”、“授权”、“禁止”……因此无法确定步骤 2 和步骤 4(相同)

解决方案:我换成了https://github.com/stnoonan/spnego-http-auth-nginx-module以获得正确的基于 GSSAPI 的实现。

相关内容