为了增强安全性并改善用户体验, F5 NGINX Plus (R29+) 现在支持安全断言标记语言 (SAML)。 SAML 是一种为 Web应用提供单点登录 (SSO) 的完善协议,它允许身份提供者 (IdP) 验证用户对资源的访问权限,然后将该信息传递给服务提供商 (SP) 进行授权。
在这篇博文中,我们将逐步介绍如何使用不原生支持 SAML 的 Web应用将 NGINX 与Microsoft Entra ID (以前称为 Azure Active Directory (Azure AD))集成。 我们还介绍了如何为应用实现 SSO 并将其与 Microsoft Entra ID 生态系统集成。 通过学习本教程,您还将了解 NGINX 如何从 SAML 断言中提取声明(包括 UPN、名字、姓氏和组成员身份),然后通过 HTTP 标头将它们传递给应用。
本教程包括三个步骤:
要完成本教程,您需要:
dev.sports.com.crt 和 dev.sports.com.key
)demonginx.cer
来完成笔记: 本教程不适用于 NGINX 开源部署,因为键值存储是 NGINX Plus 独有的。
在此设置中,NGINX Plus 充当 SAML SP,并可以通过 SAML IdP 参与 SSO 实施,后者通过用户代理间接与 NGINX Plus 通信。
下图说明了 SSO 流程,其中包含 SP 启动和请求与响应的 POST 绑定。 需要再次注意的是,该通信渠道不是直接的,而是通过用户代理进行管理的。
图 1: SAML SP 发起的 SSO,具有针对 AuthnRequest 和 Response 的 POST 绑定
要访问您的 Microsoft Entra ID 管理门户,请登录并导航到左侧面板。 选择Microsoft Entra ID ,然后单击需要 SSO 配置的目录标题。 选择后,选择企业应用。
图 2: 在管理门户中选择企业应用
要创建应用,请单击门户顶部的“新建应用程序”按钮。 在这个例子中,我们创建了一个名为demonginx的应用。
图 3: 在 Microsoft Entra ID 中创建新应用
重定向到新创建的应用概述后,通过左侧菜单转到入门,然后单击管理下的单点登录。 然后,选择SAML作为单点登录方法。
图4: 使用 SSO 部分启动 SAML 配置
要在企业应用中设置 SSO,您需要在 Microsoft Entra ID 中将 NGINX Plus 注册为 SP。为此,请单击基本 SAML 配置中编辑旁边的铅笔图标,如图 5 所示。
添加以下值,然后单击“保存” :
验证证书的使用是可选的。 启用此设置时,必须解决 NGINX 中的两个配置选项:
$saml_sp_sign_authn
设置为true 。 这指示 SP 对发送给 IdP 的 AuthnRequest 进行签名。$saml_sp_signing_key
提供用于此签名的私钥路径。 确保将相应的公钥证书上传到Microsoft Entra ID进行签名验证。笔记: 在此演示中,属性和声明已被修改,并且添加了新的 SAML 属性。 这些 SAML 属性由 IdP 发送。 确保您的 NGINX 配置设置为正确接收和处理这些属性。 您可以在NGINX GitHub repo中检查和调整相关设置。
从 Microsoft Entra ID 下载 IdP证书(原始)并将其保存到您的 NGINX Plus 实例。
图5: 从 Microsoft Entra ID 下载 IdP 证书(原始)
图6: 添加新用户或组
在 Microsoft Entra ID 中,您可以通过添加或分配用户和组来授予对支持 SSO 的公司应用的访问权限。
在左侧菜单上,单击“用户和组” ,然后单击顶部按钮“添加用户/组” 。
在 NGINX Plus SP 中配置文件之前,请确保您拥有必要的证书:
dev.sports.com.crt 和 dev.sports.com.key
)demonginx.cer
)笔记: 证书需要采用 SPKI 格式。
要开始此步骤,请从 Microsoft Entra ID 下载 IdP 证书进行签名验证。 然后,将 PEM 转换为 DER 格式:
如果您想验证 SAML SP 断言,建议使用与用于 TLS 终止的公钥/私钥不同的公钥/私钥。
提取SPKI格式的公钥证书:
编辑 frontend.conf 文件以更新以下项目:
ssl_certificate
– 更新以包含 TLS 证书路径。ssl_certificate_key
– 更新以包含 TLS 私钥路径。在生产部署中,您可以根据业务需求使用不同的后端目的地。 在此示例中,后端提供了定制的响应:
我们通过为用户的邮件和objectid添加新的声明,修改了 Microsoft Entra ID 中的属性和声明。 这些更新使您能够为您的应用提供更加个性化和定制化的响应,从而改善用户体验。
图 7: Microsoft Entra ID 中修改的属性和声明
下一步是配置 NGINX,它将代理流量到后端应用。 在此演示中,后端 SAML应用在https://dev.sports.com上公开提供。
编辑你的frontend.conf
文件:
# 这是文件 frontend.conf
# 这是我们使用 SAML SSO 保护的后端应用
上游 my_backend {
区域my_backend 64k;
服务器 dev.sports.com;
}
# 自定义日志格式,在 REMOTE_USER 字段中包含“NameID”主题
log_format saml_sso'$remote_addr-$saml_name_id[$time_local]“$request”“$host”'
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 前端服务器 - 具有 SAML SSO 身份验证的反向代理
#
服务器 {
# 实现 SAML SSO 支持的功能位置
包括conf.d/saml_sp.server_conf;
# 按要求降低严重程度
错误日志 /var/log/nginx/error.log 调试;
听443 ssl;
ssl_certificate /home/ubuntu/dev.sports.com.crt;
ssl_certificate_key /home/ubuntu/dev.sports.com.key;
ssl_session_cache共享:SSL:5米;
地点 / {
# 当用户未通过身份验证时(即“saml_access_granted”。
# 变量未设置为“1”),则会出现 HTTP 401 未授权错误
# 返回,由@do_samlsp_flow 命名位置处理。
错误页面 401 = @do_samlsp_flow;
如果 ($saml_access_granted != "1") {
返回401;
}
# 成功验证的用户被代理到后端,
# 将 NameID 属性作为 HTTP 标头传递
proxy_set_header mail $saml_attrib_mail; # Microsoft Entra ID 的用户邮件
proxy_set_header objectid $saml_attrib_objectid; # Microsoft Entra ID 的对象 ID
访问日志 /var/log/nginx/access.log saml_sso;
代理密码<a href="http://my_backend;">http://my_backend;</a>
proxy_set_header 主机 dev.sports.com;
return 200 "欢迎来到应用页面\n我的objectid是$http_objectid\n我的电子邮件是$http_mail\n";
默认类型文本/纯文本;
}
}
# vim: 语法=nginx
为了使属性saml_attrib_mail
和saml_attrib_ objectid
反映在 NGINX 配置中,请按如下方式更新saml_sp_configuration.conf
的键值存储部分:
keyval_zone 区域=saml_attrib_mail:1M 状态=/var/lib/nginx/state/saml_attrib_email.json 超时=1h;
keyval $cookie_auth_token $saml_attrib_mail 区域=saml_attrib_mail;
keyval_zone 区域=saml_attrib_objectid:1M 状态=/var/lib/nginx/state/saml_attrib_objectid.json 超时=1h;
keyval $cookie_auth_token $saml_attrib_objectid 区域=saml_attrib_objectid;
接下来,配置 SAML SSO 配置文件。 该文件包含 SP 和 IdP 的主要配置。 要根据您的特定 SP 和 IdP 设置对其进行自定义,您需要调整文件中包含的多个 map{} 块。
下表提供了saml_sp_configuration.conf
中变量的描述:
多变的 | 描述 |
---|---|
saml_sp_entity_id | 用户用来访问应用的 URL。 |
示例:saml_sp_acs_url | 服务提供商用来接收和处理 SAML 响应、提取用户身份,然后根据提供的信息授予或拒绝对请求的资源的访问的 URL。 |
saml_sp_sign_authn | 指定从 SP 到 IdP 的 SAML 请求是否应该签名。 签名是使用 SP 签名密钥完成的,您需要将相关证书上传到 IdP 来验证签名。 |
saml_sp_签名密钥 | 用于签署从 SP 到 IdP 的 SAML 请求的签名密钥。 确保将相关证书上传到 IdP 以验证签名。 |
saml_idp_entity_id | 用于定义 IdP 的身份。 |
saml_idp_sso_url | SP 向其发送 SAML 断言请求以启动身份验证请求的 IdP 端点。 |
saml_idp_verification_certificate | 用于验证从 IdP 收到的签名 SAML 断言的认证。 该证书由IdP提供,需要采用SPKI格式。 |
网址 | IdP 向其发送 SAML LogoutRequest(启动注销过程时)或 LogoutResponse(确认注销时)的 SP 端点。 |
签名 | 指定注销 SAML 是否要由 SP 签名。 |
示例:saml_idp_slo_url | SP 向其发送 LogoutRequest(启动注销过程时)或 LogoutResponse(确认注销时)的 IdP 端点。 |
saml_sp_want_signed_slo | 指定 SAML SP 是否希望对来自 IdP 的 SAML 注销响应或请求进行签名。 |
下面的代码仅显示针对saml_sp_configuration.conf 此用例的编辑值。
笔记: 确保配置文件的其余部分仍然出现在文件中(例如,键值存储)。 还要确保根据您的部署正确调整saml_sp_configuration.conf
文件中的变量。
# SAML SSO 配置
map $host $saml_sp_entity_id {
# 向 IdP 标识 SP 的唯一标识符。
# 必须是 URL 或 URN。
default "https://dev.sports.com";
}
map $host $saml_sp_acs_url {
# ACS URL,IdP 将使用其身份验证响应重定向到的 SP 上的端点。
# 必须与“saml_sp.serer_conf”文件中定义的 ACS 位置匹配。
default "https://dev.sports.com/saml/acs";
}
map $host $saml_sp_request_binding {
# 指在单点登录 (SSO) 过程中从 SP 向 IdP 发送身份验证请求的方法。
# 仅允许 HTTP-POST 或 HTTP-Redirect 方法。
default 'HTTP-POST';
}
map $host $saml_sp_sign_authn {
# SP 是否应签署发送给 IdP 的 AuthnRequest。
default "false";
}
map $host $saml_sp_decryption_key {
# 指定 SP 用于解密来自 IdP 的加密断言
# 或 NameID 的私钥。
default "";
}
map $host $saml_sp_force_authn {
# SP 是否应强制 IdP 对用户进行重新身份验证。
default "false";
}
map $host $saml_sp_nameid_format {
# 指示 IdP 生成的 SAML 断言中名称标识符的所需格式。 检查 SAML 2.0 Core 规范的第 8.3 节
# (http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf)
# 以获取允许的 NameID 格式列表。
default "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified";
}
map $host $saml_sp_relay_state {
# SP 应在成功登录后重定向到的相对或绝对 URL。
default "";
}
map $host $saml_sp_want_signed_response {
# SP 是否希望 IdP 的 SAML 响应
# 进行数字签名。
default "false";
}
map $host $saml_sp_want_signed_assertion {
# SP 是否希望 IdP 的 SAML 断言
# 进行数字签名。
default "true";
}
map $host $saml_sp_want_encrypted_assertion {
# SP 是否希望 IdP 的 SAML 断言
# 进行加密。
default "false";
}
map $host $saml_idp_entity_id {
# 向 SP 标识 IdP 的唯一标识符。
# 必须是 URL 或 URN。
default "https://sts.windows.net/8807dced-9637-4205-a520-423077750c60/";
}
map $host $saml_idp_sso_url {
# SP 将发送 SAML AuthnRequest 以启动
# 身份验证过程的 IdP 端点。
default "https://login.microsoftonline.com/8807dced-9637-4205-a520-423077750c60/saml2";
}
map $host $saml_idp_verification_certificate {
# 将用于验证从 IdP 收到的 SAML Response、LogoutRequest 或 LogoutResponse 上的数字签名的证书文件。
# 必须是 PKCS#1 格式的公钥。 请参阅有关如何将
# X.509 PEM 转换为 DER 格式的文档。
default "/etc/nginx/conf.d/demonginx.spki";
}
######### 单点注销 (SLO) #########
map $host $saml_sp_slo_url {
# IdP 将发送 SAML LogoutRequest 以启动
# 注销过程的 SP 端点或用于确认注销的 LogoutResponse。
default "https://dev.sports.com/saml/sls";
}
map $host $saml_sp_slo_binding {
# 指在单点注销 (SLO) 过程中从 SP 向 IdP 发送 LogoutRequest 或 LogoutResponse
# 的方法。
# 仅允许使用 HTTP-POST 或 HTTP-Redirect 方法。
default 'HTTP-POST';
}
map $host $saml_sp_sign_slo {
# SP 是否必须签署发送给 IdP 的 LogoutRequest 或 LogoutResponse。
默认“false”;
}
map $host $saml_idp_slo_url {
# SP 将发送 LogoutRequest 以启动注销过程的 IdP 端点或发送 LogoutResponse 以确认注销。
# 如果未设置,则 SAML 单点注销 (SLO) 功能将被禁用,并且对“注销”位置的请求将导致用户会话终止并重定向到注销登录页面。
默认“https://login.microsoftonline.com/8807dced-9637-4205-a520-423077750c60/saml2”;
}
map $host $saml_sp_want_signed_slo {
# SP 是否希望 IdP 的 SAML LogoutRequest 或 LogoutResponse
# 进行数字签名。
default "true";
}
map $host $saml_logout_landing_page {
# 请求 /logout 位置后将用户重定向到何处。 这可以
# 用自定义注销页面或完整 URL 替换。
default "/_logout"; # 内置的简单注销页面
}
map $proto $saml_cookie_flags {
http "Path=/; SameSite=lax;"; # 用于 HTTP/纯文本测试
https "Path=/; SameSite=lax; HttpOnly; Secure;"; # 生产建议
}
map $http_x_forwarded_port $redirect_base {
"" $proto://$host:$server_port;
default $proto://$host:$http_x_forwarded_port;
}
map $http_x_forwarded_proto $proto {
"" $scheme;
default $http_x_forwarded_proto;
}
# 此行以下的高级配置
# saml_sp.server_conf 中的其他高级配置(服务器上下文)
######### 保存与 SAML 相关的键值数据库的共享内存区域
# 用于存储 AuthnRequest 和 LogoutRequest 消息标识符 (ID) 的区域
# 以防止重放攻击。 (必需)
# 超时决定 SP 等待 IDP 响应的时间,
# 即用户身份验证过程需要多长时间。
keyval_zone zone=saml_request_id:1M state=/var/lib/nginx/state/saml_request_id.json timeout=5m;
# 用于存储 SAML 响应消息标识符 (ID) 的区域,以防止重放攻击。 (必需)
# 超时决定 SP 保留 ID 以防止重复使用的时间。
keyval_zone zone=saml_response_id:1M state=/var/lib/nginx/state/saml_response_id.json timeout=1h;
# 用于存储 SAML 会话访问信息的区域。 (必需)
# 超时决定 SP 保留会话访问决策的时间(会话生命周期)。
keyval_zone zone=saml_session_access:1M state=/var/lib/nginx/state/saml_session_access.json timeout=1h;
# 用于存储 SAML NameID 值的区域。 (必需)
# 超时决定 SP 保留 NameID 值的时间。 必须等于会话生存期。
keyval_zone zone=saml_name_id:1M state=/var/lib/nginx/state/saml_name_id.json timeout=1h;
# 用于存储 SAML NameID 格式值的区域。 (必需)
# 超时决定 SP 保留 NameID 格式值的时间。 必须等于会话生存期。
keyval_zone zone=saml_name_id_format:1M state=/var/lib/nginx/state/saml_name_id_format.json timeout=1h;
# 用于存储 SAML SessionIndex 值的区域。 (必需)
# 超时决定 SP 保留 SessionIndex 值的时间。 必须等于会话生存期。
keyval_zone zone=saml_session_index:1M state=/var/lib/nginx/state/saml_session_index.json timeout=1h;
# 用于存储 SAML AuthnContextClassRef 值的区域。 (必需)
# 超时决定 SP 保留 AuthnContextClassRef 值的时间。 必须等于会话生存期。
keyval_zone zone=saml_authn_context_class_ref:1M state=/var/lib/nginx/state/saml_authn_context_class_ref.json timeout=1h;
# 用于存储 SAML 属性值的区域。 (可选)
# 超时决定 SP 保留属性值的时间。 必须等于会话生存期。
keyval_zone zone=saml_attrib_uid:1M state=/var/lib/nginx/state/saml_attrib_uid.json timeout=1h;
keyval_zone zone=saml_attrib_name:1M state=/var/lib/nginx/state/saml_attrib_name.json timeout=1h;
keyval_zone zone=saml_attrib_memberOf:1M state=/var/lib/nginx/state/saml_attrib_memberOf.json timeout=1h;
######### SAML 相关变量,其值由键值数据库中的键(会话 cookie)查找。
# 必需:
keyval $saml_request_id $saml_request_redeemed zone=saml_request_id; # SAML 请求 ID
keyval $saml_response_id $saml_response_redeemed zone=saml_response_id; # SAML 响应 ID
keyval $cookie_auth_token $saml_access_granted zone=saml_session_access; # SAML 访问决策
keyval $cookie_auth_token $saml_name_id zone=saml_name_id; # SAML 名称 ID
keyval $cookie_auth_token $saml_name_id_format zone=saml_name_id_format; # SAML 名称 ID 格式
keyval $cookie_auth_token $saml_session_index zone=saml_session_index; # SAML 会话索引
keyval $cookie_auth_token $saml_authn_context_class_ref zone=saml_authn_context_class_ref; # SAML AuthnContextClassRef
# 可选:
keyval $cookie_auth_token $saml_attrib_uid zone=saml_attrib_uid;
keyval $cookie_auth_token $saml_attrib_name zone=saml_attrib_name;
keyval $cookie_auth_token $saml_attrib_memberOf zone=saml_attrib_memberOf;
keyval_zone zone=saml_attrib_mail:1M state=/var/lib/nginx/state/saml_attrib_mail.json timeout=1h;
keyval $cookie_auth_token $saml_attrib_mail zone=saml_attrib_mail;
keyval $cookie_auth_token $saml_attrib_objectid zone=saml_attrib_objectid;
keyval_zone zone=saml_attrib_objectid:1M state=/var/lib/nginx/state/saml_attrib_objectid.json timeout=1h;
######### 导入实现 SAML SSO 和 SLO 功能的模块
js_import samlsp from conf.d/saml_sp.js;
测试配置需要两部分:
使用 NGINX Plus 配置 SAML SP 并使用 Microsoft Entra ID 配置 IdP 后,验证 SAML 流至关重要。 此验证过程可确保通过 IdP 的用户身份验证成功,并且授予对 SP 保护的资源的访问权限。
要验证 SP 发起的 SAML 流,请打开您喜欢的浏览器并在地址栏中输入https://dev.sports.com 。 这将把您引导至 IdP 登录页面。
图 8: IdP 登录页面
输入在 IdP 登录页面中配置的用户的凭据。 在用户提交后,IdP 将会对用户进行身份验证。
图 9: 输入已配置的用户凭证
成功建立会话后,用户将被授予对先前请求的受保护资源的访问权限。 随后,该资源将显示在用户的浏览器中。
图 10: 成功加载的应用页面
通过检查 SP 和 IdP 日志可以获得有关 SAML 流的有价值的信息。 在 SP 端(NGINX Plus),确保 auth_token cookie 设置正确。 在 IdP 端(Microsoft Entra ID),确保身份验证过程顺利完成,并且 SAML 断言已发送给 SP。
NGINX access.log
应如下所示:
127.0.0.1 - - [14/Aug/2023:21:25:49 +0000] “GET / HTTP/1.0” 200 127 “https://login.microsoftonline.com/” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML,如 Gecko) Version/16.1 Safari/605.1.15” “-”
99.187.244.63 - Akash Ananthanarayanan [14/Aug/2023:21:25:49 +0000] “GET / HTTP/1.1” “dev.sports.com” 200 127 “https://login.microsoftonline.com/” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15(KHTML,如 Gecko)版本/16.1 Safari/605.1.15" "-
而 NGINX debug.log
如下所示:
2023/08/14 21:25:49 [信息] 27513#27513: *399 js: SAML SP 成功,创建会话 _d4db9b93c415ee7b4e057a4bb195df6cd0be7e4d
SAML 单点注销 (SLO) 允许用户通过一个操作注销所有相关的 IdP 和 SP。 NGINX Plus 支持 SP 发起和 IdP 发起的注销场景,增强 SSO 环境中的安全性和用户体验。 在此示例中,我们使用 SP 发起的注销场景。
图 11: SAML SP 发起的 SLO,具有针对 LogoutRequest 和 LogoutResponse 的 POST/重定向绑定
验证您的会话后,通过访问 SP 中配置的注销 URL 注销。 例如,如果您已将https://dev.sports.com/logout设置为 NGINX Plus 中的注销 URL,请在浏览器的地址栏中输入该 URL。
图 12: 成功退出会话
为了确保安全注销,SP 必须发起 SAML 请求,然后由 IdP 进行验证和处理。 此操作有效地终止了用户的会话,然后 IdP 将发送 SAML 响应以将用户的浏览器重定向回 SP。
恭喜! NGINX Plus 现在可以充当 SAML SP,为身份验证过程提供另一层安全性和便利性。 这一新功能是 NGINX Plus 向前迈出的重要一步,使其成为优先考虑安全性和效率的组织的更强大、多功能的解决方案。
您现在就可以开始使用 SAML 和 NGINX Plus,只需启动NGINX Plus 的 30 天免费试用即可。 我们希望您发现它有用并欢迎您的反馈。
有关 NGINX Plus 与 SAML 的更多信息,请参阅以下资源。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”