Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
kafka-keycloak-oauth — Apache Kafka 4.1.0(KRaft)とKeycloak OAuth2認証をStrimziで使用 - CVE-2025-27817のURL許可リスト制限をバイパス | Kitploit
ツール/GitHubGitHub/oriolrius/kafka-keycloak-oauth
クラウドインフラストラクチャセキュリティ脆弱性分析構成監査DevSecOps認証学習と教育
GitHuboriolrius/kafka-keycloak-oauth

kafka-keycloak-oauth

Apache Kafka 4.1.0(KRaft)とKeycloak OAuth2認証をStrimziで使用 - CVE-2025-27817のURL許可リスト制限をバイパス

リポジトリを見る
5310ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

Apache Kafka 4.1.0 + Keycloak OAuth2 認証

Keycloak 26.1.1 OAuth2/OIDC 認証を備えた本番環境対応の Apache Kafka 4.1.0(KRaft モード)。Strimzi Kafka イメージを使用。

このプロジェクトが kafka-oauth-keycloak-tls-demo より優れている理由

これは以前の POC を大幅に改善した進化版です:

  • Strimzi OAuth 0.17.0(旧 1.0.0 から変更)- Strimzi Kafka 0.48.0 イメージに同梱された安定版
  • カスタム Docker ビルド不要 - OAuth がプリインストールされた公式 Strimzi イメージを使用し、Dockerfile の複雑さを排除
  • CVE-2025-27817 への対応 - URL 許可リスト制限と、Strimzi OAuth がそれを回避する理由を文書化
  • シンプルなアーキテクチャ - 単一 KRaft 結合モード(ブローカー+コントローラー)、分割アーキテクチャではない
  • librdkafka クライアントに焦点 - Java ネイティブクライアントではなく、confluent-kafka-python でテスト済み(URL 許可リストの問題なし)
  • 包括的な技術ドキュメント - 本番環境チェックリスト、トラブルシューティング、パフォーマンスチューニング、プリンシパルマッピングの詳細
  • よりクリーンな証明書管理 - 即時テスト用のサンプル証明書を同梱
  • 自動化された Keycloak セットアップ - スクリプトによるレルム/クライアント/マッパー作成と audience 設定
  • 動作する Python テストスイート - OAuth エンドツーエンドのメッセージ配信を検証
  • 明示的な issuer URL の扱い - トークンエンドポイントと issuer 検証における内部/外部 URL の二重性を文書化

アーキテクチャ

  • Kafka ディストリビューション: Strimzi Kafka イメージ 0.48.0(Apache Kafka 4.1.0 + Strimzi OAuth 0.17.0 プリインストール)
  • Kafka バージョン: Apache Kafka 4.1.0(KRaft 結合ブローカー+コントローラー)
  • OAuth ライブラリ: Strimzi Kafka OAuth 0.17.0(イメージに同梱、CVE-2025-27817 の URL 許可リスト制限を回避)
  • OAuth プロバイダー: Keycloak 26.1.1
  • セキュリティ: 外部クライアントは SASL_SSL(OAuth)、ブローカー間は PLAINTEXT、自己署名 CA による SSL

CVE-2025-27817 の背景

Apache Kafka 4.0.0+ では、SSRF/任意ファイル読み取りの脆弱性を修正するため、JVM システムプロパティとして URL 許可リスト(org.apache.kafka.sasl.oauthbearer.allowed.urls)が導入されました。これにより、ネイティブ Apache Kafka クライアントでの標準的な OAuth 利用が妨げられます。

解決策: Strimzi Kafka OAuth ライブラリはこの制限を実装していないため、Kafka 4.1.0 で OAuth 機能を利用できます。

前提条件

  • Docker Compose
  • Python 3.x + uv(テスト用)
  • OpenSSL(証明書生成用)

クイックスタート

root@kitploit:~
# SSL 証明書の生成
cd kafka-security
./generate-certs.sh
cd ..

