博客 | NGINX

使用 NGINX Plus 和 NGINX 通过 LDAP 对application用户进行身份验证

NGINX-F5-horiz-black-type-RGB 的一部分
欧文·加勒特缩略图
欧文·加勒特
2015 年 6 月 22 日发布

客户经常问我们如何使用 NGINX Plus 和 NGINX 通过对请求的用户进行身份验证来保护受保护的资源或应用。 今天,我们宣布了这种身份验证系统的参考实现,并将其发布在GitHub上的 NGINX, Inc. 存储库中。 在这篇文章中,我们描述了该实现的工作原理、如何安装它以及如何将它用作您自己的身份验证系统的模型。

该解决方案利用 NGINX Plus 和 NGINX 中的ngx_http_auth_request_module模块,将身份验证请求转发到外部服务。 在参考实现中,该服务是我们称之为ldap‑auth 的守护进程。 它是用 Python 编写的,默认情况下与轻量级目录访问协议 (LDAP) 身份验证服务器( OpenLDAP)进行通信,但我们也针对 Microsoft® Windows® Server Active Directory 的默认配置测试了 ldap‑auth 守护程序(2003 和 2012 版本)。

ldap‑auth 守护进程可作为您自己的“连接器”应用程序的模型,您可以用其他语言编写该应用程序,使用不同的身份验证系统进行部署,或者两者兼而有之。 NGINX专业服务团队可以协助进行此类调整。

笔记:

  • 该参考实现不适用于生产用途,而仅作为您自己实现的模型。
  • 为了方便阅读,本文的其余部分引用了 NGINX Plus,但参考实现也适用于 NGINX Open Source。 先决条件 http_auth_request 模块包含在NGINX Plus 包预构建的 NGINX 二进制文件中。

参考实现中的身份验证工作原理

为了执行身份验证,http_auth_request 模块向 ldap‑auth 守护进程发出 HTTP 子请求,该守护进程充当中介并解释 LDAP 服务器的子请求 - 它使用 HTTP 与 NGINX Plus 通信,并使用适当的 API 与 LDAP 服务器通信。

我们假设如果您对参考实现感兴趣,您已经有一个应用或其他资源,您想通过要求身份验证来保护它们。 但是,为了更容易测试参考实现,我们提供了一个示例后端守护程序,它也是用 Python 编写的,它监听端口 9000。 它可以在测试期间代替实际的 HTTP应用,通过提示用户凭证并基于这些凭证创建 cookie。

NGINX Plus 的 LDAP 身份验证参考实现包括 ldap-auth 守护程序和示例后端守护程序

以下是参考实施中身份验证过程的逐步描述。 详细信息由nginx-ldap-auth.conf配置文件中的设置决定;请参阅下面的配置参考实现。 步骤下方的流程图总结了该过程。

  1. 客户端发送 HTTP 请求,请求托管在服务器上的受保护资源,而 NGINX Plus 则充当该服务器上的反向代理。

  2. NGINX Plus(具体来说,是 http_auth_request 模块)将请求转发到 ldap‑auth 守护进程,该守护进程使用 HTTP 代码进行响应401因为没有提供任何凭证。

  3. NGINX Plus 将请求转发到http://backend/login ,它对应于后端守护进程。 它将原始请求 URI 写入转发请求的X-Target标头。

  4. 后端守护进程向客户端发送一个登录表单(该表单在守护进程的 Python 代码中定义)。 根据error_page指令的配置,NGINX 将登录表单上的 HTTP 代码设置为200

  5. 用户在表单上填写用户名和密码字段,然后单击登录按钮。 根据表单中的代码,客户端生成一个指向/login的 HTTP POST请求,NGINX Plus 将其转发到后端守护进程。

  6. 后端守护进程构造一个格式为用户名:密码的字符串,应用 Base64 编码,生成一个名为nginxauth的 cookie,并将其值设置为编码后的字符串,然后将该 cookie 发送给客户端。 它设置httponly标志以防止使用 JavaScript 读取或操纵 cookie(防止跨站点脚本 [XSS]漏洞)。

  7. 客户端重新传输其原始请求(从步骤 1 开始),这次将 cookie 包含在 HTTP 标头的Cookie字段中。 NGINX Plus 将请求转发到 ldap‑auth 守护进程(如步骤 2 所示)。

  8. ldap‑auth 守护进程解码 cookie,并在身份验证请求中将用户名和密码发送到 LDAP 服务器。

  9. 下一步操作取决于 LDAP 服务器是否成功验证用户身份:

    • 如果身份验证成功,ldap‑auth 守护进程将发送 HTTP 代码200到 NGINX Plus。 NGINX Plus 从后端守护进程请求资源。 在参考实现中,后端守护进程返回以下文本:

         你好世界! 请求的 URL: 网址
      

      nginx-ldap-auth.conf文件包含用于缓存身份验证尝试结果的指令;要禁用缓存,请参阅下面的缓存

    • 如果身份验证失败,ldap‑auth 守护进程将发送 HTTP 代码401到 NGINX Plus。 NGINX Plus 将请求再次转发给后端守护进程(如步骤 3 所示),并重复该过程。

在 NGINX Plus 的 LDAP 身份验证参考实现中,ldap-auth 守护进程是 NGINX Plus 和 LDAP 服务器之间的中介

安装组件

与参考实现一起分发的 NGINX Plus 配置文件nginx-ldap-auth.conf将除 LDAP 服务器之外的所有组件(即 NGINX Plus、客户端、ldap‑auth 守护程序和后端守护程序)配置为在同一主机上运行,这对于测试目的来说已经足够了。 在测试期间,LDAP 服务器也可以在该主机上运行。

在实际部署中,后端应用和身份验证服务器通常分别在单独的主机上运行,​​NGINX Plus 则在第三台主机上运行。 ldap-auth 守护程序在大多数情况下不会消耗太多资源,因此它可以在 NGINX Plus 主机或您选择的其他主机上运行。

  1. 创建GitHub 存储库的克隆。

  2. 如果 NGINX Plus 尚未运行,请根据操作系统的说明进行安装。

  3. 如果 LDAP 服务器尚未运行,请安装并配置一个。 默认情况下,ldap‑auth 守护程序与 OpenLDAP 通信,但也支持 Microsoft Windows Active Directory 2003 和 2012。

    如果您仅使用 LDAP 服务器来测试参考实现,则可以使用 GitHub 上提供的OpenLDAP 服务器 Docker 映像,或者可以使用诸如如何在 Ubuntu 16.04 上安装和配置 OpenLDAP 和 phpLDAPadmin 之类的说明来设置服务器。

    记下您为基本 DN、绑定 DN 和绑定密码设置的值。 您将把它们放在配置参考实现中的 NGINX 配置文件中。

  4. 在要运行 ldap‑auth 守护程序的主机上,安装以下附加软件。 我们建议使用随操作系统分发的版本,而不是从开源存储库下载软件。

    • Python 版本 2。 不支持版本 3。
    • Python LDAP 模块, python‑ldap (由python-ldap.org开源项目创建)。
  5. 将以下文件从存储库克隆复制到指示的主机:

    • nginx-ldap-auth.conf – NGINX Plus 配置文件,包含用于测试参考实现的最小指令集。 在 NGINX Plus 主机上安装(如果使用常规配置方案,则在/etc/nginx/conf.d目录中)。 为了避免配置冲突,请记住移动或重命名随 NGINX Plus 安装的任何默认配置文件。
    • nginx-ldap-auth-daemon.py – ldap‑auth 守护进程的 Python 代码。 安装在您选择的主机上。
    • nginx-ldap-auth-daemon-ctl.sh – 用于启动和停止守护进程的示例 shell 脚本。 与 ldap‑auth 守护程序安装在同一个主机上。
    • backend-sample-app.py – 测试期间代表后端应用服务器的守护进程的 Python 代码。 安装在您选择的主机上。
  6. 按照下面的配置参考实现中所述修改 NGINX Plus 配置文件。 进行更改后,运行nginx -t命令来验证文件在语法上是否有效。

    root# nginx -t nginx: 配置文件/etc/nginx/nginx.conf语法正确 nginx: 配置文件/etc/nginx/nginx.conf测试成功
    
  7. 启动 NGINX Plus。 如果 NGINX Plus 已运行,请运行以下命令重新加载配置文件:

    根目录#nginx -s reload
    
  8. 在适当的主机上运行以下命令来启动 ldap‑auth 守护程序和后端守护程序。

    root# nginx-ldap-auth-daemon-ctl.sh start root# python backend-sample-app.py
    
  9. 使用 Web 浏览器访问http:// nginx-server-address :8081 。 验证浏览器是否显示身份验证表单。 填写表单并提交后,请验证服务器是否对有效凭证返回预期的响应。 如上所述,后端守护进程返回以下文本:

       你好世界! 请求的 URL: 网址
    

配置参考实现

nginx-ldap-auth.conf文件中进行以下更改。 如上所述,有些是必需的,有些是可选的。

LDAP 服务器设置

按照nginx-ldap-auth-daemon.py中的实现,ldap‑auth 守护进程与 OpenLDAP 服务器进行通信,传递参数来指定要验证的用户帐户。 为了消除修改 Python 代码的需要, nginx-ldap-auth.conf文件包含proxy_set_header指令,用于设置 HTTP 标头中的值,然后用于设置参数。 下表映射了参数和标题。

