【Keycloak】Realm インポートで「Script upload is disabled」エラーを回避する方法

# 目的

本記事では、Keycloak の Realm インポート時に発生した `Script upload is disabled` エラーの原因と、その対処法について解説します。
特に、Keycloak Client で Authorization 機能が有効化されている場合に注意が必要な点を整理し、再現例とともに解決策を提供します。

# 対象読者

- Keycloak を使用した認証認可基盤を設定・管理しているエンジニア
- Realm 構成のエクスポート・インポート機能によって Keycloak のデータや設定情報を別環境に横展開しようとしている方
- 中級レベルのクラウド／インフラ知識を持つ開発者

# 概要

Keycloak では、CLI または管理 UI から Realm の情報を JSON ファイルとしてエクスポートし、別環境の Keycloak 起動時または起動後にインポートすることで、同一の Realm 構成を複製・再現することができます。
しかし、Realm 内における特定の Keycloak Client で Authorization 機能が有効な状態でエクスポートされたデータをインポートしようとすると、`Script upload is disabled` というエラーが発生し、 JavaScript が読み込まれない問題に遭遇することがあります。
本記事では、このエラーがなぜ発生するのか、どうすれば回避できるのかを詳しく解説します。

# 背景：なぜこの問題が起こるのか
Keycloak で Realm 構成のインポート機能を利用すると、JSON ファイルに含まれる Keycloak Client や Client Scope, Role, User などの設定情報が読み込まれ、対象の Realm 構成を再現することができます。
ただし、インポート対象の Realm 内に **Authorization 機能が有効化された Keycloak Client が存在する場合**、JavaScript で定義されたスクリプトベースのポリシーがセキュリティ上の理由で制限されるため、JSON ファイルの読み込みがブロックされ、`Script upload is disabled` というエラーによって、Realm 構成のインポートが失敗してしまいます。

# 再現例：Docker コンテナでの Keycloak 起動時に Realm 構成のインポートが失敗するケース

例として、以下のように Docker コンテナの起動コマンドを実行し、Keycloak の起動時に JSON ファイルから Realm 構成をインポートするオプションを指定します。

