Fedora ServerでのKeycloak構築・設定ガイド:シングルサインオン(SSO)とOAuth2/OIDC基盤の実装

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

クイックスタート(5分で完了)

アプリの動作検証やサンドボックス環境用に、Fedora Server上でKeycloakクラスタを手早く立ち上げる必要がありますか?以下の基本的なコマンドを実行するだけで、約5分で環境を構築できます。

まず、OpenJDK 21および必要な展開ツールをインストールします:

sudo dnf install -y java-21-openjdk-headless tar gzip curl

次に、Keycloak(Quarkusランタイム)ディストリビューションをダウンロードし、/optディレクトリに展開します:

cd /opt
KEYCLOAK_VERSION="24.0.2"
sudo curl -LO https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-${KEYCLOAK_VERSION}.tar.gz
sudo tar -xzf keycloak-${KEYCLOAK_VERSION}.tar.gz
sudo mv keycloak-${KEYCLOAK_VERSION} keycloak
sudo rm -f keycloak-${KEYCLOAK_VERSION}.tar.gz

一時的な管理者アカウント情報を設定し、開発モード(development mode)で起動します:

export KEYCLOAK_ADMIN=admin
export KEYCLOAK_ADMIN_PASSWORD=AdminStrongPassword123!
/opt/keycloak/bin/kc.sh start-dev --http-port=8080

Fedora ServerではデフォルトでSSH以外のポートがブロックされているため、firewalldでポート8080を開放します:

sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --reload

ブラウザを開き、http://<Fedora-Server-IP>:8080にアクセスします。先ほど作成した管理者ユーザーadminでログインすれば、Admin Consoleへすぐにアクセスできます。

詳細解説:アーキテクチャとKeycloakによるSSOの仕組み

1. Keycloakのコアコンセプト

SSOやIAM基盤としてKeycloakを使いこなすには、以下の4つの基本概念を理解しておく必要があります:

  • Realm(レルム): 独立したユーザー管理空間(マルチテナント)。デフォルトでは管理用のmasterレルムが存在します。本番環境や実プロジェクトでは、個別のレルム(例:internal-corpやecommerce-app)を作成して運用します。
  • Client(クライアント): フロントエンドSPA(React、Vue)、モバイルアプリ(Flutter)、バックエンドREST API(FastAPI、Spring Boot)など、Keycloakに認証を委譲するすべてのアプリケーションを指します。
  • Roles & Groups(ロールとグループ): ユーザーの権限管理と認可制御を行います。システム全体に適用されるレルムロール(Realm Roles)や、特定のアプリケーション内のみで有効なクライアントロール(Client Roles)を設定できます。
  • Identity Providers(IdP / アイデンティティプロバイダー): 外部認証との連携ブリッジです。Google、GitHub、Microsoft 365によるソーシャルログインや、既存のLDAP / Active Directoryとの同期を実現します。

2. PKCE対応Authorization Codeフロー(OIDC)の仕組み

Webアプリやモバイルアプリにおいて現在最も安全とされる標準認証フローです。認証は以下の6つのステップで進行します:

  1. ユーザーがWebアプリ(クライアント)上の「ログイン」ボタンをクリックします。
  2. ブラウザが/realms/{realm-name}/protocol/openid-connect/authエンドポイントへcode_challenge(PKCE)を付与してKeycloakにリダイレクトされます。
  3. ユーザーが認証情報を入力し、有効化されている場合は2要素認証(2FA/OTP)を行います。
  4. Keycloakが認証を完了し、リダイレクトURI経由で認可コード(Authorization Code)を返却します。
  5. クライアントのバックエンドがAuthorization Codeとcode_verifierをKeycloakに送信し、IDトークンおよびアクセストークン(JWT形式)と交換します。
  6. クライアントはトークンを保持してログインセッションを維持します。ユーザーの生のパスワードを保持する必要は一切ありません。

3. Fedora上でのPostgreSQLおよびSystemdによる本番環境構成

開発モードで使われるデフォルトのH2データベースは、メモリ上またはローカルファイルにデータを一時保存するだけです。本番環境(Production)では、可用性とデータの完全性を確保するためにPostgreSQLの使用が必須となります。

FedoraへのPostgreSQLのインストールと初期化手順:

sudo dnf install -y postgresql-server postgresql-contrib
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql

# Keycloak用のユーザーおよびデータベースの作成
sudo -u postgres psql -c "CREATE DATABASE keycloak;"
sudo -u postgres psql -c "CREATE USER keycloak WITH ENCRYPTED PASSWORD 'KeycloakDBPass456!';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;"

続いて、設定ファイル/opt/keycloak/conf/keycloak.confを編集します:

# データベース設定
db=postgres
db-username=keycloak
db-password=KeycloakDBPass456!
db-url=jdbc:postgresql://localhost:5432/keycloak

# HTTP & プロキシ設定
http-enabled=true
http-port=8080
proxy-headers=xforwarded
hostname=sso.yourcompany.com

セキュリティ上、Keycloakをroot権限で実行することは推奨されません。専用のシステムユーザーを作成します:

