🚪

API Gateway KongのOSS版管理画面(Kong Manager)をSSL化+Basic認証で外部からアクセス

2023/09/20に公開

TL;DR

  • Kong外のnginxでSSL化+Basic認証
  • Kong側も同一ホスト名でSSL化しておく
  • Kong外nginx→Kong Managerへはホスト名でフォワーディング

背景

  • Kongを外部からGUIで操作したい
  • Kong Managerへは認証をかけたい
  • オンプレでBasic以外のwebサイト認証の仕組みを独自に構築するのはハードルが高い
  • ホスト環境を汚さないために全部Dockerで完結させたい

完成形イメージ

事前準備:Basic認証用.htpasswd作成

コマンド履歴にパスワードは残したくないので、環境変数にパスワードを指定しコンテナに渡して.httpasswdファイル作成

.passenv
HTPASSWD=Basic認証のパスワード
source ./.passenv && \
docker run \
--rm -it httpd:2.4.57-bookworm \
htpasswd -nb Basic認証のログインユーザー名 $HTPASSWD >> ./.htpasswd
./.htpasswd
Basic認証のパスワード:エンコード済パスワード

docker-compose用のKong・nginx共通.env作成

以下のような.envファイルを作成しておく。

.env
POSTGERS_DB=データベース名
POSTGERS_USER=データベースのログインユーザー名
POSTGERS_PASSWORD=データベースのログインパスワード
DB_DIR=データベースのデータ保存先ディレクトリ
CERTS_DIR=サーバー証明書のあるディレクトリ
KONG_HOST=外部公開用ホスト名
API_SSL_PORT=SSL接続API用ポート
ADMIN_SSL_PORT=管理機能SSL通信用ポート
ADMIN_GUI_SSL_PORT_INTERNAL=管理画面SSL通信用のコンテナ内部ポート
ADMIN_GUI_SSL_PORT_EXPOSE=管理画面SSL通信用の外部nginx向けホスト側ポート

NGINX_CONF_TMPL_PATH=Kong向け外部nginxの設定ファイルテンプレートのパス
HTPASSWD_PATH=.htpasswdファイルのパス
NGINX_INTERNAL_ADMIN_GUI_PORT=Kong向け外部nginxの、管理画面SSL通信用の内部ポート番号

サーバー証明書ディレクトリに 公開鍵:fullchain.pem、秘密鍵:privkey.pemを配置しておく。
また、外部からのアクセスの場合ADMIN_SSL_PORTで指定したポートの通信も一旦外に出るようなので、ポートを公開しておく必要がある。

Basic認証を有効にするnginx設定テンプレート作成

kong.conf.template
server {
    listen      ${NGINX_INTERNAL_KONG_GUI_PORT} ssl;
    server_name ${KONG_HOST};

    ssl_certificate /certs/fullchain.pem;
    ssl_certificate_key /certs/privkey.pem;

    location / {
        auth_basic "Login required";
        auth_basic_user_file /auth/.htpasswd;
        set $redirect_to https://172.17.0.1:${KONG_GUI_PORT_EXPOSE};

        set $internal_host $server_name:${KONG_GUI_PORT_INTERNAL};
        add_header Reqested-Host $remote_addr;
        proxy_redirect   off;
        proxy_pass $redirect_to;
        proxy_set_header Host               $internal_host;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host   $internal_host;
        proxy_set_header X-Forwarded-Server $internal_host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-Proto  https;
    }
}

Kong+nginx起動

docker-compose.yml
version: '3'

