0

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 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_create

The 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"},
  "msg": "Status code was 415 and not [200]: HTTP Error 415: Unsupported Media Type",
  "redirected": false,
  "status": 415,
  "url": "https://keycloak-server/auth/"
}

The documentation says it must be a POST to / and it consumes application/json. So, I'm not sure - is the URL correct? If I try https://keycloak-server/auth/realms/, I'm getting a 404. If I remove the Content-type - I'm getting a 406 with "Not acceptable". If I remove Accepts too, I'm getting a HTML page.

So - what is wrong?

  • I think the endpoint should be https://keycloak-server/auth/admin/realms? What happens if you try with CURL something like this curl -v -X POST \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d @realm.json \ $KCHOST/auth/admin/realms? – JSapkota Mar 18 at 1:17
  • Yes, I can confirm, if I add the /admin/ between auth and realms, it works. I'll write an answer with a complete example. – TRW Mar 19 at 7:18
1

As @JSapkota mentioned the URL was wrong. It must be 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_create

Take 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.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.