:::note info
インポート対象となる JSON ファイルの作成（Keycloak Realm エクスポート機能の利用）方法は、Keycloak 公式ドキュメントを参照してください。
- [Exporting a Realm to a Directory (Keycloak Official Guides)](https://www.keycloak.org/server/importExport#_exporting_a_realm_to_a_directory)
:::

```bash
# JSON ファイルが格納された `./keycloak/dev/data/import` ディレクトリをコンテナにマウントして
# `--import-realm` オプションで Keycloak 起動時に Realm 構成をインポートさせる
docker run --rm \
  -v ./keycloak/dev/data/import:/opt/keycloak/data/import \
  -e KC_BOOTSTRAP_ADMIN_USERNAME="admin" \
  -e KC_BOOTSTRAP_ADMIN_PASSWORD="password" \
  -p 127.0.0.1:8083:8080 \
  quay.io/keycloak/keycloak:26.2 \
  start-dev --import-realm
```

しばらくすると、`Script upload is disabled` エラーによりコンテナが異常終了し、Keycloak の起動に失敗してしまいます。

```:コンテナログからエラー発生箇所を抜粋
2025-06-21 07:59:56,927 INFO  [org.keycloak.exportimport.util.ImportUtils] (main) Realm 'dev' imported
2025-06-21 07:59:57,044 INFO  [com.arjuna.ats.jbossatx] (main) ARJUNA032014: Stopping transaction recovery manager
2025-06-21 07:59:57,269 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (development) mode
2025-06-21 07:59:57,269 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Script upload is disabled
2025-06-21 07:59:57,269 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.
```

# 解決方法❶：Keycloak Client の Authorization 機能におけるスクリプトベースのポリシーを除去する

ローカルでの開発や検証用途など、比較的セキュリティリスクが低い環境の場合、インポート時のエラー原因となっている Keycloak Client の Authorization 機能におけるスクリプトベースのポリシーを JSON ファイル内から除去することで、容易にエラーを解消することができます。

:::note warn
ポリシーを削除することで、本来必要な Keycloak Client の認可設定が失われてしまうため、本番環境ではこちらの方法を採用しないでください。
:::

```diff_json: インポート対象の JSON ファイルにおけるスクリプトベースのポリシー定義箇所を抜粋
{
  "id" : "d7acc6e8-d346-...",
  "realm" : "dev",
  "clients" : [ {
    "id" : "6c7b0f0a-528c-...",
    "clientId" : "nestjs-bff",
    "authorizationServicesEnabled" : true,
  }, {
    "authorizationSettings" : {
      "allowRemoteResourceManagement" : true,
      "policyEnforcementMode" : "ENFORCING",
      "resources" : [ {
        "name" : "Default Resource",
        "type" : "urn:nestjs-bff:resources:default",
        "ownerManagedAccess" : false,
        "attributes" : { },
        "uris" : [ "/*" ]
      } ],
-      "policies" : [ {
-        "name" : "Default Policy",
-        "description" : "A policy that grants access only for users within this realm",
-        "type" : "js",
-        "logic" : "POSITIVE",
-        "decisionStrategy" : "AFFIRMATIVE",
-        "config" : {
-          "code" : "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
-        }
-      }, {
-        "name" : "Default Permission",
-        "description" : "A permission that applies to the default resource type",
-        "type" : "resource",
-        "logic" : "POSITIVE",
-        "decisionStrategy" : "UNANIMOUS",
-        "config" : {
-          "defaultResourceType" : "urn:nestjs-bff:resources:default",
-          "applyPolicies" : "[\"Default Policy\"]"
-        }
-      } ],
+      "policies" : [ ],
      "scopes" : [ ],
      "decisionStrategy" : "UNANIMOUS"
    }
  }
```

上記のように JSON ファイルを修正してから再度 Docker コンテナの起動コマンドを実行すると、JSON ファイルから Realm 構成が正常にインポートされ、Keycloak の起動に成功します。

```:コンテナログから Realm インポート実行箇所を抜粋
2025-06-21 08:19:53,632 INFO  [org.keycloak.exportimport.util.ImportUtils] (main) Realm 'dev' imported
2025-06-21 08:19:53,683 INFO  [org.keycloak.services] (main) KC-SERVICES0032: Import finished successfully
```

# 解決方法❷：Keycloak Client の Authorization 機能を無効化する

本番環境など、比較的セキュリティリスクが高い環境の場合は、JSON ファイル内で Keycloak Client の **Authorization 機能自体を一度無効化**することで、Realm 構成インポート時のエラーを解消することができます。

:::note info
Realm インポート時に無効化した Keycloak Client の Authorization 機能については、ポリシーの設定内容等を別途エクスポート・インポートすることで複製・再現可能です。詳細は Keycloak 公式ドキュメントを参照してください。
- [Export and import authorization configuration (Keycloak Official Guides)](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_server_import_config)
:::

```diff_json: インポート対象の JSON ファイルにおける Authorization 機能の設定箇所を抜粋
{
  "id" : "d7acc6e8-d346-...",
  "realm" : "dev",
  "clients" : [ {
    "id" : "6c7b0f0a-528c-...",
    "clientId" : "nestjs-bff",
-    "authorizationServicesEnabled" : true,
-  }, {
-    "authorizationSettings" : {
-      "allowRemoteResourceManagement" : true,
-      "policyEnforcementMode" : "ENFORCING",
-      "resources" : [ {
-        "name" : "Default Resource",
-        "type" : "urn:nestjs-bff:resources:default",
-        "ownerManagedAccess" : false,
-        "attributes" : { },
-        "uris" : [ "/*" ]
-      } ],
-      "policies" : [ {
-        "name" : "Default Policy",
-        "description" : "A policy that grants access only for users within this realm",
-        "type" : "js",
-        "logic" : "POSITIVE",
-        "decisionStrategy" : "AFFIRMATIVE",
-        "config" : {
-          "code" : "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
-        }
-      }, {
-        "name" : "Default Permission",
-        "description" : "A permission that applies to the default resource type",
-        "type" : "resource",
-        "logic" : "POSITIVE",
-        "decisionStrategy" : "UNANIMOUS",
-        "config" : {
-          "defaultResourceType" : "urn:nestjs-bff:resources:default",
-          "applyPolicies" : "[\"Default Policy\"]"
-        }
-      } ],
-      "scopes" : [ ],
-      "decisionStrategy" : "UNANIMOUS"
-    }
  }
```

上記のように JSON ファイルで Keycloak Client の Authorization 機能を無効化（設定箇所を削除）してから再度 Docker コンテナの起動コマンドを実行すると、JSON ファイルから Realm 構成が正常にインポートされ、Keycloak の起動に成功します。

```:コンテナログから Realm インポート実行箇所を抜粋
2025-06-21 08:45:56,041 INFO  [org.keycloak.exportimport.util.ImportUtils] (main) Realm 'dev' imported
2025-06-21 08:45:56,057 INFO  [org.keycloak.services] (main) KC-SERVICES0032: Import finished successfully
```

:::note info
その他の解決策として、管理 UI で Keycloak Client の Authorization 機能を無効化し、Realm 構成のエクスポート機能で JSON ファイルを再作成する方法でも解決可能です。
![Keycloak Client の Authorization 機能を無効化するための管理 UI 画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357086/00aafe6f-286f-48ac-93bf-a082ec59d34c.png)
:::

# まとめ

Keycloak における Realm 構成インポート時の `Script upload is disabled` エラーは、Realm 内の特定 Keycloak Client における Authorization 機能のポリシーが原因で発生することがあります。
この問題を避けるためには、Authorization 機能からスクリプトベースのポリシーを削除、または Authorization 機能自体を無効化し、JSON ファイルに設定情報が含まれていない状態で Keycloak にインポートすると解決できます。
環境の再現性を保ちつつ、安全かつ確実に Keycloak の Realm 構成を複製・移行するための一助となれば幸いです！

# 参考リンク

- Realm 構成エクスポート・インポート機能の利用方法を解説した Web サイト
  - [Keycloakをdockerで動かしてレルムをエキスポートする (Qiita)](https://qiita.com/tinsep19/items/a65b6149c43b611f391c)
  - [Exporting a Realm to a Directory (Keycloak Official Guides)](https://www.keycloak.org/server/importExport#_exporting_a_realm_to_a_directory)
- Realm 構成インポート時のエラー原因調査に役立った Web サイト
  - [Keycloak – Script upload is disabled while importing a realm (HowToDoInJava)](https://howtodoinjava.com/devops/keycloak-script-upload-is-disabled/)
  - ["Script upload is disabled" when using realm import file (GitHub)](https://github.com/dasniko/testcontainers-keycloak/issues/83#issuecomment-2309650108)