KeycloakがActive Directoryに登録されたユーザで認証できるようにする


社内システムを立ち上げるにあたり、前の会社ではWebシステム毎にログインしていて嫌気がさしてたので、是非ともシングルサインオンにしたいと思った。その実現に、昔ちょっとだけ評価したOpenAMとかの情報をググり漁り始めたら、Keycloakの情報の方が目についたので、新しいものに流されやすいのでKeycloakの勉強を始めました。
とは言え、Keycloakに全社員のアカウント情報を登録するのは面倒なので、既存のActive Directoryと連携させる方法を試してみました。

構成

プロトコルは本来、HTTPSとLDAPSでなければならないけど、それは次のステップということで安易なまま。

Active Directoryサーバ

LDAPとして情報を確認するのに、こちらで紹介されていた、Windows Serverに元からあるLDPを使用した。

Keycloakサーバ

構築

Docker Composeで、ちょちょいと。

version: '3'
services:
  keycloak:
    image: jboss/keycloak
    environment:
      DB_VENDOR: POSTGRES
      DB_ADDR: postgres
      DB_DATABASE: keycloak
      DB_USER: keycloak
      DB_SCHEMA: public
      DB_PASSWORD: password
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: password
    ports:
      - 50000:8080
  postgres:
    image: postgres
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: password

お試しなのでDBの永続化をしていません。
なお、この時のkeycloakは6.0.1、PostgreSQLは11.3でした。

設定

  1. Realmを作成。
  2. User Federationを選択。
  3. Add provider...でLDAPを選択。
  4. 開いた画面で以下の項目を設定してSave。

    項目 備考
    Console Display Name ${任意の名前}
    Import Users OFF ONだとActive DirectoryからKeycloak内にアカウント情報をコピーするようだが、今回は認証できるか確認するだけなのでOFF。
    Edit Mode READ_ONLY 安全のため、Keycloak側で行ったアカウント情報の更新がActive Directory側に反映されないようにした。
    Vendor Active Directory
    Username LDAP attribute sAMAccountName
    Connection URL ldap://${Active Directoryサーバのホスト名}
    Users DN ${LDPで調べたユーザが登録されているDN}
    Bind DN ${LDPで調べた自アカウントのDN}
    Bind Credential ${自アカウントのパスワード}

    ${}は環境依存の値。
    Import Usersで、
    Edit ModeをREAD_ONLYにすると、

  5. 同画面のMappersタブを開き、usernameを選択。LDAP AttributeをsAMAccountNameに変更する。

  6. あとはClientsでWebアプリ用の設定を登録。Client Protocolはデフォルトのopenid-connectのままで、Client IDにsample-keycloakと、Root URLにWebアプリのURLを指定。

Webアプリ

Spring Bootで作成。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>quo.vaids.megasys</groupId>
    <artifactId>sample-keycloak</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sample-keycloak</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-2-starter</artifactId>
            <version>4.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
application.yml
keycloak:
  realm: ins.local
  auth-server-url: http://${Keycloakが動いている}:50000/auth
  resource: sample-keycloak
  public-client: true
  security-constraints:
    - securityCollections:
        - patterns:
            - /*
      authRoles:
        - uma_authorization

あとはsrc/main/resources/staticにindex.htmlを置いた。これでsecurity-constraintsで/
*を指定しているのでWebアプリにアクセスすればKeycloakにリダイレクトされる。

この時、Active Directory側にはロールに該当する情報が存在しないが、authRolesを指定しないとアクセス制限がかからないので悩んだ。が、Keycloak側でRelmのデフォルトとしてoffline_accessとuma_authorizationロールを割り当てているのに気が付き、これを指定した。

動作確認

WebアプリにアクセスするとKeycloakにリダイレクトされ、アカウント情報を入力すると、正常にindex.htmlが表示された。

なお、実際にはLDAP AttributeをsAMAccountNameに変更するのを知らず、アカウント情報を入力してもエラーとなった。

Keycloakのログを見ると

KC-SERVICES0013: Failed authentication:
org.keycloak.models.ModelException:
User returned from LDAP has null username!
Check configuration of your LDAP mappings.

が出て、解決まで時間がかかりました。