apache 反向代理背后的 Keycloak

Keycloak behind apache reverse proxy

我浏览了 google 但没有找到任何 具体 答案或 示例 ,所以再次在这里试试运气(通常走运吧)。

问题

无法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。