Keycloak を使って管理者だけが Node-RED に SSO ログインできるようにした

# Keycloak を使って管理者だけが Node-RED に SSO ログインできるようにした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604208/e2fc51b6-2612-4366-3964-c1f58b264e3f.png)

Node-RED を管理しているメンバーが何人かいるのですが、共用管理者アカウントではなく各自のアカウントで SSO できるようにし、かつ管理者のみにアクセスを限定したかったので対応してみました。


## 前提条件
Keycloak の管理者グループに admin ロールを割り当て、対象ユーザーは管理者グループに所属していることを前提としています。

`try0ut.ml` というドメインで構築しているものとします。


## バージョン

|name | ver.|
|:---| :--- |
|Keycloak| v20.0.2 |
|Node-RED| v3.0.2  |



## 個別ユーザーで SSO ログインできる設定

### [Keycloak] Client scope を作成する

1. `openid` クライアントスコープを追加します。
    - Name: `openid`
    - Type: `Optional`
    - Include in token scope: `ON`
1. 'Save' ボタンを押します。


### [Keycloak] Client を作成する

1. `oidc-nodered` クライアントを追加します。
    - Client type: `OpenID Connect`
    - Client ID: `oidc-nodered`
    - Client authentication: `ON`
    - Valid redirect URIs: `https://nodered.try0ut.ml/*`
1. 'Save' ボタンを押して、'Credentials' タブが表示されたら **Client secret** をメモしておきます。
1. 'Client scopes' タブに切り替えて、`openid` スコープを追加します。Assign type は、**Default** に設定します。

### [Node-RED] 認証情報を設定する

1. Node-RED のユーザーフォルダ (e.g. /data) に、`passport-keycloak-oauth2-oidc` をインストールしておきます。
    ```bash
    $ npm install passport-keycloak-oauth2-oidc
    ```

1. `settings.js` で adminAuth を設定します。
    
    ```javascript:settings.js
    adminAuth: {
      type: 'strategy',
      strategy: {
        name: 'keycloak',
        label: 'Sign in',
        icon: 'fa-lock',
        autoLogin: 'true',
        strategy: require('passport-keycloak-oauth2-oidc').Strategy,
        options: {
          realm: 'master',
          clientID: 'oidc-nodered',
          clientSecret: '********',
          publicClient: 'false',
          authServerURL: 'https://keycloak.try0ut.ml',
          callbackURL: 'https://nodered.try0ut.ml/auth/strategy/callback',
          verify: function(token, tokenSecret, profile, done) {
            done(null, profile);
          }
        },
      },
      users: [
        {
          username: 'guest', permissions: ['*']
        }
      ]
    },
    ```
    
    - realm: Keycloak の対象レルム（デフォルト: `master`）
    - clientID: Keycloak で作成したクライアントの ID
    - clientSecret: clientID に紐づくシークレット
    - publicClient: `false` (= clientSecret を使用)
    - authServerURL: Keycloak の URL
    - callbackURL: Node-RED の URL + `/auth/strategy/callback`

### [Node-RED] 個別ユーザーでログインする

1. `guest` ユーザーで Keycloak にログインします。
1. Node-RED を開き、**Sign in** ボタンをクリックします。
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604208/e2fc51b6-2612-4366-3964-c1f58b264e3f.png" width=400px />
1. ログインできることを確認します。
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604208/b1c277b5-49d2-ade3-0482-e1970f6df25c.png" width=400px />

## 管理者ユーザーだけが SSO ログインできる設定

### [Keycloak] 管理者ユーザーを登録する
1. administrators グループを作成し、管理者にしたいユーザーを追加します。
1. Role mapping を開き、`admin` ロールを追加します。

### [Keycloak] roles スコープを修正する
1. Client scope から `roles` スコープを開きます。
1. **Include in token scope** が `ON` になっているか確認します。
1. 'Mappers' タブから `client roles` を開き、設定を確認します。
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604208/f518221a-c9da-6584-78ec-70dc935c803a.png" width=400px />
1. 'Mappers' タブから `realm roles` を開き、設定を確認します。ここでは、'Token Claim Name' を `roles` に書き換える必要があります。[^1]
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604208/5e761dc4-2f38-5c6e-c2d4-723f8d8fa05c.png" width=400px />
    [^1]: https://stackoverflow.com/questions/57997377/get-the-user-roles-with-the-keycloak-userinfo-endpoint

### [Node-RED] admin ロールによるログインを許可する
1. `settings.js` で adminAuth を設定します。ベースは、個別アクセスの時の設定を使います。
    1. `verify` を書き換えます。参考元[^2]と違い、**passport-keycloak-oauth2-oidc** では、グループは取れないのでロールを使います。  
    なお、管理者以外はエラーメッセージを表示させてログインできないようにしておきます。

    ```javascript:settings.js
    verify: function(token, tokenSecret, profile, done) {
      if (profile.roles.includes('admin')) {
        profile.username = 'admin';
        done(null, profile);
      } else {
        done(new Error('Operation not permitted.'));
      }
    }
    ```
    
    1. `users` を書き換えます。

    ```javascript:settings.js
    users: [
      {
        username: 'admin', permissions: ['*']
      }
    ]
    ```
    
    [^2]: https://discourse.nodered.org/t/oauth-openid-login-with-keycloak/54144/3

1. 設定が反映されるように Node-RED を再起動します。


### [Node-RED] 非管理者ユーザーでログインを試す

1. `guest` ユーザーで Keycloak にログインします。
1. Node-RED を開き、**Sign in** ボタンをクリックします。
1. エラーメッセージが表示されてログインできないことを確認します。
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604208/e3487f08-2bbe-7bb0-a8fb-4865ac14dbc3.png" width=400px />

### [Node-RED] 管理者ユーザーでログインする

1. `admin` ユーザーで Keycloak にログインします。
1. Node-RED を開き、**Sign in** ボタンをクリックします。
1. ログインできることを確認します。なお、[keycloak] administrators グループに所属する他ユーザーでも admin としてログインできます。