CLI tool
keycloak/terraform-provider-keycloak avatar
keycloak/terraform-provider-keycloak

terraform-provider-keycloak: managing Keycloak as code

Terraform provider for Keycloak

955 stars451 forksGoApache-2.0

At a glance

What is it?
The keycloak Terraform provider is the first party provider for Keycloak, and the parts worth reading are the operational ones: a documented path to migrate state away from the old mrparkers provider, a stated support window of the latest three Keycloak minor versions, an acceptance test suite that runs against real servers, and a local Docker Compose environment with PostgreSQL, OpenLDAP and a mutual TLS variant for testing.
Who is it for?
Adopt terraform-provider-keycloak when you run Keycloak in more than one environment and want the users, clients and roles described in the same repository as the rest of your infrastructure, since a first party provider with a published version and a migration path is a better bet than an unmaintained one.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A first party provider, with the documentation moved to the registry

terraform-provider-keycloak is the Terraform provider for Keycloak, and the important organisational fact is who maintains it. The repository sits under the keycloak organisation, the licence is Apache-2.0 with a LICENSE-APACHE-2.0 file in the tree, and the package is published as keycloak/keycloak in the Terraform Registry, with the documentation on the registry rather than in the repository. The README says so explicitly, that all documentation for the provider can now be found on the Terraform Registry.

That is the pattern for a provider maintained by the project it serves, and it has practical consequences. The docs are versioned with the provider on the registry, so they match the version you installed, which is better than a README that describes the current development branch. The provider is also built with the standard HashiCorp plugin libraries, so the behaviour of the Terraform integration, the state handling and the diagnostics is the standard one rather than something custom.

The provider is written in Go, and the topic list includes hacktoberfest, which points to how outside contributions are recruited. There is a MAINTAINERS.md in the repository, and a CHANGELOG.md for the version history.

The resources it exposes are the ones a Keycloak deployment is made of. The example directory in the repository shows the shape of the configuration, with main.tf, roles.tf, workflows.tf, client_authorization_policys.tf, a federated user example and an external token exchange example, and there are separate example directories for a custom authorisation policy and a custom user federation provider, which are the two extension points Keycloak has for code that is not built in.

Installing it, and the block you need in your configuration

For Terraform 0.13 and later the provider is installed automatically through the required_providers block:

hcl
terraform {
  required_providers {
    keycloak = {
      source = "keycloak/keycloak"
      version = ">= 5.10.0"
    }
  }
}

The version constraint in the example is a floor rather than a pin, which is a choice with consequences. A floor lets a plan pick up the newest provider, which brings new resources and new bug fixes but also new behaviour, and for a provider whose schema follows the Keycloak version, that can mean a plan that differs between two runs of the same configuration. Pinning to an exact version and bumping deliberately is the safer habit, and the changelog for each version is linked from the README for exactly that purpose.

The older paths are still documented, which is useful when you inherit a configuration. On Terraform 0.12 you can download the provider and place it in one of the implied local mirror directories, and for any provider version below 2.0.0 the old instructions for installing third party plugins still apply. Those are legacy notes, kept in the README because the provider has existed long enough that people are still on those versions.

The migration note is the other piece of installation guidance, and it is the one most teams will need. To migrate from mrparkers/keycloak to keycloak/keycloak, the README says you can use the terraform state replace-provider command:

code
terraform state replace-provider mrparkers/keycloak keycloak/keycloak

This rewrites the state so that the resources are attributed to the new provider without touching the infrastructure they describe. The link to the Terraform documentation for the command is there, and the reason this matters is that the alternative, destroying and recreating the tenant, would take a production identity server offline and lose the identifiers that other systems point at.

The supported version window, and the Quarkus change that broke base paths

The provider states a support policy: it will officially support the latest three minor versions of Keycloak, although older versions may still work.

The versions used when running acceptance tests in CI are listed, and the list is a descending set of nine, from 26.8.0 as the latest through 26.7.5, 26.6.4, 26.5.7, 26.4.7, 26.3.5, 26.2.5, 26.1.4 and 26.0.8.

