7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Keycloakハンズオン

Last updated at Posted at 2021-01-27

先日社内で開催した勉強会にてKeycloakのハンズオンを行いましたのでその時のテキストを公開します。


Dockerを使ってKeycloakで認証サーバーを建て、WEBサーバーに対してリバースプロキシ方式で認証をかけます。

1. Keycloak作成

早速Keycloakを使って認証サーバーを建てます。

1-1. ネットワーク作成

コンテナ間で通信を行うので、最初にコンテナが所属するネットワークを作成します。

$ docker network create --driver bridge keycloak

1-2. コンテナ作成

Keycloakのコンテナを建てます。Keycloakの開発元がコンテナイメージを提供してくれているので、それを使います。

keycloak.yaml
version: "3"

services:
  keycloak:
    image: jboss/keycloak:12.0.2
    environment:
      KEYCLOAK_USER: administrator
      KEYCLOAK_PASSWORD: "00000000"
    ports:
    - 8080:8080
    networks:
    - keycloak

networks:
  keycloak:
    external: true

KEYCLOAK_USERとKEYCLOAK_PASSWORDは管理コンソールへのログインIDとパスワードです。

1-3. コンテナ起動

$ docker-compose -f keycloak.yaml up -d

1-4. 起動確認

ブラウザを開き、http://localhost:8080にアクセスするとウェルカムページが表示されます。

2. 認証サーバーの設定

Keycloakの設定をしていきます。

2-1. 管理コンソールへのログイン

1-4でアクセスしたウェルカムページのAdministration Consoleをクリックしてください。
ログインページが表示されるので、KEYCLOAK_USERKEYCLOAK_PASSWORDで設定したユーザーIDとパスワードを入力してログインしてください。
ログインに成功すると管理コンソールの画面へ遷移します。

2-2. 日本語化

ひとまず、分かりづらいかと思いますので、日本語化します。
右側にあるタブのThemesをクリックしてください。
Internationalization EnabledONにするとSupported LocalesDefault Localeが表示されます。Default LocalejaにしてSaveボタンを押してください。
日本語に変わらない場合は、右上のAdministrator(もしくはKEYCLOAK_USERで設定した名前)をクリックして、Manage accountをクリックしてください。アカウント管理画面が日本語で表示されたら、セキュリティ管理コンソールに戻るで日本語化した管理画面に遷移します。

2-3. レルムの作成

現在表示されてるのはMasterレルムの管理ページです。レルムというのはKeycloakのルートデータで、それぞれが独立した認証プロバイダとなります。Masterレルムは全てのレルムへのアクセス権をデフォルトで持ってるレルムで、ここにログインすると全てのレルムの管理を行うことができます。
基本的にMasterレルムはKeycloakの管理を行う場所で、ここを認証プロバイダとして使うことはないので、新しいレルムを作りましょう。左のサイドメニューの上にあるMasterにマウスオーバーすると、レルムの追加というボタンが出てくるので押してください。レルムの追加画面に遷移するので、名前にレルム名を入力して作成を押すとレルムが作られます。今回はhandsonで作成します。

2-4. レルムの設定

作成すると、サイドメニューの上のMasterHandson(もしくは設定したレルム名)になってると思います。ここがHandsonレルムの管理ページです。
右側の設定ページの下の方にエンドポイントとあります。そこのOpenIDエンドポイントの設定をクリックしてください。OpenID Connectに必要な各種設定値が記載されたJSONを取得できます。

{
  "issuer": "http://localhost/auth/realms/handson",
  "authorization_endpoint": "http://localhost:8080/auth/realms/handson/protocol/openid-connect/auth",
  "token_endpoint": "http://localhost:8080/auth/realms/handson/protocol/openid-connect/token",,
  "userinfo_endpoint": "http://localhost:8080/auth/realms/handson/protocol/openid-connect/userinfo",
  ...
}

この設定値を取得するためのエンドポイントはOpenID Connectの仕様に定められており、OpenID Connectに準拠してる認証サービスにはこの[ベースURL]/.well-known/openid-configurationというエンドポイントは必ず存在します。例えば、Googleの場合はhttps://accounts.google.com/.well-known/openid-configuration にあります。ここに記述される属性はこちらで定義されています。
この設定値のうち、issuerの値は後で使いますので控えておいてください。
では、いくつか基本的な設定をします。右側のタブのログインをクリックしてください。遷移後の画面で以下をONにします。

  • ユーザー登録
  • パスワード忘れ
  • ログイン状態の保存

