Docker上でKeycloakを構築:SSO、2FA、OpenLDAP同期を備えた統合IAM基盤の実装

インフラ拡大に伴うアイデンティティ管理の課題

45名のエンジニアチームが、12個もの社内Webアプリケーションで認証情報を個別に管理している状況を想像してみてください。Jenkinsのダッシュボード、社内Wiki、Grafanaのモニタリング画面、ステージング環境のクラスタなど、あらゆるツールがサイロ化した独立したユーザーデータベースを抱えています。

エンジニアの新規オンボーディングでは、5〜6つの管理コンソールで手動アカウント作成が必要になり、採用ごとにDevOpsエンジニアの時間を1時間も奪ってしまいます。さらに深刻なのがオフボーディングです。金曜日の午後にエンジニアが退職した際、各独立システムのアカウントを手作業で削除していては、アクティブなセッショントークンや孤立したアカウントが見落とされ、深刻なセキュリティリスクに晒されることになります。

当然ながら、メンバーはパスワード疲れに陥ります。各環境で10文字程度の脆弱なパスワードを使い回したり、暗号化されていない共有テキストファイルに認証情報を保存し始めたりします。統合されたIdentity and Access Management(IAM)層が存在しないと、監査ログは散乱し、ワンクリックでのセッション破棄もできず、日常的に使用するツール間でセキュリティ基準が著しく不揃いになってしまいます。

IAMの基本概念:レルム(Realm)、フェデレーション、シングルサインオン(SSO)

コンテナを立ち上げる前に、後々のトラブルシューティングを省くための4つの基礎概念を押さえておきましょう。

  • Keycloakレルム(Realm): ユーザー、認証情報、ロール、連携アプリケーションを包含する独立したセキュリティドメインです。デフォルトのmasterレルムは管理者用コントロールプレーンとしてのみ機能します。社内スタッフや日々の業務サービス向けには、必ず別のレルム(例:internal-corp)を新規作成してください。
  • OpenID Connect(OIDC)& SAML: Keycloakは最新のIDプロトコルを仲介します。多くのWebプラットフォームは、OAuth 2.0をベースにRS256署名付きJWTトークンを利用するOIDCを介してKeycloakと連携するため、アプリケーション側が生のパスワードを保持・処理することはありません。
  • ユーザーフェデレーション(User Federation / LDAP): 重複したデータベースを並行運用する代わりに、KeycloakはOpenLDAPやActive Directoryなどの外部ディレクトリサービスに直接バインドします。ユーザーツリーを読み取り、LDAPバインドリクエストで認証情報を検証し、プロファイルメタデータをローカルにキャッシュします。
  • 多要素認証(MFA / 2FA): Keycloakは標準規格RFC 6238のTime-based One-Time Password(TOTP)に対応しています。ユーザーはGoogle AuthenticatorやFreeOTPなどのアプリでQRコードをスキャンするだけで設定でき、有料のSMSゲートウェイを導入する必要はありません。

ハンズオン実践:Keycloak、PostgreSQL、OpenLDAPの環境構築

ステップ1:Docker Composeによるインフラ構成の定義

KeycloakはQuarkusランタイム上で動作し、メタデータの保存先としてPostgreSQLとスムーズに統合できます。Keycloakと併せて、アイデンティティ情報を保管するOpenLDAPと、スキーマ管理用の軽量WebクライアントであるphpLDAPadminも同時に起動します。

32文字以上の高エントロピーなデータベース用および管理者用パスワードを生成する場合、toolcraft.app/ja/tools/security/password-generator のクライアントサイドジェネレーターが便利です。ネットワーク経由でキーを送信せず、ブラウザメモリ上でローカルにエントロピーを計算して安全に生成できます。

以下の設定を docker-compose.yml として保存します。

version: '3.8'

networks:
  iam-network:
    driver: bridge

volumes:
  postgres_data:
  ldap_data:
  ldap_config:

services:
  postgres:
    image: postgres:15-alpine
    container_name: keycloak-db
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak_admin
      POSTGRES_PASSWORD: ReplaceWithAStrongSecretDbPass123!
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - iam-network
    restart: unless-stopped

  openldap:
    image: osixia/openldap:1.5.0
    container_name: openldap
    environment:
      LDAP_ORGANISATION: "Example Corp"
      LDAP_DOMAIN: "example.com"
      LDAP_ADMIN_PASSWORD: ReplaceWithLdapAdminPass123!
    volumes:
      - ldap_data:/var/lib/ldap
      - ldap_config:/etc/ldap/slapd.d
    networks:
      - iam-network
    restart: unless-stopped

  phpldapadmin:
    image: osixia/phpldapadmin:0.9.0
    container_name: phpldapadmin
    environment:
      PHPLDAPADMIN_LDAP_HOSTS: openldap
      PHPLDAPADMIN_HTTPS: "false"
    ports:
      - "8080:80"
    networks:
      - iam-network
    depends_on:
      - openldap
    restart: unless-stopped

  keycloak:
    image: quay.io/keycloak/keycloak:24.0.1
    container_name: keycloak-server
    command: start-dev
    environment:
      KC_DB: postgres
      KC_DB_URL_HOST: postgres
      KC_DB_URL_PORT: 5432
      KC_DB_URL_DATABASE: keycloak
      KC_DB_USERNAME: keycloak_admin
      KC_DB_PASSWORD: ReplaceWithAStrongSecretDbPass123!
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: ReplaceWithAdminConsolePass123!
    ports:
      - "8081:8080"
    networks:
      - iam-network
    depends_on:
      - postgres
    restart: unless-stopped