# サービスの起動
docker compose up -d

# Keycloak の確認
curl http://localhost:8080/health/ready

# Keycloak レルムとクライアントのセットアップ
./scripts/setup-keycloak.sh

# OAuth プロデューサーのテスト
source ~/.venv/bin/activate
uv pip install confluent-kafka
python tests/quick_test.py

ネットワークトポロジー

root@kitploit:~
keycloak:8080 (HTTP) ←→ kafka-broker:9093 (SASL_SSL/OAuth)
                      ↔ kafka-broker:19092 (PLAINTEXT/ブローカー間)
                      ↔ kafka-broker:29093 (PLAINTEXT/KRaft コントローラー)

SSL 設定

CA 構成

  • ルート CA: kafka-security/ca-cert + ca-key
  • ブローカーキーストア: kafka-security/broker/kafka.server.keystore.jks(サーバー証明書 + 秘密鍵を含む)
  • ブローカートラストストア: kafka-security/broker/kafka.server.truststore.jks(CA 証明書を含む)
  • パスワード: changeit(すべてのキーストア/トラストストア)

証明書の詳細

root@kitploit:~
# ブローカー証明書
CN=kafka-broker
SAN=DNS:kafka-broker,DNS:localhost,IP:127.0.0.1

# 有効期間: 3650 日
# 鍵アルゴリズム: RSA 2048 ビット
# 署名アルゴリズム: SHA256withRSA

Keycloak OAuth 設定

レルム: kafka-realm

クライアント

kafka-broker(機密)

  • クライアント ID: kafka-broker
  • クライアントシークレット: setup-keycloak.sh によって自動生成
  • 目的: ブローカー間 OAuth 認証
  • マッパー:
    • Audience マッパー: JWT の aud クレームに kafka-broker を追加
    • ユーザー名マッパー: トークンに preferred_username を含める

kafka-producer(機密)

  • クライアント ID: kafka-producer
  • クライアントシークレット: 自動生成
  • 目的: 外部プロデューサークライアント
  • グラント: client_credentials
  • マッパー: kafka-broker と同じ

kafka-consumer(機密)

  • クライアント ID: kafka-consumer
  • クライアントシークレット: 自動生成
  • 目的: 外部コンシューマークライアント
  • グラント: client_credentials
  • マッパー: kafka-broker と同じ

トークンエンドポイント

root@kitploit:~
POST http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=kafka-producer
&client_secret=<secret>
&scope=profile email

JWT トークン構造

root@kitploit:~
{
  "aud": ["kafka-broker", "account"],
  "iss": "http://localhost:8080/realms/kafka-realm",
  "azp": "kafka-producer",
  "preferred_username": "service-account-kafka-producer",
  "scope": "profile email"
}

Kafka 設定

KRaft モード(kraft-config.properties)

root@kitploit:~
# ノード ID
node.id=1
process.roles=broker,controller
controller.quorum.voters=1@kafka-broker:29093

# リスナー
listeners=SASL_SSL://0.0.0.0:9093,PLAINTEXT://0.0.0.0:19092,CONTROLLER://0.0.0.0:29093
advertised.listeners=SASL_SSL://localhost:9093,PLAINTEXT://kafka-broker:19092
listener.security.protocol.map=SASL_SSL:SASL_SSL,PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
inter.broker.listener.name=PLAINTEXT
controller.listener.names=CONTROLLER

# SASL メカニズム
sasl.enabled.mechanisms=OAUTHBEARER

# Strimzi OAuth ハンドラー(SASL_SSL のリスナーごと)
listener.name.sasl_ssl.oauthbearer.sasl.login.callback.handler.class=io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler
listener.name.sasl_ssl.oauthbearer.sasl.server.callback.handler.class=io.strimzi.kafka.oauth.server.JaasServerOauthValidatorCallbackHandler

