web-dev-qa-db-ja.com

Apacheリバースプロキシの背後にあるKeycloak

私はconcreteの答えやexamplesを見つけることなくグーグルをサーフィンしたのでここでもう一度私の運を試します(しばしば幸運になります)。

問題

  • Apacheリバースプロキシの背後で実行されている単一のスプリングブートRESTfulサービスがあります。このRESTfulサービスはHTTPのみを実行しています。ローカルIP172.sポート8080で実行されているとします。

  • Apacheリバースプロキシも設定しました。ローカルIP172.aとパブリックIP55.aで実行されているとします。このプロキシは両方のポート80に応答しますが、すべてのHTTPトラフィックは自動的に443にリダイレクトされます。

  • スタンドアロンのKeycloakサーバーを実行している別のサーバーがあります。また、このサーバーは、リバースプロキシを介してパブリックアクセスできるように構成されています。ローカルIP172.kで実行されているとします。このKeycloakサーバーはHTTPのみで実行されています。 HTTPリクエストは、リバースプロキシ経由でSSLを使用して処理されます。

  • 最後に、ローカルIP172.fで実行されている別のフロントエンドwebappがあります。このfrontend-webappはNodejsで実行されており、リバースプロキシを介して構成されています。また、HTTPのみを実行していますが、クライアント(ブラウザー)は、KeycloakおよびRESTfulサービスの場合と同様に、リバースプロキシを介してSSLを使用しています。このフロントエンドはRESTfulサービスを使用しており、keycloakjavascriptアダプターを使用して認証するようにも構成されています。

  • RESTfulサービスは、Spring Boot Keycloakアダプターを使用してベアラーのみとして構成されますが、フロントエンドアプリはアクセスタイプpublicで構成されます。

RESTfulサービスサーバー、Keycloakサーバー、およびフロントエンドサーバーはパブリックアクセスできません。それらはリバースプロキシを介してのみアクセス可能です。ただし、それらは互いに通信できます(同じプライベートネットワーク内にあるため)。

フロントエンドのkeycloak.jsonファイルでは、auth-server-urlがプロキシURLhttps://example.com/authに設定されており、フロントエンドは有効なトークンを正常に取得できます。これで、RESTfulサービスを利用しようとすると、トークン発行者が無効であるというエラーがRESTfulアダプターで発生します。もちろん、http-headerではAuthorization: Bearer <token>を送信しています。このエラーが発生する理由は、RESTfulキークローク構成で、ローカルURL auth-server-urlを使用するようにhttp://172.k:9080/authを構成したため、このURLがトークン内のURL(https://example.com/auth)と異なるためです。

質問

フロントエンドと同じauth-server-urlをRESTfulサービスに含めることはできません。RESTfulサービスでHTTPSも設定する必要があり(URLがhttpsであるため)、証明書を設定する必要があるなど、非常に複雑になります。そしてそのようなもの。また、ローカルのみのサーバーでSSLを設定するのは非効率的で実用的ではないと思います。

だから私の質問は、リバースプロキシを経由せずにアダプタがKeycloakと通信できるようにする方法です。 RESTfulアダプターがauth-server-url: http://172.k:9080/authを介したトークン検証のためにKeyclokサーバーと通信するようにしたい。

以前はバックエンドに別のURLがあり、削除されました: https://issues.jboss.org/browse/KEYCLOAK-262

9
Gogi

別のことを試しましたが、問題を解決できませんでした。私には、フロントエンドアダプタがトークンに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内の同じVPN内でローカルキークロークエンドポイントを何らかの方法で指定することが可能であったはずです。

2
Gogi

DockerコンテナのプロジェクトにKeycloakを使用しています。私は同じ問題を抱えていましたが、ローカルネットワークで発生しました(したがって、これは解決策ではない可能性があります。この場合は申し訳ありません)。だからこれは状況でした:

  • REST Java webappがwildflyで実行され、単一のDockerコンテナ
  • 以前の同じネットワーク内の単一のDockerコンテナで実行されているKeycloak
  • Dockerの外部の私のマシンでローカルに実行されているApacheは、適切に構成されたangular 2アプリを提供します

  • angular 2アプリのアダプターがURLを指していました http://aaa.auth.com (ローカルファイルホストをエントリ127.0.0.1aaa.authで変更しました.com)

  • ホスト名 http://aaa.auth.com でWildflyDockerとKeycloakDockerの間にリンクを追加し、このホスト名をJava webappアダプターで使用しました。
  • これがKeycloakの要件であることがわかっている限り、両方のアダプターが同じアドレスを指していました。 https://issues.jboss.org/browse/KEYCLOAK-2067 を参照してください。

あなたの場合(Docker、HTTP対HTTPSなど)とは多くの違いがありますが、Web経由のREST-Keycloakの通信を避けるために、サーバーのファイルホスト(RESTfulサービスをホストする)を変更して、エントリを挿入してみましたか?リバースプロキシ(172.a)と「example.com」のローカルIP?

または、プライベートDNSで解決できるかもしれません。

4
Reste85

DockerSwarm環境でも同様の問題が発生しました。 KeycloakとSpringBootコンテナは、どちらも同じリバースプロキシの背後にありました。

Tomcatの場合:問題はhttp(s)コネクタを正しく設定することです。リバースプロキシのホスト名とポートがhttp:// $ {EXTERNAL_HOSTNAME}:$ {EXTERNAL_PORT}であるとしましょう。

次に、Tomcat.xmlのhttp(s)コネクタには、次の2つの追加属性が必要です。

<Connector [...] proxyName="${EXTERNAL_HOSTNAME}" proxyPort="${EXTERNAL_PORT}"/>

これにより、servletRequest.getServerName()およびservletRequest.getServerPort()へのすべての呼び出しがリバースプロキシの値で応答します。キークロークアダプタは確かにこれらの関数を使用してリダイレクト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アダプターの認証サーバーの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を終了するユーザーにとって重要です。

2
Asinus

解決策の1つは、アダプターを8.0.0にアップグレードすることです。この問題はバージョン8.0.0で修正されているようです。

https://issues.redhat.com/browse/KEYCLOAK-607

0
Kohei TAMURA