バックグラウンドで環境を起動します。

docker compose up -d
docker compose logs -f keycloak

ログを確認します。およそ15〜20秒でKeycloakに Running the server in development mode. Started... と出力されます。これで http://localhost:8081 からKeycloakへ、http://localhost:8080 からphpLDAPadminへアクセスできるようになります。

ステップ2:OpenLDAPにテストユーザーを登録

ブラウザで http://localhost:8080 を開きます。管理者DN cn=admin,dc=example,dc=com と設定した LDAP_ADMIN_PASSWORD でサインインします。users という名前の構造的組織単位(OU)を作成し、ou=users,dc=example,dc=com 配下にテストアカウントを追加します。

  • 名(givenName): Alex
  • 姓(sn): Mercer
  • ユーザー名(uid): amercer
  • メールアドレス(mail): [email protected]
  • パスワード(userPassword): TemporaryPass987!

ステップ3:ユーザーフェデレーションでKeycloakとOpenLDAPを連携

  1. http://localhost:8081 のKeycloak管理コンソールに KEYCLOAK_ADMIN の認証情報でログインします。
  2. 左上のレルムセレクターをクリックし、Create Realm を選択して、レルム名を internal-corp と入力します。
  3. 左側のサイドバーで User federation を開き、Add LDAP providers を選択します。
  4. 接続パラメータを設定します:
    • UI display name: Company-OpenLDAP
    • Vendor: Other
    • Connection URL: ldap://openldap:389
    • Users DN: ou=users,dc=example,dc=com
    • Authentication type: simple
    • Bind DN: cn=admin,dc=example,dc=com
    • Bind credential: ReplaceWithLdapAdminPass123!
    • Username LDAP attribute: uid
    • RDN LDAP attribute: uid
    • UUID LDAP attribute: entryUUID
    • User object classes: inetOrgPerson, organizationalPerson, person
    • Edit mode: READ_ONLY(LDAPを信頼できる単一の情報源として維持する場合は読み取り専用のままにし、ユーザーによるパスワード変更をディレクトリ側へ書き戻したい場合は WRITABLE に切り替えます)
  5. Test connection、続けて Test authentication をクリックします。両方で緑色の成功バッジが表示されたら、Save をクリックします。
  6. 下部の Sync settings ペインまでスクロールし、Sync all users をクリックします。Keycloakの Users タブを確認すると、ディレクトリのメールアドレスやプロファイル情報を保持した状態で amercer が即座に表示されます。

ステップ4:二要素認証(TOTP)ポリシーの強制適用

LDAPからユーザー情報が連携されたら、連携先ツール全体に2FAを必須化する設定は2分もかからずに完了します。

  1. internal-corp レルム内で、Authentication > Required actions をクリックします。
  2. Configure OTP を見つけ、Set as default action を有効化します。これにより、認証アプリの登録を行っていないすべてのアカウントに対し、次回の初回ログイン時に設定が義務付けられます。
  3. Authentication > Policies > OTP Policy に移動します。ハッシュアルゴリズムをSHA-256、標準的な6桁コード、有効時間(トークンウィンドウ)30秒に設定することをおすすめします。

さっそくこのフローをテストしてみましょう。http://localhost:8081/realms/internal-corp/account/ にアクセスし、amercer としてサインインします。KeycloakはOpenLDAPに対してパスワードを検証した後、直ちにセッションの進行を停止し、登録用QRコードを表示します。ユーザーは最初の6桁コードを検証するまで、連携ツールにアクセスすることはできません。

現場での運用ノウハウとアーキテクチャの知見

高トラフィックな本番環境でコンテナ化されたKeycloakを運用してきた経験から、特に重要となる3つの運用ルールがあります。

  • start-dev はローカル開発環境のみにとどめる: start-dev フラグは重要なTLS検証を無効化し、平文のHTTPに直接バインドします。ステージングや本番環境では、マルチステージDockerfileを用意し、PostgreSQLドライバーを事前キャッシュした上で kc.sh build を実行してビルドします。そして、443ポートでTLS終端を処理するリバースプロキシ(TraefikやNGINXなど)の背後に配置し、kc.sh start --optimized でコンテナを起動してください。
  • アクセストークンの有効期限は短く保つ: アクセストークンの有効期間は5分程度が最適です。トークン更新のハンドシェイクを避けるためだけにアクセストークンを8時間に延ばすような運用は避けてください。ベアラートークンが漏洩した際に管理上の悪夢を招くことになります。5分程度の短いアクセストークンと12時間程度の長めのリフレッシュトークンを組み合わせ、Revoke Refresh Token を有効にして交換のたびにリフレッシュトークンをローテーションさせましょう。
  • バックグラウンド同期ジョブを自動化する: READ_ONLY のLDAP構成では、新規追加されたメンバーがログインするか手動同期を実行するまで、Keycloakの検索一覧に反映されません。これを防ぐため、Periodic Full Sync(86,400秒=24時間ごと)と Periodic Changed Users Sync(300秒=5分ごと)を有効化してください。これにより、新しく追加されたLDAPグループやメンバー変更が手作業ゼロでKeycloakのロールマッピングに反映されます。

Docker上でKeycloakとOpenLDAPを組み合わせることで、堅牢で実績のあるIAMアーキテクチャが完成します。アプリケーションはOIDCを通じて認証を委譲し、システム管理者はクリーンで一元管理されたディレクトリを維持でき、運用中のあらゆる社内ダッシュボードに対してTOTP必須化などの強固なセキュリティベースラインを一貫して適用できます。

Share: