Docker

Docker Swarm上のWebサービスでIPアクセス制限が効かない原因について

Docker Swarm環境においてクライアントIPを参照したいときの注意点。
例えばnginxサービスとかでリバースプロキシ側で特定のクライアントIPを除いてBasic認証を掛けたいのにうまくいかない場合など。

スポンサーリンク

nginxで特定IPを除いてBasic認証を掛ける場合

例としてHTTPポート(80/443)をフォワードしているnginxサービスがあるとします。
そこで単純に以下のような設定でBasic認証掛けようとすると、指定したIPからのアクセスに対する認証スルーが効きいてくれません。

satisfy any;

# 認証スルーさせたいリモートIPアドレス
allow XXX.XXX.XXX.XXX;

deny all;
auth_basic "basic authentication";
auth_basic_user_file /run/secrets/nginx-proxy-htpasswd;

include /etc/nginx/network_internal.conf;

リモートIPの参照がうまくいかない理由

なぜ設定がうまく動作していないかというとSwarmモードでは、ポートフォワードするとingressルーティング・メッシュという、いわばロードバランサを経由してアクセスを受けるためです。
なので単純にリモートIPを拾おうとすると本来のクライアントIPではなく、そのロードバランサのIPを参照することとなります。

swarm モード・ルーティング・メッシュを使う — Docker-docs-ja 24.0 ドキュメント

AWSのALBなどではX-Forwarded-Forヘッダを付加してくれるので、そちらを参照すれば良いのですが、
残念ながらingressルーティング・メッシュはこのような機能を備えていないようです。

ルーティング・メッシュを迂回する

これを回避する方法としては、単純なものとして上記のドキュメントにもあるとおりルーティング・メッシュの迂回をする必要があります。
サービスのportsの設定を詳細にして、mode: hostにしましょう。
以下はcomposeファイルの書き方例の抜粋です。

ports:
  - published: 443
    target: 443
    protocol: tcp
    mode: host

これでホストPCのネットワークに直接フォワードされるようになるので、クライアントIPが正しく判別することが可能になります。
ただし、同時にルーティング・メッシュによるノードを跨いだロードバランシングは効かなくなります。

他の解決方法

docker-ingress-routing-daemonというデーモンを使うという手もあるようです。

GitHub - newsnowlabs/docker-ingress-routing-daemon: Docker swarm daemon that modifies ingress mesh routing to expose true client IPs to service containers
Docker swarm daemon that modifies ingress mesh routing to expose true client IPs to service containers - newsnowlabs/doc...

こちらは真のクライアントIPがDocker Swarm配下のサービスに伝達されるようになるものらしく、
ルーティング・メッシュの利点を生かしたまま目的を果たせそうです。
ただし、こちらはDockerよりも上位のレイヤーに導入が必要となるため、導入はやや面倒かもしれませんね。

以上。

スポンサーリンク
記事を書いた人

システムえんじにゃー🐈
趣味はエレキギター、自転車など。作曲したい。
World of Warshipsやってます。
記事に関する質問はお気軽にどうぞ。

surface0 (さーふぇす)をフォローする

コメント

タイトルとURLをコピーしました