以上の設定で、よくあるログインページを表示できるようになります。ONにしたら保存を押してください。

2-5. クライアント作成

認証するアプリ(RP)の情報を登録していきます。左側のサイドメニューからクライアントをクリックしてください。右側の画面に登録されてるクライアントの一覧が表示されたら、右上の作成を押してください。
クライアントの追加画面が表示されたら、クライアントIDを入力して、保存を押してください。今回はnginxとします。

2-6. クライアント設定

クライアントが作成されるとクライアントの設定画面に遷移しますので、セキュアに認証するためにいくつか設定していきます。
まず、アクセスタイプpublicからconfidentialに変えてください。これでクライアントシークレットが発行されます。
次に、有効なリダイレクトURIを入力します。これは認証後にサービスに戻るURIなので、RPとなるサービスのURLになるかと思います。今回はローカルのWEBサーバーなので、http://localhost/*と入れてください。
入力したら一番下の保存を押してください。保存を押すと一番上のタブにクレデンシャルというものが出てきます。クレデンシャルタブに移動するとシークレットというものがあります。これは認証時に使用するクライアントシークレットとなるので控えておいてください。

3. WEBサーバー

WEBサーバーを作成します。Nginxを使用します。

3-1. Nginxコンテナ作成

client.yaml
version: "3"

services:
  nginx:
    image: nginx
    ports:
    - 80:80
    networks: 
    - keycloak

networks:
  keycloak:
    external: true

3-2. コンテナ起動

$ docker-compose -f client.yaml up -d

3-3. 起動確認

ブラウザを開き、 http://localhost にアクセスしてください。
Nginxのウェルカムページが表示されれば問題ありません。

4. 認証プロキシ

Nginxの代わりに認証プロセスを行ってくれるリバースプロキシを建てます。
公式が推奨してるオープンソースのoauth2-proxyを使用します。

4-1. コンテナ作成

docker-composeの設定にプロキシコンテナを追加します。[クライアントシークレット]には先程クライアントの設定ページで控えたシークレットを入れてください。その他、レルム名やクライアント名を変えてる場合は適時置き換えてください。

client.yaml
version: "3"

services:
  nginx:
    image: nginx
    # 80番ポートはプロキシで使うのでnginxから削除
-   ports:
-   - 80:80
    networks: 
    - keycloak

+ proxy:
+   image: quay.io/oauth2-proxy/oauth2-proxy
+   environment:
+     OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
+     OAUTH2_PROXY_COOKIE_SECRET: 01234567890123456789012345678912
+     OAUTH2_PROXY_COOKIE_SECURE: "false"
+     OAUTH2_PROXY_COOKIE_NAME: "oauth2_proxy"
+     OAUTH2_PROXY_EMAIL_DOMAINS: "*"
+     OAUTH2_PROXY_UPSTREAMS: http://nginx/
+     OAUTH2_PROXY_PROVIDER: oidc
+     OAUTH2_PROXY_OIDC_ISSUER_URL: http://keycloak:8080/auth/realms/handson
+     OAUTH2_PROXY_CLIENT_ID: nginx
+     OAUTH2_PROXY_CLIENT_SECRET: [クライアントシークレット]
+     OAUTH2_PROXY_REDIRECT_URL: http://localhost/oauth2/callback
+     OAUTH2_PROXY_SCOPE: openid email profile
+     OAUTH2_PROXY_PASS_ACCESS_TOKEN: "true"
+     OAUTH2_PROXY_PASS_USER_HEADERS: "true"
+     OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER: "true"
+     OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: "true"
+     OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL: "true"
+   ports:
+   - 80:4180
+   networks: 
+   - keycloak

networks:
  keycloak:
    external: true

一個一個説明すると時間がかかるのでポイントだけ説明すると、OAUTH2_PROXY_OIDC_ISSUER_URLには先程のOpenID Connect設定値エンドポイントで控えたissuerのURLを入力します。ただし、このプロキシから見たKeycloakのURLにしてください。docker-composeはサービス名でルーティングできるので、localhostkeycloakに変更します。認証時にリダイレクトされるURLもkeycloakになるので、以下のコマンドでホスト名を追加しておきます。

