AWS Cognito * Keycloak saml認証
手順イメージ
- Keycloak ローカルセットアップ
- AWS Cognito作成
- Keycloak , Cognito連携
TODO: 順次修正
Keycloakセットアップ
環境
Windows11 WSL v2.x, Ubuntu22.04
上記、公式のDownloadsページのServer一覧から、Container imageのQueryをクリック
Keycloak Container image Usageに書かれている
docker run quay.io/keycloak/keycloak start-dev
で簡単に開発モードでkeycloakを起動できるみたい
ポート等の設定と、keycloak管理画面へのログインユーザー設定を含めて docker run
を叩きたい
docker run -d -p 8080:8080 -p 8443:8443 -p 9000:9000 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak start-dev
パラメータ | 説明 |
---|---|
KEYCLOAK_ADMIN | 管理者名 |
KEYCLOAK_ADMIN_PASSWORD | 管理者パスワード |
start-dev
は開発者モードで起動する
参考: https://www.keycloak.org/server/containers > Trying Keycloak in development mode
dockerがbackgroundで立ち上がったら http://localhost:8080 に接続してみるとKeycloak管理画面へのログイン画面が表示される
ここで先ほどの管理者名、管理者パスワードを使ってログインすることができる
Keycloak用語集
単語 | 説明 |
---|---|
Realm | レルム。Keycloakの管理単位、ユーザー等の情報はレルム単位で管理される |
Realm Role | 権限を定義する単位。Roleはユーザーがシステム内でどのような操作を行えるかを決定する。 Realm Role : レルム全体に適用されるロール Client Role : 特定のクライアントに限定されるロール |
User | Keycloakで管理される個々のユーザー |
Client | Keycloakが保護するアプリケーションやサービスです。クライアントにはWebアプリケーション、モバイルアプリ、APIなどが含まれます。クライアントは認証を行い、ユーザーに代わってアクセスをリクエストします |
Client Scope | クライアントに関連するロールやプロトコルマッパーのセットです。クライアントスコープを使用することで、特定のクライアントに対してアクセス権を柔軟に設定できます |
Group | ユーザーを整理するための単位です。グループにユーザーを追加することで、そのグループに設定されたロールや属性をユーザーに一括適用できます |
Client Login設定
Access Settings の各項目
Root URL | クライアントアプリケーションのルートURL。(例)http://localhost:3000 |
Home URL | ユーザーがログイン後にリダイレクトされるホームページのURL。(例)http://localhost:3000/home |
Valid redirect URIs | 認証後にリダイレクトが許可されるURIのリスト。複数のURIをカンマで区切って指定できる。(例)http://localhost:3000/callback, http://localhost:3000/redirect
|
Valid post logout redirect URIs | ログアウト後にリダイレクトが許可されるURIのリストです。これも複数のURIをカンマで区切って指定できます。ユーザーがログアウトした後、指定されたURLにリダイレクトされます。(例)https://your-app.com/logout-callback, https://another-app.com/logout
|
Clients > Keysタブ > Client signature requried OFFとクライアント署名を不要にしたが、必要なケース、不要なケースが知りたい
必要なケース
-
SPA (Single Page Application)
- SPAは一般的にパブリッククライアントとして動作し、ブラウザ上で直接実行されます。このため、クライアント署名は通常必要ありません。代わりに、OAuth 2.0のImplicitフローやAuthorization Code Flow with PKCEを使用します。
- 例: React、Angular、Vue.jsなどで作成されたアプリケーション
- SPAは一般的にパブリッククライアントとして動作し、ブラウザ上で直接実行されます。このため、クライアント署名は通常必要ありません。代わりに、OAuth 2.0のImplicitフローやAuthorization Code Flow with PKCEを使用します。
-
パブリッククライアント
- パブリッククライアントは、クライアントシークレットを安全に保管できないクライアントです。ブラウザやモバイルアプリなどがこれに該当します。これらの場合、クライアント署名は通常使用されません
- 例: モバイルアプリケーション(iOS、Android)、CLIアプリケーション
- パブリッククライアントは、クライアントシークレットを安全に保管できないクライアントです。ブラウザやモバイルアプリなどがこれに該当します。これらの場合、クライアント署名は通常使用されません
不要なケース
- 機密クライアント (Confidential Client)
- 機密クライアントは、クライアントシークレットや証明書を安全に保管できるサーバーサイドアプリケーションです。これらのクライアントは、クライアント署名を使用してセキュリティを強化することが推奨されます。
- 例: サーバーサイドのウェブアプリケーション(Java、Node.js、Pythonなど)。
- 機密クライアントは、クライアントシークレットや証明書を安全に保管できるサーバーサイドアプリケーションです。これらのクライアントは、クライアント署名を使用してセキュリティを強化することが推奨されます。
- SAML 2.0を使用するクライアント
- SAMLアサーションの署名が必要な場合、クライアント署名が使用されます。これにより、SAMLメッセージの信頼性と整合性が保証されます。
- 例: エンタープライズアプリケーション統合。
- SAMLアサーションの署名が必要な場合、クライアント署名が使用されます。これにより、SAMLメッセージの信頼性と整合性が保証されます。
- OAuth 2.0 JWTベアラートークンを使用するクライアント
- JWTベアラートークンを使用する場合、トークンの署名が必要です。これにより、トークンの発行元と内容の信頼性を確認できます。
- 例: APIゲートウェイと連携するマイクロサービス
- JWTベアラートークンを使用する場合、トークンの署名が必要です。これにより、トークンの発行元と内容の信頼性を確認できます。
- 高セキュリティ要件がある場合
- 金融機関やヘルスケアなど、高度なセキュリティが要求される環境では、クライアント署名が使用されます。これにより、リクエストの改ざん防止や発信元の検証が強化されます。
- 例: オンラインバンキングシステム、医療情報管理システム。
- 金融機関やヘルスケアなど、高度なセキュリティが要求される環境では、クライアント署名が使用されます。これにより、リクエストの改ざん防止や発信元の検証が強化されます。
Cognito, Keycloak を使ったsaml認証を作成する
大体これでできる
細かいところを深堀してく
Cognitoの設定
Cognitoユーザープールサインインオプションで `ユーザー名、Email、電話` の3つのうちどれを(複数選択可)選択するか?
ユーザー名とEmailの2つを選択した場合、ログイン時に「ユーザー名またはEmail、とパスワード」を入力してください
という表示になる
ただ、注意なのが Keycloak
側でもEmailでのログイン可にしておく必要がある。ということ
画面でいうとこちら
Email settings で設定できる項目一覧
Email as username | メールアドレスをユーザー名として使用できるようにするかどうかを設定する |
Login with email | ユーザーがメアドでログインできるようにするかどうかを設定する |
Duplicate emails | 同じメアドを複数のユーザーが使用できるようにするかどうかを設定する |
Verify email | ユーザーが登録時にメアドを確認する必要があるかどうかを設定する |
Cognito SAMLで使うエンドポイント
エンドポイント | 説明 | 今回のケース |
---|---|---|
https://ユーザープールのドメイン /login |
認可エンドポイント | keycloak画面でのログイン時にkeycloak -> Cognitoにリクエストされる |
https://ユーザープールのドメイン /logout |
ログアウトエンドポイント | サインアウト時に呼ばれる。ブラウザ -> keycloak -> cognito順に処理される |
https://ユーザープールのドメイン /oauth2/authorize |
ユーザーをホストされたUIにリダイレクトするか、Idpでサインインするようにリダイレクト | ログイン画面から「keycloackでログイン」をクリックするとブラウザ -> cognitoと呼ばれるAPI。cognitoはこの後idpに対してリダイレクトさせてログインを表示される |
https://ユーザープールドメイン /saml2/idpresponse |
Cognitoがsaml2.0のIdpからの認証応答 |
クライアントシークレットの生成はしない
- セキュリティのリスク
- クライアントシークレットが公開されると、悪意のあるユーザーがそのシークレットを使用して不正なリクエストを行うことができます。
- ブラウザに保存される可能性
- シングルページアプリケーションはクライアントサイドで実行されるため、クライアントシークレットを安全に保持する方法がありません。
SPAの場合はアプリケーションのコードがクライアントのブラウザで実行されるので、クライアントシークレットを使用するのは安全ではないので生成はしない
- シングルページアプリケーションはクライアントサイドで実行されるため、クライアントシークレットを安全に保持する方法がありません。
暗号化キーと証明書
暗号化キー
KeycloackのRealm settings > Endpoints > Saml 2.0 identity Provider Metadataから取得できるMetadataファイルはIdp設定情報が含まれています。
含まれている具体的な情報
- Entity ID
- SSO Endpoint
- 証明書(公開鍵)
- 署名証明書(signing key): saml レスポンスの署名を検証するために使用する
- 暗号化証明書(encryption key): saml アサーションを暗号化するために使用する(cognitoが復号に使用する)
これらの情報は Samlレスポンスの検証や暗号化されたデータの復号に必要です
証明書
Keycloakのクライアント設定で指定する証明書(Encryption keys config)は、samlアサーションを暗号化するための公開鍵を提供する
この公開鍵を利用して Cognitoが暗号化されたアサーションを復号します
暗号化エラーが起きたので解決した
keycloack -> cognito でSAMLリクエストを復号化するときにエラーが起きていたので一旦やめた
暗号化、署名をOFFにする
keycloak側をOFFにする
Clientsからクライアントを選択して、Keys画面で両方をOFFにする(今回は悔しいが暗号化は見送る、、)
Cognito側をOFFにする
SAML署名と暗号化の部分を両方OFFにする
OpenID Connectのスコープを変更する
OpenID Connectのスコープが元々 aws.cognito.signin.user.admin, Email, OpenID
だったが Email, OpenID, プロファイル
に修正した
上記に応じて、下記も修正
NEXT_PUBLIC_SCOPE=profile email openid
メモ
図解
調査方法まとめ
Keycloakログ
今回はDockerで立ててるので docker logs
コマンドで確認する
docker logs [docker container id]
実際にログファイルがある場所
とりあえずdocker に接続してみて調べる
$ docker exec -it 12b /bin/bash
bash-5.1$ find / -name "*.log"
/var/log/hawkey.log
find: ‘/proc/tty/driver’: Permission denied
/path/to/your/keycloak/log/file.log
にあるらしいのだが、自分の場合見つからなかった、、
どこにあるのかわからんので、とりあえずdocker logsで対応した
エラーまとめ
Invalid query param signature
エラー内容
2024-07-23 17:43:37,816 ERROR [org.keycloak.protocol.saml.SamlService] (executor-thread-311) request validation failed: org.keycloak.common.VerificationException: org.keycloak.common.VerificationException: Invalid query param signature
未解決、、、今回は暗号化を見送る、、
ChatGPTに投げた結果
エラーメッセージ Invalid query param signature
は、KeycloakがCognitoからのSAMLリクエストの署名を検証できなかったことを示しています。このエラーが発生する主な原因として、CognitoとKeycloakの間で使用されている署名に関する設定が一致していない可能性があります。
検証と修正手順
1. KeycloakのSAML設定
-
Keycloak管理コンソールにログインします。
-
左側のメニューからClientsを選択し、Cognito用のクライアントを選択します。
-
Settingsタブを開き、次の設定を確認します。
- Sign documents がオンになっていること。
- Sign assertions がオンになっていること。
-
Signature algorithm が
RSA_SHA256
になっていること。
-
SAML Keys セクションで、正しい証明書が設定されていることを確認します。
2. Keycloakの公開鍵のエクスポート
- Keycloak管理コンソールで、Clientsを選択し、Cognito用のクライアントを選択します。
- Keysタブを開きます。
- Certificateセクションから、公開鍵をエクスポートします。
3. Cognitoの設定確認
- AWS管理コンソールにログインします。
- Cognitoサービスを選択し、設定したユーザープールを選択します。
- 左側のメニューからIdentity Providersを選択し、SAML IdPの設定を編集します。
- Keycloakの公開鍵が正しく設定されていることを確認します。
4. リクエストURLの確認
以下のURLが正しく構成されていることを確認します。特に、クエリパラメータが正しくエンコードされていることを確認します。
詳細な手順
Keycloakでの設定確認
- Keycloak管理コンソールにログイン。
- 左側のメニューからClientsを選択し、Cognito用のクライアントを選択。
- Settingsタブを開く。
-
Signature and Encryptionセクションで、次の設定を確認:
- Sign documents がオン。
- Sign assertions をオンに切り替える。
-
Signature algorithm が
RSA_SHA256
になっている。 - SAML signature key name を適切なキーに設定する。
Keycloakの公開鍵のエクスポート
- Keycloak管理コンソールで、Clientsを選択し、Cognito用のクライアントを選択。
- Keysタブを開く。
- Certificateセクションから、公開鍵をエクスポートする。
エクスポート例(公開鍵の形式を確認):
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
Cognitoの設定確認
- AWS管理コンソールにログイン。
- Cognito > 該当ユーザープール > Identity Providers で、SAML IdPの設定を編集。
- Keycloakの公開鍵が正しく設定されていることを確認。
ログの再確認
KeycloakとCognitoのログを再度確認し、具体的なエラーメッセージを探します。
Keycloakのログ確認
-
コンテナ内にシェルアクセス:
docker exec -it xxxxxx /bin/bash
-
ログファイルの場所を検索:
find / -name "*.log"
-
ログファイルの内容を表示:
tail -f /path/to/your/keycloak/log/file.log
まとめ
- Sign assertions をオンにする。
- SAML signature key name を適切なキーに設定する。
- Keycloakの公開鍵がCognitoに正しく設定されていることを確認する。
- Keycloakのログを再確認し、具体的なエラーメッセージを探す。
これらの設定を確認および修正した後、再度認証フローを試してみてください。問題が解決するはずです。
参考記事
keycloack公式
動画