Closed chlumper closed 3 years ago
I appreciate the detailed bug description. It helps a lot to reproduce the case and find the error quickly.
Could it be that the CLI needs to refresh the access-token after the creation of the realm?
I tried this and this resolves the error. Godlike hint.
Argh, i do a mistake, the quick fix is in main (https://github.com/adorsys/keycloak-config-cli/commit/e9f86fd79c9be3266312a41c7b2977d3ba1811dc) now, but I will open a PR to have a test for this case.
Thank you very much for fixing the issue so quickly!
Just tested it with the edge
image and everything works as expected now :clap:.
Looking forward to the next release version...
Hello there !
I'm kind of facing the same issue while testing locally with docker and docker-compose on Ubuntu. Not sure if it's relevant to open a new issue, so I'm commenting here for now.
Keycloak: 15.1.1 Keycloak Config CLI: v4.5.0-15.1.1
Both containers are attached to an internal network and are able to reach each another.
I'm trying to inject my JSON realms configuration through keycloak-config-cli, on a fresh new instance of Keycloak with its default out-of-the-box configuration.
Keycloak properly initialize and create its internal database. But config CLI is not able to reach it for some reason:
INFO 1 --- [ main] d.a.k.config.KeycloakConfigApplication : Starting KeycloakConfigApplication v4.5.0 using Java 17.0.1 on ce89b99b38f3 with PID 1 (/app/keycloak-config-cli.jar started by ? in /)
INFO 1 --- [ main] d.a.k.config.KeycloakConfigApplication : No active profile set, falling back to default profiles: default
INFO 1 --- [ main] d.a.k.config.KeycloakConfigApplication : Started KeycloakConfigApplication in 1.053 seconds (JVM running for 1.444)
INFO 1 --- [ main] d.a.k.config.KeycloakConfigRunner : Importing file '/config/realms/00_master-dev-realm-export.json'
INFO 1 --- [ main] d.a.k.config.provider.KeycloakProvider : Wait 120 seconds until http://keycloak.docker:8080/auth is available ...
ERROR 1 --- [ main] d.a.k.config.KeycloakConfigRunner : Could not connect to keycloak in 120 seconds: HTTP 403 Forbidden
INFO 1 --- [ main] d.a.k.config.KeycloakConfigRunner : keycloak-config-cli running in 02:00.150.
If I curl Keycloak instance from config CLI, it's reachable:
# curl -L -I http://keycloak.docker:8080/auth
HTTP/1.1 303 See Other
Connection: keep-alive
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Location: http://keycloak.docker:8080/auth/
Referrer-Policy: no-referrer
Content-Length: 0
Date: Wed, 22 Dec 2021 16:41:14 GMT
HTTP/1.1 200 OK
Cache-Control: no-cache, must-revalidate, no-transform, no-store
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Referrer-Policy: no-referrer
Content-Security-Policy: frame-src 'self'; frame-ancestors 'self'; object-src 'none';
Date: Wed, 22 Dec 2021 16:41:15 GMT
Connection: keep-alive
X-Robots-Tag: none
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Content-Type: text/html;charset=utf-8
Content-Length: 4076
The only way I found to make it work is to change Keycloak's master realm setting SSL_REQUIRED from "EXTERNAL" to "NONE", then configuration is properly applied by config CLI.
My docker-compose.yml file looks like this:
keycloak-config-cli:
container_name: keycloak-config-cli
image: quay.io/adorsys/keycloak-config-cli:v4.5.0-15.1.1
depends_on:
keycloak:
condition: service_healthy
volumes:
- ./.docker/keycloak-config-cli/config:/config
networks:
- external
- internal
env_file:
- .env
And relevant env vars:
KEYCLOAK_URL=http://keycloak.${INTERNAL_DOMAIN}:8080/auth
KEYCLOAK_USER=admin
KEYCLOAK_PASSWORD=secret
KEYCLOAK_SSLVERIFY=false
The only way I found to make it work is to change Keycloak's master realm setting SSL_REQUIRED from "EXTERNAL" to "NONE", then configuration is properly applied by config CLI.
Thats the reason here. I can see a http:// URL is configured here. If you are trying to login through http://, then keycloak would deny this request.
INFO 1 --- [ main] d.a.k.config.provider.KeycloakProvider : Wait 120 seconds until http://keycloak.docker:8080/auth is available ...
ERROR 1 --- [ main] d.a.k.config.KeycloakConfigRunner : Could not connect to keycloak in 120 seconds: HTTP 403 Forbidden
The curl request in you example return 200 but keycloak-config-cli does not do a simple GET / request. It constantly tries to authenticate, which already result in a 403 forbidden error.
From my point of view. Your issue is a different one compared to the original one.
Instead using the internal URL, you may need to use the external URL of Keycloak.
Thank you for the very quick reply and for your explanation and advice.
Makes total sense, guess I was expecting Keycloak to know it's on an internal network, but from its side it's still an external request which has to be secured. It would certainly work if I could reach it from localhost.
Checkout compose network_mode
https://docs.docker.com/compose/compose-file/compose-file-v3/#network_mode
You can configure that the keycloak-config-cli container will join the keycloak network namespace. If both containers share the same namespace, then you can reach keycloak via localhost.
Oh nice! I'll look into it, I didn't know you could actually do that.
I found another way around this, that I'm sharing here as well.
According to Keycloak documentation:
external requests:: Users can interact with Keycloak without SSL so long as they stick to private IP addresses such as localhost, 127.0.0.1, 10.x.x.x, 192.168.x.x, and 172.16.x.x. If you try to access Keycloak without SSL from a non-private IP address, you will get an error.
So I just changed my docker internal network subnet and now Keycloak config CLI can reach it like it would if it was on a same network namespace:
networks:
internal:
driver: bridge
internal: true
ipam:
config:
- subnet: 172.16.0.0/16
gateway: 172.16.0.1
I guess it's something like this
keycloak-config-cli:
container_name: keycloak-config-cli
image: quay.io/adorsys/keycloak-config-cli:v4.5.0-15.1.1
...
network_mode: "service:keycloak"
and remove the networks
from that service completly.
Looks like you found already a alternative solution.
The original issue is still reproducible with almost the same setup as @chlumper mentioned.
Environment setup:
- Kubernetes
- Keycloak 15.0.2 & Postgres as a persistence (both running in namespace A)
- Keycloak Config CLI v4.5.0 (running in the namespace B)
Initially, the target realm was created by Keycloak Config CLI v4.3.0 and it (CLI tool) was restarted multiple times during the releases with no issues at all. The problem came up when the Keycloak & Postgres were restarted (data anyways was stored in the volume so no data loss was faced).
I tried the approach suggested by @jkroepke to turn off SSL validation via Web UI in the Realm settings (Realm Settings > Login > Require SSL - none
), but it didn't make it work. I do believe that SSL has nothing to do with it since all IP addresses inside the Kubernetes are private (10...* mask)
I collected HTTP logs of the request that got denied (cleaned up from sensitive info):
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> GET /auth/admin/realms/my-realm HTTP/1.1
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> Accept: application/json
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> Authorization: Bearer TOKEN
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> Cookie: KC_RESTART=
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> Host: keycloak.namespace-name.svc.cluster.local:8080
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> Connection: Keep-Alive
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.13 (Java/11.0.11)
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 >> "GET /auth/admin/realms/my-realm HTTP/1.1[\r][\n]"
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 >> "Accept: application/json[\r][\n]"
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 >> "Authorization: Bearer TOKEN[\r][\n]"
2022-01-12 16:32:09.804 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 >> "Cookie: KC_RESTART=[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "HTTP/1.1 403 Forbidden[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "X-XSS-Protection: 1; mode=block[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "X-Frame-Options: SAMEORIGIN[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "Referrer-Policy: no-referrer[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "Date: Wed, 12 Jan 2022 16:32:09 GMT[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "Connection: keep-alive[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "Strict-Transport-Security: max-age=31536000; includeSubDomains[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "X-Content-Type-Options: nosniff[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "Content-Type: application/json[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "Content-Length: 25[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "[\r][\n]"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.wire : http-outgoing-0 << "{"error":"unknown_error"}"
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << HTTP/1.1 403 Forbidden
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << X-XSS-Protection: 1; mode=block
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << X-Frame-Options: SAMEORIGIN
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << Referrer-Policy: no-referrer
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << Date: Wed, 12 Jan 2022 16:32:09 GMT
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << Connection: keep-alive
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << Strict-Transport-Security: max-age=31536000; includeSubDomains
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << X-Content-Type-Options: nosniff
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << Content-Type: application/json
2022-01-12 16:32:09.807 DEBUG 7 --- [ main] org.apache.http.headers : http-outgoing-0 << Content-Length: 25
The payload part of the token which was used by Keycloak Config CLI and got the 403 code.
{
"exp": 1642005189,
"iat": 1642005129,
"jti": "104d8fb4-062f-435c-a53e-d352fb4a267e",
"iss": "http://keycloak.namespace-name.svc.cluster.local:8080/auth/realms/master",
"sub": "uuid",
"typ": "Bearer",
"azp": "keycloak-loader-client",
"acr": "1",
"realm_access": {
"roles": [
"create-realm"
]
},
"scope": "profile email",
"clientId": "keycloak-loader-client",
"email_verified": false,
"clientHost": "10.193.22.137",
"preferred_username": "service-account-keycloak-loader-client",
"clientAddress": "10.193.22.137"
}
Hi,
by reading the logs here, the error is a different one.
The author issue is around authentication/login. But you login clearly works. SSL or Hostname restrictions are not effected here. You gain an error 403 by access the realm my-realm
.
Can you verifiy, the CLI users has enough permissions? create-realm
is able to create realms, but not able to read existing one.
"realm_access": {
"roles": [
"create-realm"
]
},
The problem came up when the Keycloak & Postgres were restarted
Feels like, a users is created, then the users permission maybe modified but old permissions remains in a cache. Since the cache of keycloak is not persistent, A restart of Keycloak clear the cache.
Thanks, @jkroepke!
Yes, adding the admin
role to the service account used by Config CLI fixed the issue, thanks!
The other problem here is that setting an administrative role to the service account might be a security concern since there is a gap between just creating a realm and administrating everything from the master realm.
Do you have any recommendations on the role set for this case?
Do you have any recommendations on the role set for this case?
My Keycloak knowledge in this corner is very rare. Looks like Keycloak is missing a global level view (or auditor role).
As I know, after realm creation, there is a client in the master realm named <realm-name>-realm
and you can consume the view-realm
role here. but thats a 2 step import here, since this is only possible after the realm is created (and the cli client needs permissions inside the master realm)
Anyway the fine-grained authorization policies in Keycloak maybe fits better here, but I don't have any knowledge here.
I did a reset cache for all realms on the Keycloak manually via the Web UI and restarted Keycloak Config CLI without the admin role - it worked without the 403 error.
Later on, restarted Keycloak & Postgres pods and later the Config CLI tool as well - the issue was reproduced...
Btw, restarting Config CLI tool for the same pod (instance) works without any additional actions all the time.
One more, I played around with assigning roles to the master-realm
including view-realm, query-realms, manage-realm
, but it didn't help. The only thing that fixed the issue was to add the master realm admin
role. Keycloak is so finicky sometimes, haha
About the two-steps import, interesting idea but seams to be very complicated. By default, I have a file of master realm which has only credentials for the Keycloak Congig CLI without any additional details on other realms. The idea here is that Config CLI can login into the master realm with pre-created realm and later create/edit any realm it wants to
I played around with assigning roles to the master-realm
But this affects only the master realm itself, for my-realm
realm, there should be a my-realm-realm
client.
https://www.keycloak.org/docs/latest/server_admin/#global-roles
Users with the create-realm role are allowed to create new realms. They will be granted full access to any new realm they create.
I guess this is, what you want and expect. Maybe keycloak we grant such permissions, but keycloak-config-cli will revoke them again. because the permissions are not defined in the json.
Users with the create-realm role are allowed to create new realms. They will be granted full access to any new realm they create.
That's a nice point!
I guess this is, what you want and expect. Maybe keycloak we grant such permissions, but keycloak-config-cli will revoke them again. because the permissions are not defined in the json.
I don't think that's the case. In my situation, Config CLI has nothing to do with the permissions as it persisted in the master realm, not the target one, so I do believe all the permissions/roles are to be saved in the master realm.
But I will check your assumption, I will try to change the properties to keep all the configurations:
import.managed.client-scope-mapping=no-delete
import.managed.role=no-delete
Otherwise, you have to use a user (grant_type=password) to archive this, because grant_type=client_credentials together with the realm role create-realm does not work.
In case, it works with a user instead a client, its one more ticket again.
So, I tried different combinations, all my results are in the table below.
To make it all clear, I set all the import.managed.<resource>
to be 'no-delete' to make sure that Config CLI won't delete it.
The reason I was adding/removing token exchange is that I found a different topic on the Keycloak Discussions saying that if the Policy Enforcer is enabled (in my case it was for the token exchange policy) - the topic starter was getting 403: https://keycloak.discourse.group/t/keyclock-return-403-instead-of-401-for-unauthenticated-requests-when-enabling-policy-enforcer-config-when-removing-policy-enforcer-config-it-returns-401/11336 , so it was more just to make sure.
Credentials type used | Token exchange enabled | Got the 'forbidden' error? |
---|---|---|
client_credentials | yes | yes |
client_credentials | no | yes |
password | yes | yes |
password | no | yes |
No clue whats going on here. I'm not able to reproduce your error...
I tried to test this on my local machine, here is my docker run:
docker run -eKEYCLOAK_USER=admin -eKEYCLOAK_PASSWORD=admin123 -p8080:8080 --rm -v $PWD/data:/opt/jboss/keycloak/standalone/data/ -ti jboss/keycloak:16.1.0
Then I create a service account
Then I create an additional realm.json
java -jar target/keycloak-config-cli.jar --spring.profiles.active=dev --keycloak.grant-type=client_credentials --keycloak.client-id=config-cli-master --keycloak.client-secret=config-cli-master-secret --import.path=realm.json --import.force=true
Logs. Between second and third run, I restart the Keycloak.
jkr@joe-nb keycloak-config-cli % java -jar target/keycloak-config-cli.jar --spring.profiles.active=dev --import.path=./src/test/resources/import-files/service-account/00_update_realm_create_service_account_in_master_realm.json
2022-01-13 22:19:08.038 INFO 84692 --- [ main] d.a.k.config.KeycloakConfigApplication : Starting KeycloakConfigApplication v4.5.1-SNAPSHOT using Java 11.0.13 on joe-nb with PID 84692 (/Users/jkr/IdeaProjects/keycloak-config-cli/target/keycloak-config-cli.jar started by jkr in /Users/jkr/IdeaProjects/keycloak-config-cli)
2022-01-13 22:19:08.040 INFO 84692 --- [ main] d.a.k.config.KeycloakConfigApplication : The following profiles are active: dev
2022-01-13 22:19:08.489 INFO 84692 --- [ main] d.a.k.config.KeycloakConfigApplication : Started KeycloakConfigApplication in 0.961 seconds (JVM running for 1.345)
2022-01-13 22:19:09.442 INFO 84692 --- [ main] d.a.k.config.KeycloakConfigRunner : Importing file '/Users/jkr/IdeaProjects/keycloak-config-cli/./src/test/resources/import-files/service-account/00_update_realm_create_service_account_in_master_realm.json'
2022-01-13 22:19:11.248 DEBUG 84692 --- [ main] d.a.k.config.service.RealmImportService : Updating realm 'master'...
2022-01-13 22:19:11.688 DEBUG 84692 --- [ main] d.a.k.c.service.ClientImportService : Create client 'config-cli-master' in realm 'master'
2022-01-13 22:19:11.889 DEBUG 84692 --- [ main] d.a.k.config.service.UserImportService : Update user 'service-account-config-cli-master' in realm 'master'
2022-01-13 22:19:12.146 DEBUG 84692 --- [ main] d.a.k.config.service.UserImportService : Add realm-level roles [uma_authorization, offline_access, create-realm] to user 'service-account-config-cli-master' in realm 'master'
2022-01-13 22:19:12.301 DEBUG 84692 --- [ main] d.a.k.config.service.UserImportService : Add client-level roles [view-profile, manage-account] for client 'account' to user 'service-account-config-cli-master' in realm 'master'
2022-01-13 22:19:12.588 DEBUG 84692 --- [ main] d.a.k.config.service.state.StateService : Updated states of realm 'master'
2022-01-13 22:19:12.708 DEBUG 84692 --- [ main] d.a.k.c.s.checksum.ChecksumService : Updated import checksum of realm 'master' to '788a04976262da5ee127a22181311afc6786bfd57957f8957e7b13ae2fcd081a'
2022-01-13 22:19:12.709 INFO 84692 --- [ main] d.a.k.config.KeycloakConfigRunner : keycloak-config-cli running in 00:03.428.
jkr@joe-nb keycloak-config-cli % java -jar target/keycloak-config-cli.jar --spring.profiles.active=dev --keycloak.grant-type=client_credentials --keycloak.client-id=config-cli-master --keycloak.client-secret=config-cli-master-secret --import.path=src/test/resources/import-files/roles/00_create_realm_with_roles.json --import.force=true
2022-01-13 22:21:33.303 INFO 84706 --- [ main] d.a.k.config.KeycloakConfigApplication : Starting KeycloakConfigApplication v4.5.1-SNAPSHOT using Java 11.0.13 on joe-nb with PID 84706 (/Users/jkr/IdeaProjects/keycloak-config-cli/target/keycloak-config-cli.jar started by jkr in /Users/jkr/IdeaProjects/keycloak-config-cli)
2022-01-13 22:21:33.305 INFO 84706 --- [ main] d.a.k.config.KeycloakConfigApplication : The following profiles are active: dev
2022-01-13 22:21:33.786 INFO 84706 --- [ main] d.a.k.config.KeycloakConfigApplication : Started KeycloakConfigApplication in 1.037 seconds (JVM running for 1.436)
2022-01-13 22:21:34.575 INFO 84706 --- [ main] d.a.k.config.KeycloakConfigRunner : Importing file '/Users/jkr/IdeaProjects/keycloak-config-cli/src/test/resources/import-files/roles/00_create_realm_with_roles.json'
2022-01-13 22:21:34.836 DEBUG 84706 --- [ main] d.a.k.config.service.RealmImportService : Creating realm 'realmWithRoles' ...
2022-01-13 22:21:36.075 DEBUG 84706 --- [ main] d.a.k.c.service.ClientImportService : Create client 'moped-client' in realm 'realmWithRoles'
2022-01-13 22:21:36.285 DEBUG 84706 --- [ main] d.a.k.config.service.RoleImportService : Create realm-level role 'my_realm_role' in realm 'realmWithRoles'
2022-01-13 22:21:36.312 DEBUG 84706 --- [ main] d.a.k.config.service.RoleImportService : Create client-level role 'my_client_role' for client 'moped-client' in realm 'realmWithRoles'
2022-01-13 22:21:36.528 DEBUG 84706 --- [ main] d.a.k.config.service.state.StateService : Updated states of realm 'realmWithRoles'
2022-01-13 22:21:36.607 DEBUG 84706 --- [ main] d.a.k.c.s.checksum.ChecksumService : Updated import checksum of realm 'realmWithRoles' to 'c51a94d6600b2f6737a474d6abb924564533092940b9b8eea310f712a6a66f5f'
2022-01-13 22:21:36.607 INFO 84706 --- [ main] d.a.k.config.KeycloakConfigRunner : keycloak-config-cli running in 00:02.144.
jkr@joe-nb keycloak-config-cli % java -jar target/keycloak-config-cli.jar --spring.profiles.active=dev --keycloak.grant-type=client_credentials --keycloak.client-id=config-cli-master --keycloak.client-secret=config-cli-master-secret --import.path=src/test/resources/import-files/roles/00_create_realm_with_roles.json --import.force=true
2022-01-13 22:21:38.576 INFO 84715 --- [ main] d.a.k.config.KeycloakConfigApplication : Starting KeycloakConfigApplication v4.5.1-SNAPSHOT using Java 11.0.13 on joe-nb with PID 84715 (/Users/jkr/IdeaProjects/keycloak-config-cli/target/keycloak-config-cli.jar started by jkr in /Users/jkr/IdeaProjects/keycloak-config-cli)
2022-01-13 22:21:38.578 INFO 84715 --- [ main] d.a.k.config.KeycloakConfigApplication : The following profiles are active: dev
2022-01-13 22:21:39.033 INFO 84715 --- [ main] d.a.k.config.KeycloakConfigApplication : Started KeycloakConfigApplication in 0.937 seconds (JVM running for 1.324)
2022-01-13 22:21:39.841 INFO 84715 --- [ main] d.a.k.config.KeycloakConfigRunner : Importing file '/Users/jkr/IdeaProjects/keycloak-config-cli/src/test/resources/import-files/roles/00_create_realm_with_roles.json'
2022-01-13 22:21:40.180 DEBUG 84715 --- [ main] d.a.k.config.service.RealmImportService : Updating realm 'realmWithRoles'...
2022-01-13 22:21:40.417 DEBUG 84715 --- [ main] d.a.k.c.service.ClientImportService : No need to update client 'moped-client' in realm 'realmWithRoles'
2022-01-13 22:21:40.595 DEBUG 84715 --- [ main] d.a.k.config.service.RoleImportService : Update realm-level role 'my_realm_role' in realm 'realmWithRoles'
2022-01-13 22:21:40.626 DEBUG 84715 --- [ main] d.a.k.config.service.RoleImportService : Update client-level role 'my_client_role' for client 'moped-client' in realm 'realmWithRoles'
2022-01-13 22:21:40.813 DEBUG 84715 --- [ main] d.a.k.config.service.state.StateService : Updated states of realm 'realmWithRoles'
2022-01-13 22:21:40.903 DEBUG 84715 --- [ main] d.a.k.c.s.checksum.ChecksumService : Updated import checksum of realm 'realmWithRoles' to 'c51a94d6600b2f6737a474d6abb924564533092940b9b8eea310f712a6a66f5f'
2022-01-13 22:21:40.904 INFO 84715 --- [ main] d.a.k.config.KeycloakConfigRunner : keycloak-config-cli running in 00:01.185.
jkr@joe-nb keycloak-config-cli % java -jar target/keycloak-config-cli.jar --spring.profiles.active=dev --keycloak.grant-type=client_credentials --keycloak.client-id=config-cli-master --keycloak.client-secret=config-cli-master-secret --import.path=src/test/resources/import-files/roles/00_create_realm_with_roles.json --import.force=true
2022-01-13 22:23:02.008 INFO 84747 --- [ main] d.a.k.config.KeycloakConfigApplication : Starting KeycloakConfigApplication v4.5.1-SNAPSHOT using Java 11.0.13 on joe-nb with PID 84747 (/Users/jkr/IdeaProjects/keycloak-config-cli/target/keycloak-config-cli.jar started by jkr in /Users/jkr/IdeaProjects/keycloak-config-cli)
2022-01-13 22:23:02.010 INFO 84747 --- [ main] d.a.k.config.KeycloakConfigApplication : The following profiles are active: dev
2022-01-13 22:23:02.450 INFO 84747 --- [ main] d.a.k.config.KeycloakConfigApplication : Started KeycloakConfigApplication in 0.969 seconds (JVM running for 1.353)
2022-01-13 22:23:03.249 INFO 84747 --- [ main] d.a.k.config.KeycloakConfigRunner : Importing file '/Users/jkr/IdeaProjects/keycloak-config-cli/src/test/resources/import-files/roles/00_create_realm_with_roles.json'
2022-01-13 22:23:04.564 DEBUG 84747 --- [ main] d.a.k.config.service.RealmImportService : Updating realm 'realmWithRoles'...
2022-01-13 22:23:05.114 DEBUG 84747 --- [ main] d.a.k.c.service.ClientImportService : No need to update client 'moped-client' in realm 'realmWithRoles'
2022-01-13 22:23:05.408 DEBUG 84747 --- [ main] d.a.k.config.service.RoleImportService : Update realm-level role 'my_realm_role' in realm 'realmWithRoles'
2022-01-13 22:23:05.455 DEBUG 84747 --- [ main] d.a.k.config.service.RoleImportService : Update client-level role 'my_client_role' for client 'moped-client' in realm 'realmWithRoles'
2022-01-13 22:23:05.731 DEBUG 84747 --- [ main] d.a.k.config.service.state.StateService : Updated states of realm 'realmWithRoles'
2022-01-13 22:23:05.861 DEBUG 84747 --- [ main] d.a.k.c.s.checksum.ChecksumService : Updated import checksum of realm 'realmWithRoles' to 'c51a94d6600b2f6737a474d6abb924564533092940b9b8eea310f712a6a66f5f'
2022-01-13 22:23:05.862 INFO 84747 --- [ main] d.a.k.config.KeycloakConfigRunner : keycloak-config-cli running in 00:02.739
I can see, that the service account of the client has manage permissions granted to the created realm
Finally, I was able to find and reproduce the issue. I am sorry, I cannot share full source codes as I am not allowed to, but I'll add as many details as possible.
@jkroepke, my initial setup was a bit different from what you mentioned in the last comment. My docker image of the Keycloak contained exported realm saved in the master-realm.json
. There is an exported master realm that would be imported each time the container is being created. Exported master realm already had credentials for the Keycloak Config CLI, so it was possible for Config CLI to authorize and create all the necessary resources. As per your comment:
Users with the create-realm role are allowed to create new realms. They will be granted full access to any new realm they create.
which added realm management opportunities to the Keycloak Config CLI to re-connect and update the created realm in the future.
The import of the master realm was done via Keycloak's standard functionality (https://www.keycloak.org/docs/latest/server_admin/#assembly-exporting-importing_server_administration_guide):
-Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=master-realm.json
And this is the root cause of the issue! By default, the strategy was set to the OVERWRITE_EXISTING
mode, and that leaded Keycloak to remove the management roles from the Keycloak Config CLI client which caused 403 error later!
Changing the -Dkeycloak.migration.strategy=IGNORE_EXISTING
fixed the issue
Thank you so much for assisting with the debug session!
Describe the bug Creation of a new realm fails with
HTTP 403 Forbidden
ifclient_credentials
authentication flow withClientId
/ClientSecret
is used (although the realm actually got created).To Reproduce
Create client
The client gets the service account role `admin` which enables management of realms. JSON (`realm-master.json`): ```json { "realm": "master", "users": [ { "username": "service-account-my-cli", "enabled": true, "serviceAccountClientId": "my-cli", "realmRoles": [ "uma_authorization", "offline_access", "admin" ], "clientRoles": { "account": [ "view-profile", "manage-account" ] } } ], "clients": [ { "clientId": "my-cli", "enabled": true, "clientAuthenticatorType": "client-secret", "secret": "my-secret", "bearerOnly": false, "consentRequired": false, "standardFlowEnabled": false, "implicitFlowEnabled": false, "directAccessGrantsEnabled": false, "serviceAccountsEnabled": true, "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", "protocolMappers": [ { "name": "security-admin-console-audience-mapper", "protocol": "openid-connect", "protocolMapper": "oidc-audience-mapper", "consentRequired": false, "config": { "included.client.audience": "security-admin-console", "id.token.claim": "false", "access.token.claim": "true" } } ] } ], "keycloakVersion": "12.0.4" } ``` CMD: ```bash docker run -it --rm -e KEYCLOAK_URL=http://localhost:8080/auth -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=my-cli
at master realm (with user based authentication) [click to expand]Try to create realm
JSON (`realm-node.json`): ```json { "realm": "mynode", "displayName": "mynode" } ``` CMD: ```bash docker run -it --rm -e KEYCLOAK_URL=http://localhost:8080/auth -e KEYCLOAK_CLIENTID=my-cli -e KEYCLOAK_CLIENTSECRET=my-secret -e KEYCLOAK_GRANTTYPE=client_credentials -e IMPORT_PATH=/config/realm-node.json -e SPRING_PROFILES_INCLUDE=debug -v ./config/:/config adorsys/keycloak-config-cli:v3.1.0-12.0.3 ```mynode
usingclient_credentials
authentication flow [click to expand]Causes the following error:
Stack-Trace [click to expand]
```log ERROR 1 [main] o.s.boot.SpringApplication : Application run failed java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:807) ~[spring-boot-2.4.3.jar!/:2.4.3] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:788) ~[spring-boot-2.4.3.jar!/:2.4.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) ~[spring-boot-2.4.3.jar!/:2.4.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) ~[spring-boot-2.4.3.jar!/:2.4.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.4.3.jar!/:2.4.3] at de.adorsys.keycloak.config.KeycloakConfigApplication.main(KeycloakConfigApplication.java:35) ~[classes!/:3.1.0] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[keycloak-config-cli.jar:3.1.0] at org.springframework.boot.loader.Launcher.launch(Launcher.java:107) ~[keycloak-config-cli.jar:3.1.0] at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[keycloak-config-cli.jar:3.1.0] at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:467) ~[keycloak-config-cli.jar:3.1.0] Caused by: javax.ws.rs.ForbiddenException: HTTP 403 Forbidden at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.handleErrorStatus(ClientInvocation.java:266) ~[resteasy-client-4.6.0.Final.jar!/:4.6.0.Final] at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:238) ~[resteasy-client-4.6.0.Final.jar!/:4.6.0.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:64) ~[resteasy-client-4.6.0.Final.jar!/:4.6.0.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:154) ~[resteasy-client-4.6.0.Final.jar!/:4.6.0.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:115) ~[resteasy-client-4.6.0.Final.jar!/:4.6.0.Final] at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:76) ~[resteasy-client-4.6.0.Final.jar!/:4.6.0.Final] at com.sun.proxy.$Proxy87.toRepresentation(Unknown Source) ~[na:na] at de.adorsys.keycloak.config.repository.RealmRepository.get(RealmRepository.java:69) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.repository.StateRepository.retrieveCustomAttributes(StateRepository.java:118) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.repository.StateRepository.loadCustomAttributes(StateRepository.java:68) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.service.state.StateService.loadState(StateService.java:53) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.service.RealmImportService.configureRealm(RealmImportService.java:171) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.service.RealmImportService.createRealm(RealmImportService.java:158) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.service.RealmImportService.doImport(RealmImportService.java:134) ~[classes!/:3.1.0] at de.adorsys.keycloak.config.KeycloakConfigRunner.run(KeycloakConfigRunner.java:70) ~[classes!/:3.1.0] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:804) ~[spring-boot-2.4.3.jar!/:2.4.3] ... 13 common frames omitted ```The realm
mynode
was nevertheless created but (no further configuration would occur due to the error).The log from keycloak shows no authentication problems:
Expected behavior The realm should be created without any errors and further configuration of the realm (e.g. creation of clients) should occur.
Possible issue? Could it be that the CLI needs to refresh the access-token after the creation of the realm? Since otherwise there are no claims for the new realm
mynode-realm
on the token. See comparison of a token manually issued before and after creation of the realm. This theory would fit if the RealmRepository.get() method triggers some requests. However I couldn't see any logs on the keycloak server regarding 403 forbidden.Access token before creation of new realm [click to expand]
```JSON { "exp": 1614968632, "iat": 1614968572, "jti": "a5e103b1-82ec-4cad-93c9-c1de835e79ff", "iss": "http://localhost:8080/auth/realms/master", "aud": [ "security-admin-console", "master-realm", "account" ], "sub": "5255a1fd-0f3c-4b28-baf9-4bfc11f4d7fc", "typ": "Bearer", "azp": "my-cli", "acr": "1", "realm_access": { "roles": [ "create-realm", "offline_access", "admin", "uma_authorization" ] }, "resource_access": { "master-realm": { "roles": [ "view-identity-providers", "view-realm", "manage-identity-providers", "impersonation", "create-client", "manage-users", "query-realms", "view-authorization", "query-clients", "query-users", "manage-events", "manage-realm", "view-events", "view-users", "view-clients", "manage-authorization", "manage-clients", "query-groups" ] }, "account": { "roles": [ "manage-account", "manage-account-links", "view-profile" ] } }, "scope": "email profile", "clientHost": "192.168.80.1", "email_verified": false, "clientId": "my-cli", "preferred_username": "service-account-my-cli", "clientAddress": "192.168.80.1" } ```Access token after creation of new realm [click to expand]
```JSON { "exp": 1614968495, "iat": 1614968435, "jti": "899b7864-12fb-4461-aa72-0e0383575260", "iss": "http://localhost:8080/auth/realms/master", "aud": [ "security-admin-console", "mynode-realm", "master-realm", "account" ], "sub": "593bf4b3-be03-42f0-9668-28f3da5d874a", "typ": "Bearer", "azp": "my-cli", "acr": "1", "realm_access": { "roles": [ "create-realm", "offline_access", "admin", "uma_authorization" ] }, "resource_access": { "mynode-realm": { "roles": [ "view-identity-providers", "view-realm", "manage-identity-providers", "impersonation", "create-client", "manage-users", "query-realms", "view-authorization", "query-clients", "query-users", "manage-events", "manage-realm", "view-events", "view-users", "view-clients", "manage-authorization", "manage-clients", "query-groups" ] }, "master-realm": { "roles": [ "view-realm", "view-identity-providers", "manage-identity-providers", "impersonation", "create-client", "manage-users", "query-realms", "view-authorization", "query-clients", "query-users", "manage-events", "manage-realm", "view-events", "view-users", "view-clients", "manage-authorization", "manage-clients", "query-groups" ] }, "account": { "roles": [ "manage-account", "manage-account-links", "view-profile" ] } }, "scope": "profile email", "clientHost": "192.168.48.1", "email_verified": false, "clientId": "my-cli", "preferred_username": "service-account-my-cli", "clientAddress": "192.168.48.1" } ```Only workaround we know so far is to use a kind of "service"-user instead of the client (since everything works with user authentication).
Environment (please complete the following information):