services:
  kong-migrations:
    image: kong:3.4.0-ubuntu
    command: kong migrations bootstrap
    environment:
      KONG_DATABASE: postgres
      KONG_PG_DATABASE: ${POSTGERS_DB}
      KONG_PG_HOST: db
      KONG_PG_USER: ${POSTGERS_USER}
      KONG_PG_PASSWORD: ${POSTGERS_PASSWORD}
    depends_on:
      - db
    deploy:
      restart_policy:
        condition: on-failure

  kong:
    image: kong:3.4.0-ubuntu
    restart: always
    environment:
      KONG_DATABASE: postgres
      KONG_PG_HOST: db
      KONG_PG_USER: ${POSTGERS_USER}
      KONG_PG_PASSWORD: ${POSTGERS_PASSWORD}
      KONG_REAL_IP_HEADER: X-Forwarded-For
      KONG_PROXY_LISTEN: 0.0.0.0:${API_SSL_PORT} ssl
      KONG_SSL_CERT: /certs/fullchain.pem
      KONG_SSL_CERT_KEY: /certs/privkey.pem
      KONG_ADMIN_LISTEN: 0.0.0.0:${ADMIN_SSL_PORT} ssl
      KONG_ADMIN_SSL_CERT: /certs/fullchain.pem
      KONG_ADMIN_SSL_CERT_KEY: /certs/privkey.pem
      KONG_ADMIN_GUI_LISTEN: 0.0.0.0:${ADMIN_GUI_SSL_PORT_INTERNAL} ssl
      KONG_ADMIN_GUI_URL: https://${KONG_HOST}:${ADMIN_GUI_SSL_PORT_INTERNAL}
      KONG_ADMIN_GUI_PATH: /
      KONG_ADMIN_GUI_SSL_CERT: /certs/fullchain.pem
      KONG_ADMIN_GUI_SSL_CERT_KEY: /certs/privkey.pem
    extra_hosts:
      - "${KONG_HOST}:172.17.0.1"
    ports:
      - ${API_SSL_PORT}:${API_SSL_PORT}
      - ${ADMIN_SSL_PORT}:${ADMIN_SSL_PORT}
      - ${ADMIN_GUI_SSL_PORT_EXPOSE}:${ADMIN_GUI_SSL_PORT_INTERNAL}
    volumes:
      - ${CERTS_DIR}:/certs
    depends_on:
      - db
    links:
      - db

  db:
    image: postgres:12.16-bookworm
    restart: always
    environment:
      POSTGRES_DB: ${POSTGERS_DB}
      POSTGRES_USER: ${POSTGERS_USER}
      POSTGRES_PASSWORD: ${POSTGERS_PASSWORD}
    volumes:
      - ${DB_DIR}:/var/lib/postgresql/data

  nginx:
    image: nginx:1.25.2-alpine3.18-slim
    restart: always
    command: /bin/sh -c "envsubst \
      '$$KONG_HOST $$KONG_GUI_PORT_INTERNAL $$KONG_GUI_PORT_EXPOSE \
      $$NGINX_INTERNAL_KONG_GUI_PORT\
      ' < /templates/kong.conf.template > /etc/nginx/conf.d/kong.conf; nginx -g 'daemon off;'"
    environment:
      KONG_HOST: ${KONG_HOST}
      KONG_GUI_PORT_INTERNAL: ${ADMIN_GUI_SSL_PORT_INTERNAL}
      KONG_GUI_PORT_EXPOSE: ${ADMIN_GUI_SSL_PORT_EXPOSE}
      NGINX_INTERNAL_KONG_GUI_PORT: ${NGINX_INTERNAL_ADMIN_GUI_PORT}
    ports:
      - ${ADMIN_GUI_SSL_PORT_INTERNAL}:${NGINX_INTERNAL_ADMIN_GUI_PORT}
    volumes:
      - ${NGINX_CONF_TMPL_PATH}:/templates/kong.conf.template
      - ${CERTS_DIR}:/certs
      - ${HTPASSWD_PATH}:/auth/.htpasswd
    depends_on:
      - kong
command
docker compose up -d

Kong Manager(OSS版)にアクセス

データベースのマイグレーションが完了後、https://KONG_HOSTのホスト名:ADMIN_GUI_SSL_PORT_INTERNALのポート番号にアクセスする。
※同一LAN内からアクセスする場合は以下参照。

ログインが求められる。

作成した.htpasswdのアカウントでログインすればKong Managerにアクセスできる。

Enterprise版とはデザインが異なる模様。

管理機能の通信がうまくできていないと「Gateway Services could not be retrieved
Data cannot be displayed due to an error.」といったエラーが出る。

この場合、エラー分類の詳細までは出してくれないので原因は地道に手当たり次第で調査していくしかない。
例えばポート番号やホスト名、証明書、名前解決などが正しく設定されているかを確認する。

なお、管理画面と管理機能で別ホスト名+別ホスト名用証明書を用いた場合でも上記エラーが出るので、おそらく外部公開と内部処理でホスト名は統一しなければならない模様。詳細不明。

参考

  • Docker版Kong

Discussion