The Problem: Why Realm Duplication Fails

Attempting to clone a Keycloak realm on the same instance, for example, creating a myrealm-dev from an existing myrealm, often results in a frustrating database error. The standard process involves exporting the realm from the Admin Console (Realm settings → Action → Partial export, ensuring clients and groups/roles are included), renaming it in a text editor or during import, and then importing it back. This seemingly straightforward procedure fails with a critical error: ERROR: duplicate key value violates unique constraint "constraint_a" Detail: Key (id)=(51e1a26d-c24f-4454-9a34-708f1fc14917) already exists.

This error occurs because a Keycloak realm export is not merely a configuration file; it's a serialized snapshot of database rows. Every entity within the realm—roles, clients, users, protocol mappers, components, and authentication flows—is exported with its original, unique database identifier (UUID). When you attempt to import this data back into the same Keycloak instance, the database enforces its unique constraints. It detects that the IDs being imported already exist, leading to the failure.

Think of it like trying to copy a book into your personal library, but the ISBNs of the copied books are identical to books you already own. The library system flags this as a duplicate entry, preventing the import. Keycloak's database, similarly, cannot tolerate duplicate primary keys for its entities.

The Solution: Database-Level UUID Regeneration

The only reliable way to clone a realm on the same instance is to modify the exported JSON to generate new, unique IDs for all entities before importing. This process requires direct interaction with the exported JSON and, in some cases, understanding the underlying database structure. Since Keycloak's export format is JSON, we can leverage scripting to achieve this.

Step 1: Export the Realm

Navigate to your Keycloak Admin Console. Go to the realm you wish to clone. Under Realm settings, find the Action dropdown and select Partial export. Crucially, ensure that Include clients, Include groups and roles, and Include users (if applicable) are selected. Download the generated JSON file. This file contains the full configuration and all entity IDs.

Step 2: Process the Exported JSON

The core of the solution lies in transforming the exported JSON. You need to iterate through the JSON structure and replace every UUID that represents a primary key for a Keycloak entity with a newly generated UUID. This includes IDs for realms, clients, roles, groups, users, protocol mappers, authentication flows, and any other database-backed entities.

A common approach is to use a script (e.g., Python, Node.js, or even command-line tools like jq) to parse the JSON. The script should:

  • Read the exported JSON file.
  • Identify all fields that are UUIDs and represent primary keys. Keycloak's export structure provides these directly. For instance, the top-level object has a id field, clients have id, roles have id, groups have id, etc.
  • For each identified UUID, generate a new, random UUID.
  • Replace the original UUID in the JSON with the newly generated one.
  • Save the modified JSON to a new file.

For example, using Python with the uuid and json libraries:

import json
import uuid

def generate_new_uuids(data):
    if isinstance(data, dict):
        for key, value in data.items():
            # Check if the value looks like a UUID and is a key that typically holds an ID
            # This is a simplified example; a real implementation needs to be more robust
            # and potentially aware of specific Keycloak JSON structures.
            if isinstance(value, str) and len(value) == 36 and value.count('-') == 4:
                try:
                    uuid.UUID(value) # Validate if it's a valid UUID format
                    # Replace with a new UUID if it's a known ID field or generally looks like one
                    # A more precise approach would map field names to their expected types/roles.
                    data[key] = str(uuid.uuid4())
                except ValueError:
                    # Not a valid UUID, continue processing nested structures
                    pass
            else:
                # Recursively process nested dictionaries and lists
                data[key] = generate_new_uuids(value)
    elif isinstance(data, list):
        for i, item in enumerate(data):
            data[i] = generate_new_uuids(item)
    return data

# Load the exported realm JSON
with open('exported-realm.json', 'r') as f:
    realm_data = json.load(f)

# Generate new UUIDs for all entities
modified_realm_data = generate_new_uuids(realm_data)

# Save the modified JSON
with open('modified-realm-for-import.json', 'w') as f:
    json.dump(modified_realm_data, f, indent=2)

This script is a simplified illustration. A comprehensive solution would need to be more sophisticated, potentially identifying specific fields that require UUID replacement based on Keycloak's schema or export format. For instance, the realm's top-level id, client IDs, role IDs, group IDs, and user IDs are prime candidates for replacement.

Step 3: Rename the Realm

Before importing the modified JSON, you must change the realm's name to the desired new name (e.g., change myrealm to myrealm-dev). This is typically done by editing the realm field in the modified JSON file. Ensure the new name is unique and doesn't conflict with existing realms.

Step 4: Import the Modified Realm

Now, go back to the Keycloak Admin Console. Select the master realm (or the realm from which you are managing other realms). Navigate to Realm settings and find the Import realm action. Upload your modified JSON file. Keycloak will now import the realm using the newly generated IDs, avoiding the duplicate key constraint error.

Considerations and Alternatives

While this database-level manipulation is effective, it's a manual and potentially error-prone process. It requires careful scripting and validation. It's also important to note that this method bypasses Keycloak's standard API for realm management, interacting directly with its data structures.

Alternative approaches might include:

  • Using Keycloak's REST API for creation: Instead of exporting and importing, one could theoretically use the Keycloak Admin API to create a new realm and then programmatically copy configurations (clients, roles, users, etc.) from the source realm to the new one. This is significantly more complex as it involves understanding the API endpoints for every entity type and managing dependencies.
  • Leveraging External Tools: Some community-developed tools or scripts might exist that automate this UUID regeneration process. However, relying on third-party tools requires due diligence regarding their maintenance and security.

For developers and administrators who need to quickly spin up identical environments for testing or development, mastering the manual JSON manipulation technique is often the most direct path, despite its technical nature. The key takeaway is that Keycloak's export is a data snapshot, not just a configuration template, necessitating ID regeneration for same-instance duplication.