$ echo 127.0.0.1 keycloak >> /etc/hosts

OAUTH2_PROXY_SCOPEは認証後にRPに与えてほしい操作権限です。openidOpenID Connectによる認証処理の許可、emailprofileはユーザーデータの取得許可です。
OAUTH2_PROXY_UPSTREAMSには認証後にリクエストを流すサーバーを指定します。今回はNginxに渡します。
PASS~の設定は認証後のデータをUpstreamに渡すかどうかのフラグです。
OAUTH2_PROXY_REDIRECT_URLには認証後にリダイレクトしてほしいURLを指定します。oauth2-proxyの標準のコールバックエンドポイントは/oauth2/callbackとなります。

3-2. コンテナ起動

コンテナを起動します。先程起動したNginxが生きてる場合は、ポートが使われてるので、停止してから起動します。

$ docker-compose -f client.yaml down
$ docker-compose -f client.yaml up -d

3-3. 動作確認

ブラウザを開き、 http://localhost にアクセスしてください。
Keycloakのログインページへリダイレクトされます。ユーザーは登録してないので、下の登録からユーザー登録をしてください。ユーザー名は半角英数字にしてください。登録後、入力したユーザー名パスワードでログインしてください。ログインが成功したらNginxのウェルカムページに飛びます。

4. WEBサーバーに飛んでるリクエストの中身を確認

実際に使う時にoauth2-proxyがどのように認証後のデータを投げてくるのか知ってないと、その後の処理ができないので、リクエストの中身を確認してみましょう。httpbinというアプリケーションを使います。

4-1. コンテナ作成

client.yaml
version: "3"

services:
  nginx:
    image: nginx
    networks: 
    - keycloak

+ httpbin:
+   image: kennethreitz/httpbin
+   networks: 
+   - keycloak

  proxy:
    image: quay.io/oauth2-proxy/oauth2-proxy
    environment:
      ...
    ports:
    - 80:4180
    networks: 
    - keycloak

networks:
  keycloak:
    external: true

4-2. Nginxの設定

Nginxがリクエストをhttpbinに流すように設定します。
以下でNginxの設定ファイルを作成します。

nginx/conf.d/www.conf
server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://httpbin/;
    }
}

設定した作成ファイルをNginxのコンテナにマウントします。また、httpbinが起動する前にNginxが起動するのは具合が悪いので依存関係を設定します。

client.yaml
version: "3"

services:
  nginx:
    image: nginx
+   volumes: 
+   - ./nginx/conf.d:/etc/nginx/conf.d
+   depends_on:
+   - httpbin
    networks: 
    - keycloak

  httpbin:
    image: kennethreitz/httpbin
    networks: 
    - keycloak

  proxy:
    image: quay.io/oauth2-proxy/oauth2-proxy
    environment:
      ...
    ports:
    - 80:4180
    networks: 
    - keycloak

networks:
  keycloak:
    external: true

4-2. コンテナ起動

コンテナを起動します。

$ docker-compose -f client.yaml up -d

4-3. 動作確認

ブラウザを開き、 http://localhost/get にアクセスしてください。以下のようなJSONが取得できるはずです。

{
  "args": {},
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "ja,en-US;q=0.7,en;q=0.3",
    "Authorization": "Bearer xxx",
    "Cache-Control": "no-cache",
    "Connection": "close",
    "Cookie": "...",
    "Host": "httpbin",
    "Pragma": "no-cache",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "...",
    "X-Forwarded-Access-Token": "xxx",
    "X-Forwarded-Email": "foo@example.com",
    "X-Forwarded-Preferred-Username": "account_name",
    "X-Forwarded-User": "00000000-0000-0000-0000-000000000000"
  },
  "origin": "0.0.0.0",
  "url": "http://httpbin/get"
}

httpbinに飛んできたリクエストの中身がJSONで返ってきます。oauth2-proxyによって追加されたヘッダーは以下の通りです。

  • Authorization
  • X-Forwarded-Access-Token
  • X-Forwarded-Email
  • X-Forwarded-Preferred-Username
  • X-Forwarded-User

Preferred-UsernameUserの違いは、Preferred-Usernameがログイン認証等にも使われる"ユーザーが設定したユーザーID"で、Userが"認証サービス側が自動的に割り当てているユーザーID"です。

後始末

$ docker-compose -f keycloak.yaml -f client.yaml down
7
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?