Testing against nine versions rather than three is a deliberate extra cost, and it is the kind of cost that shows whether a provider is really usable. A Keycloak version upgrade can change the API, and a provider that only tested the newest one would break for everyone a few months later. The consequence for a user is that the provider's behaviour is verified across the versions you are likely to be running, which is what makes a version floor in your configuration safe.

There is one change in Keycloak itself that the README calls out, and it is the kind of detail that costs an afternoon if you hit it cold. Keycloak has been updated to use Quarkus over the legacy Wildfly distribution, and the only significant change affecting this provider is the removal of /auth from the default context path for the Keycloak API.

So if you are still running the legacy Wildfly distribution of Keycloak, you need to set the base_path provider argument to /auth, and the same can be done with the KEYCLOAK_BASE_PATH environment variable. The two ways of doing it are there for different circumstances, one in configuration and one in the environment, and a provider that handles both is saving the operator a configuration change in every environment where the variable is already set.

Releases, checksums and the Alpine caveat

The provider uses GoReleaser to build and publish releases, and each release published to GitHub contains binaries for Linux, macOS with the darwin name, and Windows, as configured in the .goreleaser.yml file in the repository.

Each release also contains a terraform-provider-keycloak version SHA256SUMS file that can be used to check integrity. That is a small line in the README and a meaningful one in practice, since a provider binary runs with the credentials for your identity server, and verifying the checksum is how you know the binary you are about to run is the one the project published.

The Alpine story is the interesting part, because it is a change. Prior to v2.0.0, a statically linked build for use within Alpine Linux was included with each release. This is no longer done, because GoReleaser does not support CGO, and the README explains the consequence and the workaround: instead of a statically linked build you can use the linux_amd64 build as long as libc6-compat is installed.

That is a good example of a downstream decision propagating all the way to the user, since a provider is distributed as a binary and the binary's linking model is set by the release tooling. The version history shows the releases are frequent, with v5.10.0 on 2026-10-05 and v5.9.0 on 2026-07-31, alongside a nightly tag, and the repository is not archived with the last push on 2026-10-19.

The local environment, and the tests that run against real servers

The development section gives a local environment that is closer to production than a mock ever would be, and that is the right choice for this kind of provider.

A local developer environment can be spun up via Docker Compose by running make local, which brings up containers for Keycloak, PostgreSQL and OpenLDAP that can be used for testing the provider. The README says plainly that this environment and its setup via make local is not intended for production use, and there are make local-stop and make local-down targets to stop and remove it. The setup scripts require the jq command line utility.

The compose file in the repository shows what that environment is made of. PostgreSQL 16 with a keycloak database, an OpenLDAP 2.6 container, and Keycloak 26.8.0 from the quay.io registry running with the verbose start-dev command. The Keycloak container is configured with a bootstrap admin account, a Postgres database, and the KC_FEATURES setting of preview and admin-fine-grained-authz:v1, which is the preview features flag together with the fine grained administration authorisation feature, so the acceptance tests can exercise the new authorisation resources. It also mounts the built jar of the custom user federation example into the providers directory, with the :z option so the volume content is shared between the containers, and it mounts the deployed JavaScript authorisation policy, which is what the generic client authorisation resource under test needs.

There is a mutual TLS variant too, make local-mtls, which starts Keycloak with required client authentication via an mTLS certificate, and a make local-mtls script in the repository for the certificates.

The acceptance tests are the reason the environment exists. Every resource supported by the provider will have a reasonable amount of acceptance test coverage, and the tests run against a Keycloak instance with make testacc, given a set of environment variables:

code
KEYCLOAK_CLIENT_ID=terraform
KEYCLOAK_CLIENT_SECRET=884e0f95-0f42-4a63-9b1f-94274655669e
KEYCLOAK_CLIENT_TIMEOUT=5
KEYCLOAK_REALM=master
KEYCLOAK_TEST_PASSWORD_GRANT=true
KEYCLOAK_URL="http://localhost:8080"
make testacc

There are documented variants for the HTTPS port, which adds a KEYCLOAK_TLS_CA_CERT pointing at a certificate in the provider testdata directory, and for HTTPS with mutual TLS, which uses the make local-mtls environment. A provider whose tests run against a real server across nine Keycloak versions is a provider you can upgrade with some confidence.

