第1回では、KeycloakのCNCF Incubatingプロジェクト入りの過程におけるAPサーバや管理コンソール画面などの大きな変更点、開発コミュニティの活動状況を紹介しました。KeycloakがCNCF Incubatingプロジェクト入りしたことで、今後クラウドネイティブな環境であるコンテナ環境での利用が増えていくことが考えられます。そこで第2回では、Keycloakの典型的なユースケースであるシングルサインオンをコンテナ環境上のKeycloakで実現する方法を紹介します。また、KeycloakをGrafanaおよびPrometheusと連携させて、Keycloakのメトリクスを可視化する方法も紹介します。
本記事のシステム構成
まず、シングルサインオンとメトリクスの可視化を実現するための本記事のシステム構成(図1)を説明します。
図1:本記事のシステム構成
本記事ではクラウドネイティブなコンテナ環境として、簡易なローカルKubernetesであるMinikubeを使用します。ただし、本記事の前提として、Minikubeはドキュメントなどを参考にすでにインストール済みで、利用可能であるとします。
そして、Minikube上にKeycloakをデプロイします。また、同様にMinikube上にArgo CDとGrafanaをデプロイして、Argo CDとGrafanaの認証をKeycloakに委譲します。これにより、本記事ではArgo CDとGrafanaのシングルサインオンを実現します。
さらに、メトリクスの可視化に必要なPrometheusをMinikube上にデプロイします。デプロイされたPrometheusはKeycloakのメトリクスエンドポイントにアクセスし、メトリクスを取得します。そして、GrafanaはPrometheusに対してクエリを実行してメトリクスを取得し、可視化します。可視化されるメトリクスはGrafanaのダッシュボードで確認することができます。
また、本記事で使用するOSSのバージョンを表 1に示します。
表1:OSSのバージョン情報
OSS | バージョン |
Minikube | 1.31.1 |
Kubernetes | 1.27.4 |
Docker | 24.0.4 |
Keycloak | 22.0.1 |
Argo CD | 2.7.10 |
Prometheus | 0.67.0 |
Grafana | 10.0.2 |
本記事のシングルサインオンのフロー
次に、本記事で実現するシングルサインオンのフロー(図2)を説明します。
図2:実現するシングルサインオンのフロー
図2の1-①~1-⑦までがArgo CDにログインするフローになります。そのうちの1-②~1-⑥は認証の標準仕様であるOpenID Connect Core 1.0(以降、OIDC)で定義された認可コードフローになります。このフローの中で1-⑤と1-⑥が重要になります。1-⑤では、Keycloakが発行する認証Cookieを含んだ認可レスポンスがブラウザに返されます。この認証Cookieがシングルサインオンを実現する上で必要になります。また1-⑥では、ユーザーに関する情報がIDトークンによってArgo CDに連携されます。Argo CDはIDトークン内の情報を基にユーザーを識別でき、またIDトークンの設定次第ではロールを識別することもできます。
一方で図2の2-①~2-⑦までがGrafanaにログインするフローになります。このフローはArgo CDにログインするフローとほぼ同じになります。ただし、すでにArgo CDにログイン済み、つまり1-⑤で発行された認証Cookieがブラウザに存在する場合、2-②で認証CookieがKeycloakに送られます。Keycloakは受け取った認証Cookieを使用してCookie認証を行い、Cookie認証が成功すれば、2-③と2-④は省略されます。これにより、ログイン画面にパスワードなどの認証情報を入力することなく、認証が成功するため、シングルサインオンが実現されます。
本記事で使用するArgo CDとGrafanaは、OIDCに対応しています。そのため、Keycloakに認証を委譲するように設定するだけで、Keycloakによるシングルサイオンを実現できます。なお、OIDCに対応していないアプリケーションで今回のようなKeycloakによるシングルサインオンを実現する場合は、別途ライブラリやリバースプロキシを導入し、OIDCに対応する必要があります。ライブラリについてはこちらのページを、リバースプロキシについてはこちらのページをご参照ください。
Keycloakのデプロイ
Keycloakの典型的なユースケースであるシングルサインオンとメトリクスの可視化を実現するために、まずはKeycloakをデプロイします。今回デプロイするKeycloakの構成は、本番用途で推奨される最低限の構成です。
- Serviceに対するアクセスにはIngressを使用
- Keycloakの設定格納用DBには外部DB(PostgreSQL)を使用
Keycloakには内部DBがありますが、内部DBはKeycloak単体で実行できるようにするために組み込まれたものであり、本番用途では外部DBの使用が推奨されます
- 通信はTLSで暗号化
- ホスト名にはこちらのページに記載がある「test.keycloak.org」を使用
KeycloakをMinikube上にデプロイする方法として、Dockerイメージを使用する方法、QuickStartsリポジトリを使用する方法、Operatorを使用する方法などがあります。Operatorを使用すると、前述した本番用途で推奨される最低限の構成を容易にデプロイできるため、今回はOperatorを使用してKeycloakをデプロイします。
初めに、今回作業する名前空間を作成し、作成した名前空間をコンテキストのデフォルトの名前空間に設定します。本記事ではkeycloakという名前空間を作成します。
リスト1:
1 | $ kubectl create namespace keycloak |
2 | $ kubectl config set-context $(kubectl config current-context) --namespace=keycloak |
そして、Keycloak Operatorをインストールするために、CRDとKeycloak Operatorのデプロイメントをインストールします。これでKeycloak Operatorを使用できるようになります。
次に、今回はIngressを使用するので、MinikubeのIngressを有効化します。
リスト3:
1 | $ minikube addons enable ingress |
次に、Keycloakの設定格納用の外部DB、今回はPostgreSQLを作成します。こちらのページに記載があるexample-postgres.yamlに以下を追記したファイルを作成します。追記箇所は太字にしています。この追記によりPostgreSQLのユーザー名がpostgresになります。また、今回は動作確認のため、testpasswordというセキュリティ強度の低いパスワードを使用していますが、本番用途で使用する場合はセキュリティ強度の高いパスワードを設定する必要があります。
リスト4:
2 | - name: POSTGRES_PASSWORD |
4 | <b>- name: POSTGRES_USERNAME</b> |
5 | <b> value: postgres</b> |
作成したexample-postgres.yamlを使用して、PostgreSQLを作成します。
リスト5:
1 | $ kubectl apply -f example-postgres.yaml |
そして、Keycloakが作成されたPostgreSQLに接続するために、PostgreSQLのユーザー名とパスワードをSecretに設定します。これでKeycloakの設定格納用の外部DBの設定が完了しました。
リスト6:
1 | $ kubectl create secret generic keycloak-db-secret --from-literal=username=postgres --from-literal=password=testpassword |
次に、TLSで通信を暗号化するため、証明書と鍵を作成し、Secretに設定します。今回は動作確認のため証明書には、自己署名証明書を使用しますが、本番用途の場合、認証局から取得した証明書を使用することを推奨します。
リスト7:
1 | $ openssl req -subj '/CN=test.keycloak.org/O=Test Keycloak./C=US' -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem |
2 | $ kubectl create secret tls example-tls-secret --cert certificate.pem --key key.pem |
これでKeycloakをデプロイする準備が完了したので、Keycloakをデプロイします。こちらのページに記載があるexample-kc.yamlを使用してKeycloakをデプロイします。
リスト8:
1 | $ kubectl apply -f example-kc.yaml |
以下のコマンドを実行して、正しい応答が返ってきたらKeycloakのデプロイが完了していることになります。
リスト9:
01 | $ kubectl get keycloaks/example-kc -o go-template='{{range .status.conditions}}CONDITION: {{.type}}{{"\n"}} STATUS: {{.status}}{{"\n"}} MESSAGE: {{.message}}{{"\n"}}{{end}}' |
08 | CONDITION: RollingUpdate |
Keycloakのデプロイが完了したら、Keycloakの名前解決の設定をし、KeycloakのIngressにアクセスできるようにします。まずはMinikubeのIPアドレスを確認します。
そして/etc/hostsファイルに以下を追記し、名前解決ができるように設定します。
リスト11:
1 | <MinikubeのIPアドレス> test.keycloak.org |
以上で、Keycloakの管理コンソール(https://test.keycloak.org/admin)にアクセスできるようになったので、ブラウザを使ってアクセスします。アクセスすると、Keycloakのログイン画面が表示されます(図3)。
図3:Keycloakのログイン画面
adminユーザーはKeycloakデプロイ時に作成されており、以下のコマンドでユーザー名とパスワードを確認できるので、表示されたユーザー名とパスワードを入力し、ログインします。
リスト12:
1 | $ kubectl get secret example-kc-initial-admin -o jsonpath='{.data.username}' | base64 --decode |
2 | $ kubectl get secret example-kc-initial-admin -o jsonpath='{.data.password}' | base64 -decode |
ログインに成功するとKeycloakの管理コンソール画面が表示されます(図4)。
図4:Keycloakの管理コンソール画面
シングルサインオンの実現方法
Keycloakをデプロイしたので、Argo CDとGrafanaの認証をKeycloakで実施するように設定します。
Keycloakの設定
本記事における、Argo CDとGrafanaの認証に必要なKeycloakの設定は以下の6つになります。
- レルムの作成
- クライアントの作成
- ユーザーの作成
- レルムロールの作成
- ユーザーのレルムロールの設定
- レルムロールをIDトークンに追加する設定
1.レルムの作成
まずはレルムを作成します。レルムとは、ユーザーやアプリケーションなどを管理するKeycloakにおける名前空間のことを指します。今回は「sso」という名前のレルムを作成します。Keycloakの管理コンソール画面の「master」をクリックし、[Create Realm]ボタンをクリックします。レルム作成画面が表示されるので(図5)、Realm nameに「sso」と入力し、[Create]ボタンをクリックします。これによりssoレルムが作成されます。
図5:レルム作成画面
2.クライアントの作成
先ほど作成したssoレルムにクライアントを作成します。Keycloakにおけるクライアントとは、アプリケーションのことを指します。今回はArgo CDとGrafanaがアプリケーションに該当するので、Argo CD用のクライアントとGrafana用のクライアントを作成します。今回デフォルトの設定から変更するクライアントの設定項目は以下の3つです。
- Client ID
クライアント識別子のことを指します。クライアントに一意の識別子を設定します
- Client authentication
図2の1-⑥と2-⑥のトークンリクエストでクライアント認証が有効か無効かを指します。許可されたクライアントだけがユーザーに関する情報を取得できるようにするため、クライアント認証を有効に設定します
- Valid redirect URIs
クライアントが図 2の1-⑤と2-⑤の認証レスポンスを受け取るURLのことを指します。Argo CDもGrafanaもOIDCに対応しているため、認証レスポンスを受け取るURLは用意されており、そのURLを設定します
まずはArgo CD用のクライアントを作成します。Clientsタブをクリックし、[Create client]ボタンをクリックすると、General Settingsの設定画面が表示されるので(図6)、Client IDに「argo」と入力し、[Next]ボタンをクリックします。これによりクライアント識別子が「argo」に設定されます。
図6:General Settingsの設定画面
[Next]ボタンをクリックすると、Capability configの設定画面が表示されるので(図7)、Client authenticationを「On」に設定し、[Next]ボタンをクリックします。これにより図 2の1-⑥トークンリクエストでクライアント認証が必須になります。
図7:Capability configの設定画面
[Next]ボタンをクリックすると、Login settingsの設定画面が表示されるので(図8、Valid redirect URIsにArgo CDが認証レスポンスを受け取るために用意しているURL「http://argo.minikube/auth/callback」を入力し、[Save]ボタンをクリックします。これにより図2の1-⑤で認証レスポンスが「http://argo.minikube/auth/callback」に送られます。
図8:Login settingsの設定画面
以上で、Argo CD用のクライアントが作成されます。ここで、クライアント認証に必要なArgo CD用のクライアントのクライアントシークレットが自動生成されているので、Credentialsタブグから値を確認し、メモしておきます(図9)。この値は、図2の1-⑥のトークンリクエストのクライアント認証で必要になります。
図9:Credentials画面
次にGrafana用のクライアントを作成します。手順はArgo CD用のクライアントの作成と同じです。ただし、Client IDには「grafana」、Valid redirect URIsにはGrafanaが認証レスポンスを受け取るために用意しているURL「http://grafana.minikube/login/generic_oauth」を設定します。
3.ユーザーの作成
Argo CDとGrafanaにログインするユーザーを作成します。Usersタブをクリックし、[Add user]をクリックすると選択するとユーザー作成画面が表示されるので(図10)、Usernameに「admin」、Emailに「admin@example.com」を入力し、[Create]ボタンをクリックします。
図10:ユーザー作成画面
次に作成したユーザーのパスワードを設定します。Credentialsタブをクリックし、[Set password]ボタンをクリックするとパスワード設定のポップアップ画面が表示されるので(図11)、Passwordに「admin」、Password confirmationに「admin」を入力し、Temporaryに「Off」を設定し、[Save]ボタンをクリックし、[Save password]をクリックします。これによりパスワードが設定され、初回ログイン時のパスワード強制変更機能を無効にしました。また、今回は動作確認のため、adminというセキュリティ強度の低いパスワードを使用していますが、本番用途で使用する場合はセキュリティ強度の高いパスワードを設定する必要があります。
図11:パスワード設定のポップアップ画面
4.レルムロールの作成
レルムロールを作成します。レルムロールとは、ユーザーがレルムに対して持つロールのことを指します。Grafanaには独自のロール(Grafana Admin、Admin、Editor、Viewer)が存在し、ユーザーだけでなく、ロールの管理もKeycloakで行います。今回はGrafanaにAdminロールでログインできるように、Adminロール用のレルムロールを作成します。Realm rolesタブをクリックし、[Create role]ボタンをクリックすると、ロール作成画面が表示されるので(図12)、Role nameに「admin」を入力し、[Save]ボタンをクリックします。これにより、adminレルムロールが作成され、adminレルムロールが付与されたユーザーはGrafanaにAdminロールでログインできるようになります。
図12:ロール作成画面
5.ユーザーのレルムロールの設定
ユーザーのレルムロールの設定をします。今回は先ほど作成したレルムロールをユーザーに付与します。Usersタブ、admin、Role mappingタブ、[Assign role]ボタンの順にクリックすると、ロール割当のポップアップ画面が表示されるので(図13)、adminにチェックを入れ、[Assign]ボタンをクリックします。これによりadminユーザーにadminレルムロールが付与されました。
図13:ロール割当のポップアップ画面
6.レルムロールをIDトークンに追加する設定
レルムロールをIDトークンに追加する設定をします。Grafanaはログインしたユーザーにロールを付与しますが、Keycloakがロールの管理を行っているため、ロールに関する情報をIDトークンに格納してGrafanaに渡す必要があります。そのためには、クライアントがアクセスできるユーザーの情報を定義しているClient scopesの設定が必要になります。今回は以下のようにIDトークンにadminレルムロールが格納されるように設定をします。
Client scopesタブをクリックし、「roles」をクリックすると、「roles」スコープの詳細画面が表示されます(図14)。
図14:「roles」スコープの詳細画面
「roles」スコープの詳細画面が表示されたら、Mappersタブをクリックし、「realm roles」をクリックします。「realm roles」の詳細画面が表示されるので(図15)、Add to ID tokenを「On」に設定し、[Save]ボタンをクリックします。これでIDトークンにユーザーのレルムロールが追加されます。
図15:「realm roles」の詳細画面
以上でArgo CDとGrafanaの認証に必要なKeycloakの設定が完了しました。
Argo CDのデプロイ
次に、Argo CDをMinikube上にデプロイします。いくつかデプロイ方法はありますが、今回はHelmを使用します。まずはHelmをインストールします。
Helmのインストールが完了したので、Argo CDをデプロイします。まずはリポジトリを追加し、更新します。
次にデプロイ時に設定したいパラメータをargo-customize-values.yamlに記述します。今回はIngressと認証に関する設定を記述します。
リスト16:
16 | clientSecret: <argo用のクライアントのクライアントシークレット> |
21 | oidc.tls.insecure.skip.verify: true |
argo-customize-values.yamlを使用して、Argo CDをデプロイします。
リスト17:
1 | $ helm install argo argo/argo-cd -f argo-customize-values.yaml |
Argo CDのデプロイが完了したので、argo.minikubeの名前解決の設定をし、Argo CDのIngressにアクセスできるようにします。具体的には/etc/hostsファイルに以下を追記します。追記箇所は太字にしています。
リスト18:
1 | <MinikubeのIPアドレス> test.keycloak.org <b>argo.minikube</b> |
名前解決ができるようになったので、Argo CD(http://argo.minikube)にアクセスします。Argo CDにアクセスすると、Argo CDのログイン画面が表示され、[LOG IN VIA KEYCLOAK]ボタンが表示されます。[LOG IN VIA KEYCLOAK]ボタンをクリックすると、Keycloakのログイン画面が表示されます(図16)。
図16:Keycloakのログイン画面
これで、Argo CDがKeycloakに認証を委譲するように設定できました。
Grafanaのデプロイ
次に、GrafanaをMinikube上にデプロイします。Argo CDと同様にHelmを使用してデプロイします。まずはリポジトリを追加し、更新します。
次にデプロイ時に設定したいパラメータをgrafana-customize-values.yamlに記述します。今回はIngressと認証に関する設定を記述します。
リスト20:
07 | check_for_updates: true |
15 | oauth_auto_login: true |
16 | disable_login_form: true |
18 | data: /var/lib/grafana/ |
19 | logs: /var/log/grafana |
20 | plugins: /var/lib/grafana/plugins |
21 | provisioning: /etc/grafana/provisioning |
29 | client_secret: < Grafana用のクライアントのクライアントシークレット> |
30 | scopes: openid,email,profile,roles |
31 | login_attribute_path: username |
35 | role_attribute_path: contains(realm_access.roles[*], 'admin') && 'Admin' || contains(realm_access.roles[*], 'editor') && 'Editor' || 'Viewer' |
36 | tls_skip_verify_insecure: true |
grafana-customize-values.yamlを使用して、Grafanaをデプロイします。
リスト21:
1 | $ helm install grafana grafana/grafana -f grafana-customize-values.yaml |
Grafanaのデプロイが完了したので、grafana.minikubeの名前解決の設定をし、GrafanaのIngressにアクセスできるようにします。具体的には/etc/hostsファイルに以下を追記します。追記箇所は太字にしています。
リスト22:
1 | <MinikubeのIPアドレス> test.keycloak.org argo.minikube <b>grafana.minikube</b> |
名前解決ができるようになったので、Grafana(http://grafana.minikube)にアクセスします。Grafanaにアクセスすると、Keycloakのログイン画面が表示されます(図17)。
図17:Keycloakのログイン画面
これで、GrafanaがKeycloakに認証を委譲するように設定できました。
動作確認
これまでの設定で、Argo CDとGrafanaのシングルサインオンが可能になりましたので、動作確認をします。まずArgo CDにアクセスし、[LOG IN VIA KEYCLOAK]ボタンをクリックします。図16のようにKeycloakのログイン画面が表示されるので、にUsername or emailに「admin」、Passwordに「admin」を入力し、[Sign in]ボタンをクリックします。Argo CDのトップ画面が表示され(図18)、Argo CDにログインできました。
図18:Argo CDのトップ画面
次に、Grafanaにアクセスします。図 17ではKeycloakのログイン画面が表示されましたが、今回はKeycloakのログイン画面が表示されずに、Grafanaにアクセスすることができ、シングルサインオンが実現できていることを確認できました(図19)。
図19:Grafanaのトップ画面
メトリクスの可視化の実現方法
データの可視化ツールであるGrafanaをデプロイしたので、CNCFのPrometheusもデプロイし、Keycloakのメトリクスを可視化します。可視化できるメトリクスにはCPUの使用率、GCの回数、メモリの使用量などがあり、Keycloakの状況が一目でわかり、便利なので早速設定していきます。
Keycloakの設定
まずはKeycloakの設定でメトリクス機能を有効にします。以下のコマンドからカスタムリソースに設定を追記します。追記箇所は太字にしています。
リスト23:
1 | $ kubectl edit keycloak example-kc |
5 | <b> additionalOptions:</b> |
6 | <b> - name: metrics-enabled</b> |
メトリクス機能を有効にしたら、メトリクスエンドポイント(https://test.keycloak.org/metrics)にアクセスし、Prometheusのテキストフォーマットのメトリクスを取得します(図20)。
図20:取得されたメトリクス
これで、メトリクスを取得できるようになりました。
Prometheusのデプロイ
次にPrometheusをMinikube上にデプロイします。Argo CDやGrafanaと同様にHelmを使用してデプロイします。まずはリポジトリを追加し、更新します。
次にデプロイ時に設定したいパラメータをprometheus-customize-values.yamlに記述します。今回はIngressとKeycloakのメトリクスの取得先に関する設定を記述します。
リスト25:
08 | metrics_path: /metrics |
14 | insecure_skip_verify: true |
prometheus -customize-values.yamlを使用して、Prometheusをデプロイします。
リスト26:
1 | $ helm install prometheus prometheus-community/prometheus -f prometheus -customize-values.yaml |
Prometheusのデプロイが完了したので、prometheus.minikubeの名前解決の設定をし、PrometheusのIngressにアクセスできるようにします。具体的には/etc/hostsファイルに以下を追記します。追記箇所は太字にしています。
リスト27:
1 | <MinikubeのIPアドレス> test.keycloak.org argo.minikube grafana.minikube <b>prometheus.minikube</b> |
名前解決ができるようになったので、Prometheus(http://prometheus.minikube)にアクセスし、Status->TargetsからKeycloakのメトリクスエンドポイントがTargetとして設定されていることを確認します(図21)。
図21:Target一覧画面
これで、PrometheusがKeycloakのメトリクスエンドポイントにアクセスし、メトリクスを取得するようになります。
Grafanaの設定
最後にGrafanaのダッシュボードにKeycloakのメトリクスを表示するように設定します。まずはデータソースの設定をします。Grafanaのトップ画面から「DATA SOURCES」をクリックし、データソース追加画面からPrometheusを選択すると、データソースの詳細画面が表示されますので(図22)、Prometheus server URLに「http://< prometheus-serverのCLUSTER-IP>」を入力し、[Save & test]ボタンをクリックします。prometheus-serverのCLUSTER-IPは以下のコマンドから取得できます。
図22:データソースの詳細画面
これでPrometheusに対してクエリを実行できるようになりました。次にダッシュボードを作成します。ハンバーガーボタンから「Dashboards」、[New]ボタン、「New Dashboard」、[+ Add visualization]ボタン、「Prometheus」の順にクリックすると、クエリを作成する画面が表示されます(図23)。
図23:クエリ作成画面
図23の下のSelect metricで取得したいメトリクスを入力し、[Run queries]ボタンをクリックするとメトリクスがグラフとなって出力されます。図23の右上のTitleにグラフに適したタイトルを入力し、その後、[Apply]ボタンをクリックすると、ダッシュボードに入力したタイトル名のグラフが追加されます。他のメトリクスのグラフもダッシュボードに追加したい場合は[Add]ボタン、[Visualization]ボタンの順にクリックし、グラフを作成することで追加できます。
動作確認
今回はCPU使用率(図24の左上)、GCの回数(図24の右上)とメモリ使用量(図24の左下)をダッシュボードに追加し、可視化しました。
図24:ダッシュボード
今回は紹介しませんが、Grafanaではメトリクスの可視化だけでなく、メトリクスの監視も可能です。メトリクスの監視により、Keycloakに異常があった際には、メールやSlackなどでいち早く管理者に知らせることができます。ぜひ使用してみてください。
第2回では、クラウドネイティブな環境であるコンテナ環境にKeycloakをデプロイし、Keycloakの典型的なユースケースであるシングルサインオンを実現する方法を紹介しました。また、KeycloakをPrometheus、Grafanaと連携させて、Keycloakのメトリクスを可視化しました。次回は、CNCFのOSSと連携してマイクロサービスの認可の構築例を紹介します。