apache 反向代理背后的 Keycloak
Keycloak behind apache reverse proxy
我浏览了 google 但没有找到任何 具体 答案或 示例 ,所以再次在这里试试运气(通常走运吧)。
问题
我在 apache 后面有一个 spring 引导 RESTful 服务 运行
反向代理。此 RESTful 服务仅 运行 HTTP。假设它是 运行
本地 ip 172.s 端口 8080.
我还配置了一个apache反向代理。假设它是 运行
本地 ip 172.a 和 public ip 55.a。此代理响应两个端口 80,但所有 HTTP 流量都自动重定向到 443。
我有另一台服务器 运行 一个独立的 Keycloak 服务器。还
此服务器配置为 public 可通过
反向代理。假设它是本地 ip 172.k 上的 运行。此 Keycloak 服务器 运行 仅支持 HTTP。 HTTP 请求通过反向代理使用 SSL 处理。
最后,我在本地 ip 172.f 上还有另一个前端网络应用程序 运行。这个frontend-webapp是Nodejs下的运行,也是通过反向代理配置的。它也是 运行 仅 HTTP,但客户端(浏览器)正在通过反向代理使用 SSL,就像 Keycloak 和 RESTful 服务一样。此前端正在使用 RESTful 服务,并且还配置为使用 keycloak javascript 适配器进行身份验证。
RESTful 服务使用 Spring Boot Keycloak 适配器配置为仅承载,而前端应用程序配置为访问类型 public。
无法public访问RESTful服务服务器、Keycloak服务器和前端服务器;它们只能通过反向代理访问。但是他们可以相互通信(因为他们在同一个专用网络中)。
在前端keycloak.json文件中,auth-server-url
设置为代理urlhttps://example.com/auth
,前端能够成功获取有效令牌。现在,当我尝试使用 RESTful 服务时,我在 RESTful 适配器中收到错误消息,指出令牌颁发者无效。在 http-header 中,我当然发送 Authorization: Bearer <token>
。我收到此错误的原因是在 RESTful keycloak 配置中,我已将 auth-server-url
配置为使用本地 url http://172.k:9080/auth
,因此此 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 服务器通信以进行令牌验证
之前有一个不同的后端 url,已删除:https://issues.jboss.org/browse/KEYCLOAK-2623
我尝试了不同的方法,但无法解决问题。在我看来,当前端适配器将 auth-server-url:https://example.com/auth
放入令牌时,似乎无法在后端适配器中指定 auth-server-url: http://172.k:9080/auth
。所以我的解决方案是将所有后端服务也配置为 auth-server-url: https://example.com/auth
。
唯一的缺点是我的后端服务适配器通过网络与 keycloak 通信,这在性能方面可能不是很好,但至少一切正常。应该可以在同一本地网络或 AWS 中的同一 VPN 中以某种方式指定本地密钥斗篷端点。
我正在为 docker 容器中的项目使用 Keycloak。我有同样的问题,但在本地网络中(所以这可能不是解决方案,在这种情况下我很抱歉)。原来是这样:
- REST java webapp 运行 在 wildfly 上,在单个 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 之间添加了一个 link 并且我在 Java webapp 适配器中使用了这个主机名。
- 两个适配器都指向同一个地址,据我所知这是 Keycloak 的要求,请参阅 https://issues.jboss.org/browse/KEYCLOAK-2067
与您的情况有很多不同(Docker、HTTP 与 HTTPS 等),但是,为了避免通过 Web 进行 REST-Keycloak 通信,您是否尝试过修改服务器的文件主机(托管 RESTful 服务)插入一个条目,其中包含反向代理的本地 IP (172.a) 和 "example.com"?
或者,也许您可以使用私有 DNS 来解决它?
我在 docker 集群环境中遇到过类似的问题。我的 Keycloak 和我的 spring 启动容器都在同一个反向代理后面。
对于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 引导:将此 class 放到您的 class 路径中:
@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 启动):
我的密钥斗篷也在同一个反向代理后面。所以我还必须将 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 的人来说很重要。
其中一个解决方案是将适配器升级到 8.0.0。此问题似乎已在 8.0.0 版本中修复。
这是已知问题KEYCLOAK-6073:
Add support for OpenID Connect Discovery to Java adapters...
Adapters should support using different URLs for frontend and backend requests.
您需要将反向代理的位置告知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。
我浏览了 google 但没有找到任何 具体 答案或 示例 ,所以再次在这里试试运气(通常走运吧)。
问题
我在 apache 后面有一个 spring 引导 RESTful 服务 运行 反向代理。此 RESTful 服务仅 运行 HTTP。假设它是 运行 本地 ip 172.s 端口 8080.
我还配置了一个apache反向代理。假设它是 运行 本地 ip 172.a 和 public ip 55.a。此代理响应两个端口 80,但所有 HTTP 流量都自动重定向到 443。
我有另一台服务器 运行 一个独立的 Keycloak 服务器。还 此服务器配置为 public 可通过 反向代理。假设它是本地 ip 172.k 上的 运行。此 Keycloak 服务器 运行 仅支持 HTTP。 HTTP 请求通过反向代理使用 SSL 处理。
最后,我在本地 ip 172.f 上还有另一个前端网络应用程序 运行。这个frontend-webapp是Nodejs下的运行,也是通过反向代理配置的。它也是 运行 仅 HTTP,但客户端(浏览器)正在通过反向代理使用 SSL,就像 Keycloak 和 RESTful 服务一样。此前端正在使用 RESTful 服务,并且还配置为使用 keycloak javascript 适配器进行身份验证。
RESTful 服务使用 Spring Boot Keycloak 适配器配置为仅承载,而前端应用程序配置为访问类型 public。
无法public访问RESTful服务服务器、Keycloak服务器和前端服务器;它们只能通过反向代理访问。但是他们可以相互通信(因为他们在同一个专用网络中)。
在前端keycloak.json文件中,auth-server-url
设置为代理urlhttps://example.com/auth
,前端能够成功获取有效令牌。现在,当我尝试使用 RESTful 服务时,我在 RESTful 适配器中收到错误消息,指出令牌颁发者无效。在 http-header 中,我当然发送 Authorization: Bearer <token>
。我收到此错误的原因是在 RESTful keycloak 配置中,我已将 auth-server-url
配置为使用本地 url http://172.k:9080/auth
,因此此 url 是与令牌中的不同(https://example.com/auth
)。
问题
我不能在 RESTful 服务中包含与前端相同的 auth-server-url
,因为这将要求我在 RESTful 服务上也设置 HTTP(因为 url 是 https),这会使事情复杂化很多,包括需要设置证书和类似的东西。此外,我认为仅在本地服务器上设置 SSL 效率低下且不切实际。
所以我的问题是如何让适配器在不通过反向代理的情况下与 Keycloak 通信。我希望 RESTful 适配器通过 auth-server-url: http://172.k:9080/auth
.
之前有一个不同的后端 url,已删除:https://issues.jboss.org/browse/KEYCLOAK-2623
我尝试了不同的方法,但无法解决问题。在我看来,当前端适配器将 auth-server-url:https://example.com/auth
放入令牌时,似乎无法在后端适配器中指定 auth-server-url: http://172.k:9080/auth
。所以我的解决方案是将所有后端服务也配置为 auth-server-url: https://example.com/auth
。
唯一的缺点是我的后端服务适配器通过网络与 keycloak 通信,这在性能方面可能不是很好,但至少一切正常。应该可以在同一本地网络或 AWS 中的同一 VPN 中以某种方式指定本地密钥斗篷端点。
我正在为 docker 容器中的项目使用 Keycloak。我有同样的问题,但在本地网络中(所以这可能不是解决方案,在这种情况下我很抱歉)。原来是这样:
- REST java webapp 运行 在 wildfly 上,在单个 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 之间添加了一个 link 并且我在 Java webapp 适配器中使用了这个主机名。
- 两个适配器都指向同一个地址,据我所知这是 Keycloak 的要求,请参阅 https://issues.jboss.org/browse/KEYCLOAK-2067
与您的情况有很多不同(Docker、HTTP 与 HTTPS 等),但是,为了避免通过 Web 进行 REST-Keycloak 通信,您是否尝试过修改服务器的文件主机(托管 RESTful 服务)插入一个条目,其中包含反向代理的本地 IP (172.a) 和 "example.com"?
或者,也许您可以使用私有 DNS 来解决它?
我在 docker 集群环境中遇到过类似的问题。我的 Keycloak 和我的 spring 启动容器都在同一个反向代理后面。
对于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 引导:将此 class 放到您的 class 路径中:
@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 启动):
我的密钥斗篷也在同一个反向代理后面。所以我还必须将 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 的人来说很重要。
其中一个解决方案是将适配器升级到 8.0.0。此问题似乎已在 8.0.0 版本中修复。
这是已知问题KEYCLOAK-6073:
Add support for OpenID Connect Discovery to Java adapters... Adapters should support using different URLs for frontend and backend requests.
您需要将反向代理的位置告知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。