Debugging the plugin, and what the repository layout says about the code

Debugging a Terraform provider is unusual, because the provider runs as a separate process that Terraform talks to over a plugin protocol, so a normal breakpoint in your IDE does not reach it. The provider documents a remote debugging setup using the make targets build-debug and run-debug, and the steps are specific. You run make build-debug and make run-debug, attach a remote debugger to the printed local address, for example 127.0.0.1:58772, copy the TF_REATTACH_PROVIDERS environment variable that the debugger prints after the attachment, and prepend that variable to your terraform command in a separate terminal.

The README notes that the debugger options are set to wait for a connection, which allows debugging the complete plugin lifecycle, and that Goland users have a preconfigured remote debugger configuration called local debug. The easiest way to try the setup is the bundled example project, with make build-example-debug.

The repository layout describes a substantial codebase. The keycloak directory holds the resource implementations, the provider directory the provider plumbing and its testdata, the helper directory shared helpers, and there is a mutex directory, which suggests the provider deals with serialising access to resources that Keycloak does not let two Terraform runs modify at once. There are scripts, docs, and the example directories for the custom authorisation policy and the custom user federation provider.

The build requirements are stated as Go 1.26 and Terraform 1.15.0, and the project uses Go Modules for dependency management. The dependency list in go.mod is the standard Terraform plugin stack, terraform-plugin-go, terraform-plugin-log, terraform-plugin-sdk/v2 and terraform-plugin-testing for the tests, plus golang-jwt for token handling, go-retryablehttp for the API calls, go-version for version comparisons, and dario.cat/mergo for merging structures.

The project requires Go 1.26 and Terraform 1.15.0 to develop, and the go.mod requires Terraform Plugin SDK v2, which is worth knowing because the SDK v2 line is the one HashiCorp has been moving providers off, so a provider on SDK v2 is on a supported but not the newest footing.

Editorial conclusion

Adopt terraform-provider-keycloak when you run Keycloak in more than one environment and want the users, clients and roles described in the same repository as the rest of your infrastructure, since a first party provider with a published version and a migration path is a better bet than an unmaintained one. It is the wrong tool if you want to manage Keycloak through its own REST API or a configuration-as-code tool built for Keycloak, and the wrong tool if your Keycloak version is older than the supported window, since the provider officially supports only the latest three minor versions. Before adopting, check the version constraint you can write in your configuration, because the provider's own schema moves between Keycloak releases, and read the Quarkus note about the removed /auth context path if you still run the legacy Wildfly distribution.

Frequently asked questions

How do I install the Keycloak Terraform provider?

With Terraform 0.13 or later, add a required_providers block naming the source as keycloak/keycloak, for example with a version constraint of >= 5.10.0. The README also documents the older local mirror approach for Terraform 0.12 and the legacy third party plugin instructions for provider versions below 2.0.0.

How do I migrate from the mrparkers/keycloak provider?

Run terraform state replace-provider mrparkers/keycloak keycloak/keycloak, which rewrites the state so the resources are attributed to the new provider without recreating the Keycloak infrastructure.

Which Keycloak versions does the provider support?

It officially supports the latest three minor versions of Keycloak, although older versions may still work. The acceptance tests in CI run against nine versions, from 26.8.0 as the latest down to 26.0.8.

What changed when Keycloak moved from Wildfly to Quarkus?

The default context path for the Keycloak API no longer includes /auth. If you run the legacy Wildfly distribution you have to set the base_path provider argument to /auth, or set the KEYCLOAK_BASE_PATH environment variable.

How do I run the provider's tests locally?

Start a local environment with make local, which runs Keycloak, PostgreSQL and OpenLDAP in Docker Compose, then run make testacc with the KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_REALM, KEYCLOAK_URL and related variables set. Variants exist for the HTTPS port and for mutual TLS with make local-mtls.

Official sources

  1. keycloak/terraform-provider-keycloak on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/keycloak-terraform-provider-keycloak.svg)](https://hysenlabs.com/projects/keycloak-terraform-provider-keycloak)