LDAP 参数 HTTP 标头
基于 X-Ldap-BaseDN
绑定 X-Ldap-绑定DN
绑定密码 X-Ldap-BindPass
cookie名称 X-Cookie 名称
领域 X-Ldap-领域
模板 X-Ldap-模板
网址 X-Ldap-URL
  • (必需)在以下指令中,将粗体值替换为 LDAP 服务器部署的正确值。 特别注意, nginx-ldap-auth.conf文件使用 LDAPS 的知名端口 636。 如果将端口更改为 389(LDAP 的知名端口)或其他 LDAP 端口,还请记住将协议名称从ldaps更改为ldap

    # 连接 LDAP 服务器的 URL 和端口 proxy_set_header X-Ldap-URL " ldaps :// example.com :636 "; # 基本 DN proxy_set_header X-Ldap-BaseDN " cn=Users,dc=test,dc=local "; # 绑定 DN proxy_set_header X-Ldap-BindDN " cn=root,dc=test,dc=local "; # 绑定密码 proxy_set_header X-Ldap-BindPass " secret ";
    
  • (如果使用 Active Directory 而不是 OpenLDAP 则必需)取消注释以下指令,如下所示:

    proxy_set_header X-Ldap-Template "(SAMAccountName=%(username)s)";
    
  • (可选)参考实现使用基于 cookie 的身份验证。 如果您使用 HTTP 基本身份验证,请注释掉以下指令,如下所示:

    #proxy_set_header X-CookieName“nginxauth”; # proxy_set_header Cookie nginxauth=$cookie_nginxauth;
    
  • (可选)如果要更改 ldap‑auth 守护程序默认传递给 OpenLDAP 服务器的模板参数的值,请取消注释以下指令(如图所示),然后更改该值:

    proxy_set_header X-Ldap-Template " (cn=%(username)s) ";
    
  • (可选)如果要更改领域名称的默认值 ( Restricted ),请取消注释并更改以下指令:

    proxy_set_header X-Ldap-Realm “受限”;
    

后端守护进程的 IP 地址

如果后端守护进程未与 NGINX Plus 在同一主机上运行,请在上游配置块中更改其 IP 地址:

上游后端 { 服务器127.0.0.1:9000; }

ldap‑auth 守护进程的 IP 地址

如果 ldap‑auth 守护程序未与 NGINX Plus 在同一主机上运行,请更改此proxy_pass指令中的 IP 地址:

位置 = /auth-proxy { proxy_pass http://127.0.0.1 :8888; # ... }

NGINX 监听的 IP 地址和端口

如果客户端没有与 NGINX Plus 在同一主机上运行,请更改此listen指令中的 IP 地址(或完全删除该地址以接受来自任何客户端的流量)。 如果你愿意,你也可以将 NGINX 监听的端口从 8081 更改为:

服务器 { 监听127.0.0.18081 ; # ... }

缓存

nginx-ldap-auth.conf文件可以缓存数据和凭证。 您也可以选择更改以下设置:

  • http配置块中的proxy_cache_path指令创建一个名为cache的本地磁盘目录,并在共享内存中为名为auth_cache的区域分配 10 MB,用于存储元数据。

    proxy_cache_path缓存/ keys_zone= auth_cache : 10m ;
    

    如果您更改共享内存区域的名称,则还必须在proxy_cache指令(在将流量定向到 ldap‑auth 守护程序的位置块中)中更改它。

    位置 = /auth-proxy { proxy_cache auth_cache ; # ... }
    
  • proxy_cache_valid指令(与proxy_cache位于同一location块中)指定标有 HTTP 代码的缓存响应200或者403有效期为10分钟。

    位置 = /auth-proxy { proxy_cache_valid 200 403 10m ; # ... }
    

要禁用缓存,请注释掉这三个指令以及proxy_cache_key指令。

自定义身份验证系统

如上所述,您可以使用 ldap‑auth 守护程序作为您自己的应用的模型,该应用程序接受来自 http_auth_request 模块的请求。 如果用 Python 编写应用程序来与不同类型的(非 LDAP)身份验证服务器进行通信,请编写一个新的身份验证处理程序类来替换nginx-ldap-auth-daemon.py脚本中的LDAPAuthHandler

安全注意事项

后端守护进程对 cookie 中的用户名和密码使用 Base64 编码。 Base64 是一种非常弱的加密形式,导致凭证容易被提取和滥用。 为了使身份验证服务于任何实际目的,您需要在后端应用中使用更复杂的加密。


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”