patternMinor
Creating Keycloak Realm via Ansible
Viewed 0 times
creatingkeycloakviarealmansible
Problem
Currently there is no module to create a Keycloak realm with Ansible. There is a PR but it is stucked since half a year or so. So I though, there is a Keycloak REST API (https://www.keycloak.org/docs-api/9.0/rest-api/index.html#_realms_admin_resource) and I could call it with
The token is available within
As
or a complete JSON export from Keycloak via WebUI (export realm).
But in any case the following error happens:
```
fatal: [localhost]: FAILED! => {
"changed": false,
"connection": "close",
"content": "{\"error\":\"RESTEASY003065: Cannot consume content type\"}",
"content_length": "55",
"content_type": "application/json",
"elapsed": 0,
"json": {"error": "RESTEASY003065: Cannot consume content type"},
uri to create a Token and then send a JSON RealmRepresentation via REST. So I tried this:- name: "Create Token for service Keycloak"
uri:
url: "https://keycloak-server/auth/realms/master/protocol/openid-connect/token"
method: POST
body_format: form-urlencoded
body:
username: "admin"
password: "password"
grant_type: "password"
client_id: "admin-cli"
register: keycloak_token
- name: "Create Realm for service Keycloak"
uri:
url: "https://keycloak-server/auth/"
method: POST
src: "realm.json"
remote_src: "no"
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_createThe token is available within
keycloak_token.json.access_token and it is correct.As
realm.json I tested a minimal JSON (because all attributes in RealmRepresentation are marked as optional):{
"id": "myrealm",
"realm": "myrealm",
"displayName": "My Realm",
"enabled": true,
"sslRequired": "external",
"registrationAllowed": false,
"loginWithEmailAllowed": true,
"duplicateEmailsAllowed": false,
"resetPasswordAllowed": false,
"editUsernameAllowed": false,
"bruteForceProtected": true
}or a complete JSON export from Keycloak via WebUI (export realm).
But in any case the following error happens:
```
fatal: [localhost]: FAILED! => {
"changed": false,
"connection": "close",
"content": "{\"error\":\"RESTEASY003065: Cannot consume content type\"}",
"content_length": "55",
"content_type": "application/json",
"elapsed": 0,
"json": {"error": "RESTEASY003065: Cannot consume content type"},
Solution
As @JSapkota mentioned the URL was wrong. It must be
Take care about the return status code. It is "201 created" and the
This works one time. Because in the next run the REST API responses with 409 the
To be idempotent, you need to check first, if the realm exists. This can be done via
Also I had the problem, that after every request the Keycloak server responses with a 403 when I don't refresh the token before the next call to Keycloak. But I think, this depends on Realm token settings of the admin realm.
https://keycloak-server/auth/admin/realms.- name: "Create Realm for service Keycloak"
uri:
url: "https://keycloak-server/auth/admin/realms"
method: POST
src: "realm.json"
remote_src: "no"
status_code:
- 201
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_createTake care about the return status code. It is "201 created" and the
uri module must know, that this is fine.This works one time. Because in the next run the REST API responses with 409 the
uri module fails. To be idempotent, you need to check first, if the realm exists. This can be done via
GET /auth/admin/realms/{{ keycloak_realm_name }} and check the return code, if it is 404 or 200. If it is 404, then you make a "POST" otherwise a "PUT". So, this a complete example:- name: "Set facts"
set_fact:
keycloak_admin_user: "admin"
keycloak_admin_pass: "password"
keycloak_base_url: "https://keycloak.server"
keycloak_realm_name: "myrealm"
keycloak_realm_data_file: "realm.json"
- name: "Create Token for service Keycloak"
uri:
url: "{{ keycloak_base_url }}/auth/realms/master/protocol/openid-connect/token"
method: POST
body_format: form-urlencoded
body:
username: "{{ keycloak_admin_user }}"
password: "{{ keycloak_admin_pass }}"
grant_type: "password"
client_id: "admin-cli"
register: keycloak_token
- name: "Find out, if Realm {{ keycloak_realm_name }} for service Keycloak exists"
uri:
url: "{{ keycloak_base_url }}/auth/admin/realms/{{ keycloak_realm_name }}"
method: GET
status_code:
- 200
- 404
headers:
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_exists
- name: "Create Realm {{ keycloak_realm_name }} for service Keycloak"
uri:
url: "{{ keycloak_base_url }}/auth/admin/realms"
method: POST
src: "{{ keycloak_realm_data_file }}"
remote_src: "no"
status_code:
- 201
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_create
when: "keycloak_realm_exists.status == 404"
- name: "Update Realm {{ keycloak_realm_name }} for service Keycloak"
uri:
url: "{{ keycloak_base_url }}/auth/admin/realms/{{ keycloak_realm_name }}"
method: PUT
src: "{{ keycloak_realm_data_file }}"
remote_src: "no"
status_code:
- 204
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_create
when: "keycloak_realm_exists.status == 200"Also I had the problem, that after every request the Keycloak server responses with a 403 when I don't refresh the token before the next call to Keycloak. But I think, this depends on Realm token settings of the admin realm.
Code Snippets
- name: "Create Realm for service Keycloak"
uri:
url: "https://keycloak-server/auth/admin/realms"
method: POST
src: "realm.json"
remote_src: "no"
status_code:
- 201
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_create- name: "Set facts"
set_fact:
keycloak_admin_user: "admin"
keycloak_admin_pass: "password"
keycloak_base_url: "https://keycloak.server"
keycloak_realm_name: "myrealm"
keycloak_realm_data_file: "realm.json"
- name: "Create Token for service Keycloak"
uri:
url: "{{ keycloak_base_url }}/auth/realms/master/protocol/openid-connect/token"
method: POST
body_format: form-urlencoded
body:
username: "{{ keycloak_admin_user }}"
password: "{{ keycloak_admin_pass }}"
grant_type: "password"
client_id: "admin-cli"
register: keycloak_token
- name: "Find out, if Realm {{ keycloak_realm_name }} for service Keycloak exists"
uri:
url: "{{ keycloak_base_url }}/auth/admin/realms/{{ keycloak_realm_name }}"
method: GET
status_code:
- 200
- 404
headers:
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_exists
- name: "Create Realm {{ keycloak_realm_name }} for service Keycloak"
uri:
url: "{{ keycloak_base_url }}/auth/admin/realms"
method: POST
src: "{{ keycloak_realm_data_file }}"
remote_src: "no"
status_code:
- 201
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_create
when: "keycloak_realm_exists.status == 404"
- name: "Update Realm {{ keycloak_realm_name }} for service Keycloak"
uri:
url: "{{ keycloak_base_url }}/auth/admin/realms/{{ keycloak_realm_name }}"
method: PUT
src: "{{ keycloak_realm_data_file }}"
remote_src: "no"
status_code:
- 204
headers:
Content-type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{ keycloak_token.json.access_token }}"
register: keycloak_realm_create
when: "keycloak_realm_exists.status == 200"Context
StackExchange DevOps Q#11078, answer score: 4
Revisions (0)
No revisions yet.