sudo useradd -r -d /opt/keycloak -s /sbin/nologin keycloak
sudo chown -R keycloak:keycloak /opt/keycloak

/etc/systemd/system/keycloak.serviceにSystemdサービス設定ファイルを作成します。kc.sh buildステップで静的設定を事前ビルドしておくことで、起動時間を従来の15〜20秒から3秒未満へ大幅に短縮できます:

[Unit]
Description=Keycloak Identity Provider
After=network.target postgresql.service

[Service]
Type=exec
User=keycloak
Group=keycloak
Environment="KEYCLOAK_ADMIN=admin"
Environment="KEYCLOAK_ADMIN_PASSWORD=YourRootPassword"
ExecStartPre=/opt/keycloak/bin/kc.sh build
ExecStart=/opt/keycloak/bin/kc.sh start --optimized
TimeoutStartSec=600
TimeoutStopSec=60
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

設定をリロードし、サービスの自動起動と起動を有効化します:

sudo systemctl daemon-reload
sudo systemctl enable --now keycloak
sudo systemctl status keycloak

高度な設定:Webアプリ統合とNginxリバースプロキシ

1. 管理コンソールでのレルムおよびクライアントの設定

  1. 左上のドロップダウンメニューをクリックし、Create Realmを選択 > レルム名にInternal-Companyを入力します。
  2. Clientsメニューに移動 > Create Clientを選択します:
    • Client type: OpenID Connect
    • Client ID: web-portal
    • Client authentication: バックエンドAPIやSSRアプリの場合はOn、SPA(React/Vue)やモバイルアプリの場合はOffに設定します。
    • Valid redirect URIs: https://app.yourcompany.com/callback
    • Web origins: https://app.yourcompany.com

2. SSL対応Nginxリバースプロキシの設定

SSL終端とHTTPSトラフィックのルーティングを処理するために、Keycloakの前段にリバースプロキシを配置します。設定ファイル/etc/nginx/conf.d/keycloak.confを作成します:

server {
    listen 80;
    server_name sso.yourcompany.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name sso.yourcompany.com;

    ssl_certificate /etc/letsencrypt/live/sso.yourcompany.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sso.yourcompany.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }
}

3. バックエンドでのJWTトークン検証サンプル(Python FastAPI)

以下は、クライアントから送信されたアクセストークンのデジタル署名を検証・デコードするバックエンド用ミドルウェアの実装例です:

import jwt
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import requests

app = FastAPI()
security = HTTPBearer()

KEYCLOAK_URL = "https://sso.yourcompany.com/realms/Internal-Company"
# 本番環境では、頻繁なHTTPリクエストを防ぐためJWKS証明書の取得結果をキャッシュすることを推奨します
jwks_url = f"{KEYCLOAK_URL}/protocol/openid-connect/certs"
jwks = requests.get(jwks_url).json()

def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
    token = credentials.credentials
    try:
        # JWKSから該当する署名キーを取得
        header = jwt.get_unverified_header(token)
        key = [k for k in jwks['keys'] if k['kid'] == header['kid']][0]
        public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key)
        
        payload = jwt.decode(
            token, 
            public_key, 
            algorithms=["RS256"], 
            audience="account"
        )
        return payload
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, 
            detail="無効なトークンであるか、有効期限が切れています"
        )

@app.get("/api/v1/protected-data")
def get_data(user: dict = Depends(verify_token)):
    return {"status": "success", "user": user.get("preferred_username", "Unknown")}

実践的なTIPSとトラブルシューティング

  • Fedoraの迅速なパッケージ更新の活用: Fedoraは常に最新のOpenJDKやネットワーク診断ツールを提供しています。外部リポジトリの追加や依存関係を気にすることなく、ncやtcpdumpを用いてLDAP/PostgreSQLの接続テストを即座に実施できます。
  • 「Invalid parameter: redirect_uri」エラーの対処: 連携初期に最も頻発するエラーです。リクエストで送信されたURLが、KeycloakのValid redirect URIsに設定した内容と1文字単位で完全一致していないことが原因です(末尾のスラッシュ/の有無やhttpとhttpsの不一致など)。オープンリダイレクト脆弱性を防ぐため、本番環境でワイルドカード*は絶対に使用しないでください。
  • メモリおよびJVMヒープの最適化: デフォルトのQuarkusは起動時に約400MB〜600MBのメモリを消費します。同時接続ユーザー数(CCU)が1,000人を超えるシステムでは、OutOfMemoryエラーを防ぐため、サービス定義ファイル内でJAVA_OPTS_KC_HEAP="-Xms1024m -Xmx2048m"のようにヒープサイズを明示的に固定することをおすすめします。
  • ヘッダーサイズ肥大化による502 Bad Gatewayの解決: Keycloakの認証Cookieやアクセストークンを含むヘッダーは、8KB〜16KBに達することがあります。Nginxで502 Bad Gatewayが発生する場合は、前述のNginx設定サンプルのようにproxy_buffer_size 128k;およびproxy_buffers 4 256k;を設定してバッファサイズを拡張してください。
Share: