Apache反向代理背后的Keycloak
Posted
技术标签:
【中文标题】Apache反向代理背后的Keycloak【英文标题】:Keycloak behind apache reverse proxy 【发布时间】:2017-07-09 14:28:00 【问题描述】:我在谷歌上冲浪没有找到任何具体答案或示例,所以再次在这里试试运气(经常走运)。
问题
我有一个 Spring Boot RESTful 服务在 Apache 后面运行 反向代理。此 RESTful 服务仅运行 HTTP。说它正在运行 本地ip 172.s 8080端口。
我还配置了一个 apache 反向代理。说它正在运行 本地 ip 172.a 和公共 ip 55.a。此代理同时响应 80 端口,但所有 HTTP 流量都自动重定向到 443。
我有另一台服务器运行独立的 Keycloak 服务器。还 此服务器配置为可通过 反向代理。假设它在本地 ip 172.k 上运行。此 Keycloak 服务器仅在 HTTP 上运行。 HTTP 请求通过反向代理使用 SSL 进行处理。
最后,我在本地 ip 172.f 上运行了另一个前端 web 应用程序。这个 frontend-webapp 在 Nodejs 下运行,也是通过反向代理配置的。它也只运行 HTTP,但客户端(浏览器)通过反向代理使用 SSL,就像 Keycloak 和 RESTful 服务一样。此前端正在使用 RESTful 服务,并且还配置为使用 keycloak javascript 适配器进行身份验证。
RESTful 服务使用 Spring Boot Keycloak 适配器配置为仅承载,而前端应用程序配置为公共访问类型。
RESTful 服务服务器、Keycloak 服务器和前端服务器不可公开访问;它们只能通过反向代理访问。但是它们可以相互通信(因为它们在同一个专用网络中)。
在前端keycloak.json文件中,auth-server-url
设置为代理urlhttps://example.com/auth
,前端能够成功获取到有效token。现在,当我尝试使用 RESTful 服务时,我在 RESTful 适配器中收到一个错误,即令牌颁发者无效。当然,我在 http-header 中发送Authorization: Bearer <token>
。我收到此错误的原因是在 RESTful keycloak 配置中,我已将 auth-server-url
配置为使用本地 url http://172.k:9080/auth
,因此此 url 与令牌中的 URL 不同(即 https://example.com/auth
)。
问题
我不能在 RESTful 服务中包含与前端相同的 auth-server-url
,因为这将要求我还在 RESTful 服务上设置 HTTP(因为 url 是 https),这会使事情复杂化很多,包括需要设置证书和类似的东西。另外我认为在本地服务器上设置 SSL 效率低且不实用。
所以我的问题是如何让适配器在不通过反向代理的情况下与 Keycloak 对话。我希望 RESTful 适配器通过 auth-server-url: http://172.k:9080/auth
与 Keyclok 服务器通信以进行令牌验证。
之前有一个不同的后端网址,已被删除:https://issues.jboss.org/browse/KEYCLOAK-2623
【问题讨论】:
您是否尝试将 Web Origins 设置为 *.如果我是对的,我通过跨域访问遇到了同样的问题 是的,我尝试将 Web-origins 设置为 '*',但没有成功。 【参考方案1】:您需要告知 keycloak 反向代理的位置。然后在它的响应中它将位置设置到那里而不是它的本地地址。为此,在最新的 keycloak 中设置环境变量 KEYCLOAK_FRONTEND_URL
指向
字符串https://example.com/auth
(是的,它需要整个地址。
要完成这项工作,还要将 PROXY_ADDRESS_FORWARDING
设置为值 true
如果是 Docker 容器,则意味着:
environment:
...
PROXY_ADDRESS_FORWARDING: "true"
KEYCLOAK_FRONTEND_URL: "https://example.com/auth"
或者,您可以将KEYCLOAK_HOSTNAME
设置为example.com
,这将留下端口号,用于哪个???(不确定如何执行此部分,如果您发现请告诉我...) )
编辑:请注意,在某些情况下,您可能只想为特定客户端设置此项。在 keycloak 中配置每个客户端时,您可以从第一个选项选项卡中设置其 Frontend_URL。
【讨论】:
谢谢。我将 - KEYCLOAK_FRONTEND_URL=keycloak:8080/auth 放入我的 docker-compose.yml 中,它就像一个魅力! openid 端点配置现在看起来可以使用了。【参考方案2】:其中一种解决方案是将适配器升级到 8.0.0。这个问题似乎在 8.0.0 版本中得到修复。
已知问题KEYCLOAK-6073:
向 Java 适配器添加对 OpenID Connect Discovery 的支持... 适配器应支持对前端和后端请求使用不同的 URL。
【讨论】:
您好,请问可以提供样品吗?我很困惑如何使用新功能。谢谢!【参考方案3】:我在 docker swarm 环境中遇到过类似的问题。我的 Keycloak 和我的 Spring Boot 容器都在同一个反向代理之后。
对于 Tomcat: 问题是正确配置 http(s) 连接器。假设我们的反向代理的主机名和端口是 http://$EXTERNAL_HOSTNAME:$EXTERNAL_PORT。
那么 tomcat.xml 中的 http(s) 连接器应该有这两个附加属性:
<Connector [...] proxyName="$EXTERNAL_HOSTNAME" proxyPort="$EXTERNAL_PORT"/>
这将使所有对 servletRequest.getServerName() 和 servletRequest.getServerPort() 的调用都以我们的反向代理的值进行响应。 keycloak 适配器当然使用这些函数来确定重定向 url。
对于 Spring Boot:将这个类放到你的类路径中:
@Component
public class TomcatReverseProxyCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, TomcatConnectorCustomizer
@Value("$server.tomcat.proxy-name")
private String proxyName;
@Value("$server.tomcat.proxy-port")
private int proxyPort;
@Override
public void customize(final TomcatServletWebServerFactory factory)
factory.addConnectorCustomizers(this);
@Override
public void customize(final Connector connector)
connector.setProxyName(this.proxyName);
connector.setProxyPort(this.proxyPort);
然后在 application.properties 中设置:
server.tomcat.proxy-name=$EXTERNAL_HOSTNAME
server.tomcat.proxy-port=$EXTERNAL_PORT
keycloak 适配器的附加配置(以 Spring Boot 为例):
我的 keycloak 也在同一个反向代理后面。所以我还必须将 keycloak 适配器的身份验证服务器 url 设置为反向代理的主机名。然后我滥用 keycloak 适配器的代理设置,让它使用内部腿上的服务:
keycloak.auth-server-url=http://$EXTERNAL_HOSTNAME:$EXTERNAL_PORT/auth
keycloak.proxy-url=http://$INTERNAL_KEYCLOAK_HOSTNAME:$INTERNAL_KEYCLOAK_PORT/auth
这些设置也可能有意义:
server.servlet.session.cookie.domain=$EXTERNAL_HOSTNAME
server.use-forward-headers=true
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.protocol-header 对于那些在其反向代理上终止 SSL 的人来说很重要。
【讨论】:
【参考方案4】:我正在将 Keycloak 用于 docker 容器中的项目。我遇到了同样的问题,但在本地网络中(所以也许这不是解决方案,在这种情况下我很抱歉)。原来是这样的:
在 Wildfly 上运行的 REST java webapp,在单个 Docker 容器中 Keycloak 运行在与之前相同的网络中的单个 Docker 容器中Apache 在 Docker 外部的机器上本地运行,提供 angular 2 应用程序,配置正确
angular 2 应用程序的适配器指向 url http://aaa.auth.com(我使用条目 127.0.0.1 aaa.auth.com 修改了本地文件主机)
我通过主机名http://aaa.auth.com 在 Wildfly Docker 和 Keycloak Docker 之间添加了一个链接,并且我在 Java webapp 适配器中使用了这个主机名。 两个适配器都指向同一个地址,据我所知这是 Keycloak 要求,请参阅https://issues.jboss.org/browse/KEYCLOAK-2067与您的情况(Docker、HTTP 与 HTTPS 等)有很多不同,但是,为了避免通过 Web 通信 REST-Keycloak,您是否尝试过修改服务器的文件主机(托管 RESTful 服务)插入带有您的反向代理 (172.a) 和“example.com”的本地 IP 的条目?
或者,也许您可以使用私有 DNS 解决它?
【讨论】:
【参考方案5】:我尝试了不同的方法,但无法解决问题。对我来说,似乎没有办法在后端适配器中指定 auth-server-url: http://172.k:9080/auth
而前端适配器将 auth-server-url:https://example.com/auth
放入令牌中。所以我的解决方案是将所有后端服务也配置为auth-server-url: https://example.com/auth
。
唯一的缺点是我的后端服务适配器通过 web 与 keycloak 通信,这在性能方面可能不太好,但至少一切正常。应该可以在同一个本地网络或 AWS 中的同一个 *** 中以某种方式指定一个本地 keycloak 端点。
【讨论】:
致读者:如果您有其他解决方案,请务必提供答案,我很乐意接受我们的回答。 这太可悲了:( 数据或带宽很昂贵,因此通过公共网络是一个很大的浪费...... 我也在为此苦苦挣扎。我正在尝试将我的 keycloak-server 迁移到新的 URL,而后端位于同一 URL。我所有的手机应用程序都需要一些时间来更新并开始使用新的 URL。所以与此同时,我需要在我的后端适配器中接受这两个 URL。以上是关于Apache反向代理背后的Keycloak的主要内容,如果未能解决你的问题,请参考以下文章
Apache 反向代理背后的 Apache Zeppelin
keycloak + spring 适配器 +spring security 反向代理重定向到root