带有客户端身份验证的 Apache HTTPD/mod_proxy/Tomcat 和 SSL
Posted
技术标签:
【中文标题】带有客户端身份验证的 Apache HTTPD/mod_proxy/Tomcat 和 SSL【英文标题】:Apache HTTPD/mod_proxy/Tomcat and SSL with client auth 【发布时间】:2012-04-25 09:32:14 【问题描述】:我确定这是一个常见问题解答,但我找不到任何我认为是同一个问题的问题。
我有几个在 Tomcat 中运行的网络应用程序,其中有一些页面,例如受 SSL 保护的登录页面,由其 web.xmls 中的机密性元素定义。其中一个应用程序还通过证书接受客户端身份验证。我还有一个相当广泛的基于 JAAS 的授权和身份验证方案,并且各种 webapp 之间有各种共享代码和不同的 JAAS 配置等。
在完成以下任务时,我真的不想打扰任何事情。
在添加更多 Tomcat 实例之前,我现在正在将带有 mod-proxy 和 mod-proxy-balancer 的 Apache HTTPD 作为负载平衡器插入到 Tomcat 前面。
我想要为 HTTPS 请求完成的是它们被“盲目”重定向到 Tomcat 而 HTTPD 不是 SSL 端点,即 HTTPD 只是将密文直接传递给 Tomcat,以便 TC 可以继续做它已经在做的登录, SSL、web.xml 保密保证,以及最重要的客户端身份验证。
我描述的配置可以做到这一点吗?
我对 webapps 和 SSL 以及 HTTPS 和 Tomcat 非常熟悉,但是我对 Apache HTTPD 的外围知识了解有限。
如果有必要,很高兴移动它,但它是一种使用配置文件的编程;)
【问题讨论】:
@downvoter 你的观点? 【参考方案1】:这听起来类似于this question,我已经回答说这是不可能的:
您不能只将 SSL/TLS 流量从 Apache 中继到 Tomcat。任何一个 您的 SSL 连接在 Apache 结束,然后您应该反向代理 到 Tomcat 的流量(SSL [在 Httpd 和 Tomcat 之间] 在这种情况下很少有用),或者你让 客户端直接连接到 Tomcat 并让它处理 SSL 连接。
我承认支持这一说法的链接有点少。我想我可能是错的(我只是从未见过这样做,但这并不严格意味着它不存在......)。
如您所知,您需要在用户代理和 SSL 端点之间建立直接连接或完全中继的连接(在这种情况下,您希望它是 Tomcat)。这意味着 Apache Httpd 将无法查看 URL:它最多只能知道主机名(当使用服务器名称指示时)。
似乎不依赖于mod_proxy
documentation 中的 URL 的唯一选项是 AllowCONNECT
,它用于转发 HTTPS 代理服务器。
即使the options in mod_proxy_balancer
也希望在配置的某个点有路径。它的文档没有提到 SSL/HTTPS(“它为 HTTP、FTP 和 AJP13 协议提供负载平衡支持”),而 mod_proxy
在提到 CONNECT
时至少谈到了 SSL。 p>
我会建议几个选项:
使用基于iptables
的负载均衡器,无需通过Httpd,直接结束Tomcat中的连接。
在 Httpd 结束 SSL/TLS 连接并使用普通的 HTTP 反向代理到 Tomcat。
第二个选项需要更多配置来处理客户端证书和 Tomcat 的安全约束。
如果您已使用<transport-guarantee>CONFIDENTIAL</transport-guarantee>
配置您的 web 应用程序,您将需要让 Tomcat 将连接标记为安全,尽管事实上它认为这些连接来自其纯 HTTP 端口。对于 Tomcat 5,here is an article(最初是法语,但自动翻译还不错)描述了如何实现一个阀门来设置isSecure()
。 (如果你不熟悉valves,它们类似于过滤器,但在请求传播到webapp之前在Tomcat本身内部运行。它们可以在Catalina中配置)我认为从Tomcat 5.5,HTTP connector secure
option完全可以做到这一点,而无需您自己的阀门。 AJP 连接器也有类似的选项(如果使用mod_proxy_ajp
或mod_jk
)。
如果使用 AJP 连接器,mod_proxy_ajp
将转发链中的第一个证书并使其在 Tomcat 中可用(通过正常的请求属性)。您可能需要SSLOptions +ExportCertData +StdEnvVars
。 mod_jk
(尽管据我所知已弃用)也可以转发客户端发送的整个链(使用JkOptions +ForwardSSLCertChain
)。这在使用 proxy certificates 时可能是必要的(如果没有链接到它们的最终实体证书,这将毫无意义)。
如果你想使用mod_proxy_http
,一个技巧是通过an HTTP header (mod_header
) 传递证书,使用类似RequestHeader set X-ClientCert %SSL_CLIENT_CERTs
的东西。我不记得确切的细节,但重要的是确保清除此标头,以便它永远不会来自客户端的浏览器(否则谁可以伪造它)。如果需要全链,可以试试this Httpd patch attempt。这种方法可能需要一个额外的阀门/过滤器来将标头转换为javax.servlet.request.X509Certificate
(通过解析 PEM 块)。
可能感兴趣的其他几点:
如果我没记错的话,您需要为 Httpd 和 configure it to use them 显式下载 CRL 文件。根据您使用的 Httpd 版本,您可能需要restart it to reload the CRLs。 如果您使用重新协商来获取您的客户端证书,据我所知,CLIENT-CERT
指令不会使 Httpd 请求客户端证书(否则,这是通过可以访问 @987654354 的阀门完成的@ 直接使用 JSSE 连接器时)。您可能需要在 Httpd 中配置匹配路径才能请求客户端证书。
【讨论】:
谢谢布鲁诺。听起来我应该(a)按照您的建议在 HTTPD 和 Tomcat 之间使用纯文本,将 HTTPD 作为客户端的 SSL 端点,(b)摆脱<transport-guarantee>CONFIDENTIAL</transport-guarantee>
,这不会打扰我,然后搜索并销毁@代码中的 987654356@ 和 (d) 使用 mod_proxy_ajp
以便证书通过,实际上我已经在这样做了。我可以为 HTTPS 和证书等配置 HTTPD。
目前我能看到的唯一主要问题是客户端证书。我已将 Tomcat 配置为不询问它们以避免浏览器弹出窗口,并且有一个 Tomcat 魔术可以为具有客户端证书身份验证的应用程序的客户端重新握手,如果它还没有证书。我必须弄清楚如果可能的话如何让 HTTPD 做到这一点,或者可能只是不将该应用程序放在集群中:无论如何它是一个低容量的应用程序。除此之外,我认为这看起来不错。
您可以将SSLVerifyClient none
全局和SSLVerifyClient optional/require
放在<Location /path/...>
元素中(但路径可能必须特定于webapp 的预期)。
谢谢,听起来像我需要的。 Tomcat 没有那个级别的粒度,这已经给我带来了另一个问题。
This 如果您想直接在 Tomcat 中执行此操作可能会有所帮助。好久没做这个了,具体细节记不太清了。我记得mod_jk
+Jetty/AJP 在某些时候在重负载下遇到了一些稳定性问题(实际上并没有那么重,但是对于突发的请求,大约 30 秒内有 200 个请求):AJP 连接会在没有任何内容的情况下断开日志(Httpd 或 Jetty)。让 Jetty(甚至 BIO)直接通过 JSSE 处理请求结果证明更稳定(我当时没有完全调查原因,您可能会得到更好的结果)。以上是关于带有客户端身份验证的 Apache HTTPD/mod_proxy/Tomcat 和 SSL的主要内容,如果未能解决你的问题,请参考以下文章
在 Apache Web 服务器上配置 2 路 SSL 客户端身份验证
如何使用带有 LDAP 身份验证的 Apache Shiro 添加角色授权