mrparkers / terraform-provider-keycloak

Terraform provider for Keycloak
https://registry.terraform.io/providers/mrparkers/keycloak/latest/docs
MIT License
612 stars 300 forks source link

wrong parentId for realm's components when creating new realm with terraform #802

Open pescobar opened 1 year ago

pescobar commented 1 year ago

I have realized that the provider is not defining the right parentId for the realm components when creating new realms.

I tested it with keycloak 19.0.3 and 20.0.3. You can reproduce the problem like this:

First boot a keycloak test instance listening in http://localhost:8080 with username admin and password admin:

$> docker run -p 8080:8080 -e KEYCLOAK_ADMIN='admin' -e KEYCLOAK_ADMIN_PASSWORD='admin' quay.io/keycloak/keycloak:19.0.3 start-dev

Then you can create a new realm using this terraform code:

terraform {
  required_providers {
    keycloak = {
      source = "mrparkers/keycloak"
      version = "4.1.0"
    }
  }
}

provider "keycloak" {
    client_id     = "admin-cli"
    username      = "admin"
    password      = "admin"
    url           = "http://localhost:8080"
}

resource "keycloak_realm" "myrealm" {
  realm           = "myrealm"
}

If you query the components for the new realm myrealm created with terraform you get this:

$> mastertoken=$(curl -s -k -g -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" -d "client_secret=" "http://localhost:8080/realms/master/protocol/openid-connect/token" | sed 's/.*access_token":"//g' | sed 's/".*//g')

$> curl -s -k -X GET http://localhost:8080/admin/realms/myrealm/components/ -H "Content-Type: application/json" -H "Authorization: bearer $mastertoken" |jq .|grep parent
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",

But if I create another realm named anotherrealm using the keycloak webui the parentIDs for the components are in different format:

$> mastertoken=$(curl -s -k -g -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" -d "client_secret=" "http://localhost:8080/realms/master/protocol/openid-connect/token" | sed 's/.*access_token":"//g' | sed 's/".*//g')

$> curl -s -k -X GET http://localhost:8080/admin/realms/anotherrealm/components/ -H "Content-Type: application/json" -H "Authorization: bearer $mastertoken" |jq .|grep parent
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",
    "parentId": "7c3174e1-13fb-4d97-a6e1-86e4f4250cf2",

I noticed this problem because I tried to import an existing realm which was created using the webui into terraform and when I tried to add a new resource of type keycloak_realm_keystore_rsa the parentID was wrong. This is the output I get when I query the components for it, the only component with different parentID is the rsa key I created using terraform. The other realm components with parentID in format 3c4726c8-3589-41fd-b58e-6a289c062811 were created when I created the realm using the webui

 curl -s -k -X GET https://mykeycloak.com/admin/realms/scicore/components/ -H "Content-Type: application/json" -H "Authorization: bearer $mastertoken" |jq .|grep -i parent
    "parentId": "3c4726c8-3589-41fd-b58e-6a289c062811",
    "parentId": "3c4726c8-3589-41fd-b58e-6a289c062811",
    "parentId": "3c4726c8-3589-41fd-b58e-6a289c062811",
    "parentId": "3c4726c8-3589-41fd-b58e-6a289c062811",
    "parentId": "3c4726c8-3589-41fd-b58e-6a289c062811",
    "parentId": "scicore",
    "parentId": "3c4726c8-3589-41fd-b58e-6a289c062811",

Terraform succeeded and the new rsa key resource is added to the terraform state but it's not visible in the keycloak webui.

I also tried to define realm_id = 3c4726c8-3589-41fd-b58e-6a289c062811 for resource keycloak_realm_keystore_rsa in my terraform code in case this could workaround the problem but then I get this error:

Error: error sending POST request to /admin/realms/3c4726c8-3589-41fd-b58e-6a289c062811/components: 404 Not Found. Response body: {"error":"Realm not found."}

  on 001-realm-scicore.tf line 87, in resource "keycloak_realm_keystore_rsa" "scicore_realm_rsa_key":
  87: resource "keycloak_realm_keystore_rsa" "scicore_realm_rsa_key" {

p.s. The token in $mastertoken is only valid for 1min so make sure to refresh it when testing using curl

pescobar commented 1 year ago

I have done some more testing and I noticed that if I create all the resources using terraform (new resources keycloak_realm and keycloak_realm_keystore_rsa) then the new RSA key I add with terraform is visible in the keycloak webui even if the parentId format uses the realm name instead of the realm internal id.

This is the API output for a realm+rsa key created with terraform which is visible from the webui:

$> mastertoken=$(curl -s -k -g -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" -d "client_secret=" "http://localhost:8080/realms/master/protocol/openid-connect/token" | sed 's/.*access_token":"//g' | sed 's/".*//g')

$> curl -s -k -X GET http://localhost:8080/admin/realms/myrealm/components/ -H "Content-Type: application/json" -H "Authorization: bearer $mastertoken" |jq .|grep parent
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",
    "parentId": "myrealm",

For resources created from scratch using terraform the terraform state uses the same value for id and internal_id

$> terraform state show keycloak_realm.myrealm|grep myrealm
# keycloak_realm.myrealm:
resource "keycloak_realm" "myrealm" {
    id                                       = "myrealm"
    internal_id                       = "myrealm"
    realm                                = "myrealm"

but for realms created using the webui and then imported into terraform the id and internal_id don't match:

$> terraform import keycloak_realm.anotherrealm anotherrealm

$> terraform state show keycloak_realm.anotherrealm |egrep "another|internal_id"
# keycloak_realm.anotherrealm:
resource "keycloak_realm" "anotherrealm" {
    id                                       = "anotherrealm"
    internal_id                              = "734fb52a-07e7-45a2-b456-21312e57e695"
    realm                                    = "anotherrealm"

The problem seems to be that if I add resources using terraform then parentId = $id for all the components in the realm but if I add resources using the webui parentID = $internal_id and they differ

Is there any possible workaround for this issue?

ToniA commented 1 year ago

I ran into this same issue. I created a new realm manually, and then attempted to add RSA keys using keycloak_realm_keystore_rsa. No errors, Terraform's plan and apply looks good, but nothing gets created under Realm Settings -> Keys.

mrparkers/keycloak version 4.3.1, Keycloak 20.0.5

Ernstsen commented 7 months ago

We are also experiencing this issue with mrparkers/keycloak version 4.4.0 and keycloak 23.0.0

Would it be feasible to simply add the parentId argument to the keycloak_realm_keystore_rsa resource, so we can manually pass keycloak_realm.some_realm.internal_id through to the rest request? Or maybe an imported boolean, deciding whether to use realm_id or internal_id, as to not break realms already managed by the provider?