# JAAS による OAuth 設定
listener.name.sasl_ssl.oauthbearer.sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required \
  oauth.client.id="kafka-broker" \
  oauth.client.secret="<secret>" \
  oauth.token.endpoint.uri="http://keycloak:8080/realms/kafka-realm/protocol/openid-connect/token" \
  oauth.valid.issuer.uri="http://localhost:8080/realms/kafka-realm" \
  oauth.jwks.endpoint.uri="http://keycloak:8080/realms/kafka-realm/protocol/openid-connect/certs" \
  oauth.username.claim="preferred_username";

主要な Strimzi OAuth パラメータ

  • oauth.client.id: トークン取得用のクライアント識別子
  • oauth.client.secret: トークン取得用のクライアントシークレット
  • oauth.token.endpoint.uri: Keycloak トークンエンドポイント(ブローカーは内部ホスト名 keycloak:8080 を使用)
  • oauth.valid.issuer.uri: 期待される JWT issuer(トークンの iss クレームと一致する必要があり、外部の localhost:8080 を使用)
  • oauth.jwks.endpoint.uri: JWT 署名検証用の JWKS エンドポイント
  • oauth.username.claim: プリンシパル抽出用の JWT クレーム

認可

root@kitploit:~
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
super.users=User:kafka-broker;User:ANONYMOUS
allow.everyone.if.no.acl.found=true

注記: 現在はテスト用に許可設定。本番環境では ACL を使用すべきです。

クライアント設定

Python プロデューサー(confluent-kafka)

root@kitploit:~
from confluent_kafka import Producer

conf = {
    'bootstrap.servers': 'localhost:9093',
    'security.protocol': 'SASL_SSL',
    'sasl.mechanisms': 'OAUTHBEARER',
    'sasl.oauthbearer.method': 'oidc',
    'sasl.oauthbearer.client.id': 'kafka-producer',
    'sasl.oauthbearer.client.secret': '<secret>',
    'sasl.oauthbearer.token.endpoint.url': 'http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token',
    'ssl.ca.location': 'kafka-security/ca-cert',
    'ssl.endpoint.identification.algorithm': 'none',
}

producer = Producer(conf)
producer.produce('topic', b'message')
producer.flush()

Python コンシューマー(confluent-kafka)

root@kitploit:~
from confluent_kafka import Consumer

conf = {
    'bootstrap.servers': 'localhost:9093',
    'group.id': 'test-group',
    'security.protocol': 'SASL_SSL',
    'sasl.mechanisms': 'OAUTHBEARER',
    'sasl.oauthbearer.method': 'oidc',
    'sasl.oauthbearer.client.id': 'kafka-consumer',
    'sasl.oauthbearer.client.secret': '<secret>',
    'sasl.oauthbearer.token.endpoint.url': 'http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token',
    'ssl.ca.location': 'kafka-security/ca-cert',
    'ssl.endpoint.identification.algorithm': 'none',
    'auto.offset.reset': 'earliest',
}

consumer = Consumer(conf)
consumer.subscribe(['topic'])
while True:
    msg = consumer.poll(1.0)
    if msg: print(msg.value())

librdkafka が動作する理由

confluent-kafka-python は、sasl.oauthbearer.method=oidc で OAuth を実装する librdkafka(C ライブラリ)を使用します。この実装は、ネイティブ Apache Kafka Java クライアントをブロックする org.apache.kafka.sasl.oauthbearer.allowed.urls システムプロパティをチェックしません。

トラブルシューティング

OAuth トークンの検証

root@kitploit:~
TOKEN=$(curl -s -X POST http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token \
  -d "grant_type=client_credentials" \
  -d "client_id=kafka-producer" \
  -d "client_secret=<secret>" | jq -r .access_token)

echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | jq .

期待されるクレーム:

root@kitploit:~
{
  "aud": ["kafka-broker", "account"],
  "iss": "http://localhost:8080/realms/kafka-realm",
  "azp": "kafka-producer",
  "preferred_username": "service-account-kafka-producer"
}

ブローカーの OAuth ログ確認

root@kitploit:~
docker logs kafka-broker 2>&1 | grep -E "Strimzi|JWTSignatureValidator|OAUTHBEARER"

期待される出力:

root@kitploit:~
[io.strimzi.kafka.oauth.validator.JWTSignatureValidator] JWKS keys change detected

ブローカーリスナーの確認

root@kitploit:~
docker exec kafka-broker netstat -tlnp | grep java

期待される出力:

root@kitploit:~
tcp6  0.0.0.0:9093   LISTEN  (SASL_SSL)
tcp6  0.0.0.0:19092  LISTEN  (PLAINTEXT)
tcp6  0.0.0.0:29093  LISTEN  (CONTROLLER)

KRaft メタデータの確認

root@kitploit:~
docker exec kafka-broker cat /var/lib/kafka/data/meta.properties

期待される出力:

root@kitploit:~
version=1
cluster.id=kafka-cluster-01
node.id=1

一般的な問題

問題: {"status":"invalid_token"}

  • 原因: JWT 署名検証の失敗
  • 修正: oauth.jwks.endpoint.uri がブローカーコンテナから到達可能か確認
  • 確認方法: docker exec kafka-broker curl http://keycloak:8080/realms/kafka-realm/protocol/openid-connect/certs

問題: Token audience mismatch

  • 原因: JWT の aud クレームに kafka-broker が含まれていない
  • 修正: ./scripts/setup-keycloak.sh を実行して audience マッパーを追加
  • 確認方法: トークンをデコードして aud クレームに kafka-broker が含まれているか確認

問題: Token issuer mismatch

  • 原因: JWT の iss が oauth.valid.issuer.uri と一致しない
  • 修正: oauth.valid.issuer.uri=http://localhost:8080/realms/kafka-realm(外部ホスト名)を確認
  • 注記: ブローカーはトークンエンドポイントに http://keycloak:8080 を使用するが、issuer は http://localhost:8080 に対して検証する

問題: ネイティブ Java Kafka クライアントが URL 許可リストエラーで失敗

  • 原因: Apache Kafka 4.1.0 の CVE-2025-27817 修正
  • 修正: librdkafka ベースのクライアント(confluent-kafka-python)を使用するか、ブローカー側で Strimzi OAuth を使用(すでに設定済み)

パフォーマンスチューニング

トークン更新

Keycloak の JWT トークンは 5 分で期限切れになります。Strimzi OAuth は更新を自動処理します:

  • oauth.refresh.token: 未使用(client_credentials グラント)
  • トークンは期限切れの 30 秒前にキャッシュされ更新されます

JWKS キャッシュ

root@kitploit:~
sasl.oauthbearer.jwks.endpoint.refresh.ms=3600000  # 1 時間
sasl.oauthbearer.jwks.endpoint.retry.backoff.ms=100
sasl.oauthbearer.jwks.endpoint.retry.backoff.max.ms=10000

接続設定

root@kitploit:~
connections.max.idle.ms=600000
connection.failed.authentication.delay.ms=1000

本番環境チェックリスト

  • 自己署名証明書を CA 署名証明書に置き換える
  • ssl.endpoint.identification.algorithm=https に更新(none を削除)
  • 適切な ACL を設定(allow.everyone.if.no.acl.found=true を削除)
  • ACL の設定:
    root@kitploit:~
    kafka-acls --bootstrap-server localhost:9093 \
      --command-config admin.properties \
      --add --allow-principal User:kafka-producer \
      --operation Write --topic '*'
    
  • Keycloak クライアントシークレットをローテーション
  • Keycloak で HTTPS を有効化
  • oauth.token.endpoint.uri と oauth.jwks.endpoint.uri を HTTPS URL に更新
  • Kafka モニタリングを設定(JMX、Prometheus)

ディレクトリ構造

root@kitploit:~
.
├── docker-compose.yml              # オーケストレーション
├── .env                            # シークレット(gitignore 対象)
├── kafka-config/
│   ├── kraft-config.properties     # Kafka ブローカー設定
│   ├── producer.properties         # プロデューサー OAuth 設定(CLI ツール用)
│   └── consumer.properties         # コンシューマー OAuth 設定(CLI ツール用)
├── kafka-security/
│   ├── generate-certs.sh           # SSL 証明書生成スクリプト
│   ├── ca-cert                     # ルート CA 証明書
│   ├── ca-key                      # ルート CA 秘密鍵
│   └── broker/
│       ├── kafka.server.keystore.jks
│       └── kafka.server.truststore.jks
├── scripts/
│   └── setup-keycloak.sh           # Keycloak レルム/クライアントセットアップ
└── tests/
    └── quick_test.py               # OAuth 検証テスト

技術メモ

Strimzi Kafka イメージを Apache Kafka 公式イメージの代わりに使用する理由

Strimzi Kafka イメージ(quay.io/strimzi/kafka:0.48.0-kafka-4.1.0)を公式 Apache Kafka イメージの代わりに使用する理由:

  1. OAuth サポート同梱: Strimzi OAuth 0.17.0 ライブラリがプリインストール(クラス: io.strimzi.kafka.oauth.*)
  2. CVE-2025-27817 の回避: Strimzi OAuth ライブラリはネイティブ Kafka OAuth を壊す URL 許可リスト制限を実装していない
  3. 本番環境対応: Strimzi Operator を通じて Kubernetes 環境で実績あり
  4. 単一イメージ: OAuth JAR ファイルを手動でダウンロードしてマウントする必要がない

イメージ構成:

  • Strimzi Kafka 0.48.0 = Docker イメージのバージョン/リリース
  • Apache Kafka 4.1.0 = 内部に同梱された Kafka ブローカーバージョン
  • Strimzi OAuth 0.17.0 = 内部に同梱された OAuth ライブラリバージョン

Issuer URL の二重性

ブローカー設定には 2 つの URL があります:

  • oauth.token.endpoint.uri=http://keycloak:8080/...(内部 Docker ネットワーク)
  • oauth.valid.issuer.uri=http://localhost:8080/...(外部、JWT の iss クレームと一致)

これは以下の理由によるものです:

  • ブローカーは内部 DNS 名を使用してトークンを取得
  • Keycloak は外部 issuer URL でトークンを発行(レルム設定で構成)
  • JWT 検証では issuer の完全一致が必要

プリンシパルマッピング

ブローカーは JWT の preferred_username クレームからプリンシパルを抽出します:

root@kitploit:~
service-account-kafka-producer → User:service-account-kafka-producer

ACL はこのプリンシパルを参照して認可を行います。

バージョン互換性

参考リンク

  • Strimzi Kafka OAuth
  • Apache Kafka セキュリティ
  • Keycloak OIDC
  • CVE-2025-27817
  • KRaft モード
ツールをダウンロード
  • OAuth 監査証跡のログ集約を設定
  • フェイルオーバーシナリオをテスト
  • シークレットローテーション手順を文書化
  • 必要に応じて Keycloak ユーザーフェデレーション(LDAP/AD)を有効化
  • コンポーネントバージョン備考
    Apache Kafka4.1.0KRaft モード(ZooKeeper なし)
    Strimzi Kafka イメージ0.48.0Docker イメージ: quay.io/strimzi/kafka:0.48.0-kafka-4.1.0
    Strimzi OAuth ライブラリ0.17.0Strimzi Kafka 0.48.0 イメージにプリインストール
    Keycloak26.1.1最新 LTS
    librdkafka2.12.0+OIDC OAuth サポート
    confluent-kafka-python2.12.0+librdkafka バージョンと一致