1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-03-21 20:59:10 +00:00
community.general/tests/integration/targets/keycloak_realm_key/tasks/main.yml
Ivan Kokalovic 80d21f2a0d
keycloak_realm_key: add full support for all Keycloak key providers (#11468)
* feat(keycloak_realm_key): add support for auto-generated key providers

Add support for Keycloak's auto-generated key providers where Keycloak
manages the key material automatically:

- rsa-generated: Auto-generates RSA signing keys
- hmac-generated: Auto-generates HMAC signing keys
- aes-generated: Auto-generates AES encryption keys
- ecdsa-generated: Auto-generates ECDSA signing keys

New algorithms:
- HMAC: HS256, HS384, HS512
- ECDSA: ES256, ES384, ES512
- AES: AES (no algorithm parameter needed)

New config options:
- secret_size: For HMAC/AES providers (key size in bytes)
- key_size: For RSA-generated provider (key size in bits)
- elliptic_curve: For ECDSA-generated provider (P-256, P-384, P-521)

Changes:
- Make private_key/certificate optional (only required for rsa/rsa-enc)
- Add provider-algorithm validation with clear error messages
- Fix KeyError when managing default realm keys (issue #11459)
- Maintain backward compatibility: RS256 default works for rsa/rsa-generated

Fixes: #11459

* fix: address sanity test failures

- Add 'default: RS256' to algorithm documentation to match spec
- Add no_log=True to secret_size parameter per sanity check

* feat(keycloak_realm_key): extend support for all Keycloak key providers

Add support for remaining auto-generated key providers:
- rsa-enc-generated (RSA encryption keys with RSA1_5, RSA-OAEP, RSA-OAEP-256)
- ecdh-generated (ECDH key exchange with ECDH_ES, ECDH_ES_A128KW/A192KW/A256KW)
- eddsa-generated (EdDSA signing with Ed25519, Ed448 curves)

Changes:
- Add provider-specific elliptic curve config key mapping
  (ecdsaEllipticCurveKey, ecdhEllipticCurveKey, eddsaEllipticCurveKey)
- Add PROVIDERS_WITHOUT_ALGORITHM constant for providers that don't need algorithm
- Add elliptic curve validation per provider type
- Update documentation with all supported algorithms and examples
- Add comprehensive integration tests for all new providers

This completes full coverage of all Keycloak key provider types.

* style: apply ruff formatting

* feat(keycloak_realm_key): add java-keystore provider and update_password

Add support for java-keystore provider to import keys from Java
Keystore (JKS or PKCS12) files on the Keycloak server filesystem.

Add update_password parameter to control password handling for
java-keystore provider:
- always (default): Always send passwords to Keycloak
- on_create: Only send passwords when creating, preserve existing
  passwords when updating (enables idempotent playbooks)

The on_create mode sends the masked value ("**********") that Keycloak
recognizes as "preserve existing password", matching the behavior when
re-importing an exported realm.

Replace password_checksum with update_password - the checksum approach
was complex and error-prone. The update_password parameter is simpler
and follows the pattern used by ansible.builtin.user module.

Also adds key_info return value containing kid, certificate fingerprint,
status, and expiration for java-keystore keys.

* address PR review feedback

- Remove no_log=True from secret_size (just an int, not sensitive)
- Add version_added: 12.4.0 to new parameters and return values
- Remove "Added in community.general 12.4.0" from description text
- Consolidate changelog entries into 4 focused entries
- Remove bugfix from changelog (now in separate PR #11470)

* address review feedback from russoz and felixfontein

- remove docstrings from module-local helpers
- remove line-by-line comments and unnecessary null guard
- use specific exceptions instead of bare except Exception
- use module.params["key"] instead of .get("key")
- consolidate changelog into single entry
- avoid "complete set" claim, reference Keycloak 26 instead

* address round 2 review feedback

- Extract remove_sensitive_config_keys() helper (DRY refactor)
- Simplify RS256 validation to single code path
- Add TypeError to inner except in compute_certificate_fingerprint()
- Remove redundant comments (L812, L1031)
- Switch .get() to direct dict access for module.params
2026-02-18 07:48:37 +01:00

1365 lines
41 KiB
YAML

---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Remove Keycloak test realm to avoid failures from previous failed runs
community.general.keycloak_realm:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ realm }}"
state: absent
- name: Create Keycloak test realm
community.general.keycloak_realm:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ realm }}"
state: present
- name: Create custom realm key (check mode)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
enabled: true
active: true
priority: 150
check_mode: true
register: result
- name: Assert that nothing has changed
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["150"]
- result.msg == "Realm key testkey would be created"
- name: Create custom realm key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
enabled: true
active: true
priority: 150
diff: true
register: result
- name: Assert that realm key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["150"]
- result.msg == "Realm key testkey created"
- name: Create custom realm key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
enabled: true
active: true
priority: 150
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["150"]
- result.msg == "Realm key testkey was in sync"
- name: Update custom realm key (check mode)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
enabled: true
active: true
priority: 140
check_mode: true
register: result
- name: Assert that nothing has changed
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["140"]
- >-
result.msg == "Realm key testkey would be changed: config.priority ['150'] -> ['140']"
- name: Update custom realm key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
enabled: true
active: true
priority: 140
diff: true
register: result
- name: Assert that realm key was updated
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["140"]
- >-
result.msg == "Realm key testkey changed: config.priority ['150'] -> ['140']"
- name: Update custom realm key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
enabled: true
active: true
priority: 140
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["140"]
- result.msg == "Realm key testkey was in sync"
- name: Force update custom realm key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
force: true
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key_2 }}"
certificate: ""
enabled: true
active: true
priority: 140
register: result
- name: Assert that forced update ran correctly
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "testkey"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["140"]
- result.msg == "Realm key testkey was forcibly updated"
- name: Remove custom realm key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: absent
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
priority: 140
diff: true
register: result
- name: Assert that realm key was deleted
assert:
that:
- result is changed
- result.end_state == {}
- result.msg == "Realm key testkey deleted"
- name: Remove custom realm key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey
state: absent
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: ""
priority: 140
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state == {}
- result.msg == "Realm key testkey not present"
- name: Create custom realm key with a custom certificate
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey_with_certificate
state: present
parent_id: "{{ realm }}"
config:
private_key: "{{ realm_private_key }}"
certificate: "{{ realm_certificate }}"
enabled: true
active: true
priority: 150
diff: true
register: result
- name: Assert that realm key with custom certificate was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "testkey_with_certificate"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["150"]
- result.msg == "Realm key testkey_with_certificate created"
- name: Attempt to change the private key and the certificate
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: testkey_with_certificate
state: present
parent_id: "{{ realm }}"
config:
private_key: "a different private key string"
certificate: "a different certificate string"
enabled: true
active: true
priority: 150
diff: true
register: result
- name: Assert that nothing has changed
assert:
that:
- result is not changed
- result.end_state != {}
- result.end_state.name == "testkey_with_certificate"
- result.end_state.parentId == "realm_key_test"
- result.end_state.providerId == "rsa"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.active == ["true"]
- result.end_state.config.enabled == ["true"]
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.priority == ["150"]
- result.msg == "Realm key testkey_with_certificate was in sync"
# ============================================================
# Tests for auto-generated key providers
# ============================================================
- name: Create HMAC key (hmac-generated provider, check mode)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-test-key
state: present
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
enabled: true
active: true
priority: 100
algorithm: HS256
secret_size: 64
check_mode: true
register: result
- name: Assert HMAC key would be created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "hmac-test-key"
- result.end_state.providerId == "hmac-generated"
- result.end_state.config.algorithm == ["HS256"]
- result.end_state.config.secretSize == ["64"]
- result.msg == "Realm key hmac-test-key would be created"
- name: Create HMAC key (hmac-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-test-key
state: present
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
enabled: true
active: true
priority: 100
algorithm: HS256
secret_size: 64
register: result
- name: Assert HMAC key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "hmac-test-key"
- result.end_state.providerId == "hmac-generated"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.algorithm == ["HS256"]
- result.end_state.config.secretSize == ["64"]
- result.msg == "Realm key hmac-test-key created"
- name: Create HMAC key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-test-key
state: present
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
enabled: true
active: true
priority: 100
algorithm: HS256
secret_size: 64
register: result
- name: Assert HMAC key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key hmac-test-key was in sync"
- name: Update HMAC key priority
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-test-key
state: present
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
enabled: true
active: true
priority: 110
algorithm: HS256
secret_size: 64
register: result
- name: Assert HMAC key was updated
assert:
that:
- result is changed
- result.end_state.config.priority == ["110"]
- "'config.priority' in result.msg"
- name: Remove HMAC key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
priority: 110
register: result
- name: Assert HMAC key was deleted
assert:
that:
- result is changed
- result.end_state == {}
- result.msg == "Realm key hmac-test-key deleted"
# ============================================================
# AES generated key tests
# ============================================================
- name: Create AES key (aes-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: aes-test-key
state: present
parent_id: "{{ realm }}"
provider_id: aes-generated
config:
enabled: true
active: true
priority: 100
secret_size: 32
register: result
- name: Assert AES key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "aes-test-key"
- result.end_state.providerId == "aes-generated"
- result.end_state.config.secretSize == ["32"]
- result.msg == "Realm key aes-test-key created"
- name: Create AES key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: aes-test-key
state: present
parent_id: "{{ realm }}"
provider_id: aes-generated
config:
enabled: true
active: true
priority: 100
secret_size: 32
register: result
- name: Assert AES key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key aes-test-key was in sync"
- name: Remove AES key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: aes-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: aes-generated
config:
priority: 100
register: result
- name: Assert AES key was deleted
assert:
that:
- result is changed
- result.msg == "Realm key aes-test-key deleted"
# ============================================================
# ECDSA generated key tests
# ============================================================
- name: Create ECDSA key (ecdsa-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: ecdsa-test-key
state: present
parent_id: "{{ realm }}"
provider_id: ecdsa-generated
config:
enabled: true
active: true
priority: 100
algorithm: ES256
elliptic_curve: P-256
register: result
- name: Assert ECDSA key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "ecdsa-test-key"
- result.end_state.providerId == "ecdsa-generated"
- result.end_state.config.algorithm == ["ES256"]
- result.end_state.config.ecdsaEllipticCurveKey == ["P-256"]
- result.msg == "Realm key ecdsa-test-key created"
- name: Create ECDSA key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: ecdsa-test-key
state: present
parent_id: "{{ realm }}"
provider_id: ecdsa-generated
config:
enabled: true
active: true
priority: 100
algorithm: ES256
elliptic_curve: P-256
register: result
- name: Assert ECDSA key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key ecdsa-test-key was in sync"
- name: Remove ECDSA key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: ecdsa-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: ecdsa-generated
config:
priority: 100
register: result
- name: Assert ECDSA key was deleted
assert:
that:
- result is changed
- result.msg == "Realm key ecdsa-test-key deleted"
# ============================================================
# RSA generated key tests
# ============================================================
- name: Create RSA generated key (rsa-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: rsa-gen-test-key
state: present
parent_id: "{{ realm }}"
provider_id: rsa-generated
config:
enabled: true
active: true
priority: 100
algorithm: RS256
key_size: 2048
register: result
- name: Assert RSA generated key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "rsa-gen-test-key"
- result.end_state.providerId == "rsa-generated"
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.keySize == ["2048"]
- result.msg == "Realm key rsa-gen-test-key created"
- name: Create RSA generated key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: rsa-gen-test-key
state: present
parent_id: "{{ realm }}"
provider_id: rsa-generated
config:
enabled: true
active: true
priority: 100
algorithm: RS256
key_size: 2048
register: result
- name: Assert RSA generated key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key rsa-gen-test-key was in sync"
- name: Remove RSA generated key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: rsa-gen-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: rsa-generated
config:
priority: 100
register: result
- name: Assert RSA generated key was deleted
assert:
that:
- result is changed
- result.msg == "Realm key rsa-gen-test-key deleted"
# ============================================================
# Test managing default realm keys (issue #11459)
# ============================================================
- name: Update priority of default hmac-generated key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-generated
state: present
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
enabled: true
active: true
priority: 150
register: result
- name: Assert default hmac-generated key was updated
assert:
that:
- result is changed
- result.end_state.config.priority == ["150"]
- name: Remove default hmac-generated key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: hmac-generated
state: absent
parent_id: "{{ realm }}"
provider_id: hmac-generated
config:
priority: 150
register: result
- name: Assert default hmac-generated key was deleted
assert:
that:
- result is changed
- result.end_state == {}
- result.msg == "Realm key hmac-generated deleted"
# ============================================================
# RSA encryption generated key tests (rsa-enc-generated)
# ============================================================
- name: Create RSA encryption key (rsa-enc-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: rsa-enc-gen-test-key
state: present
parent_id: "{{ realm }}"
provider_id: rsa-enc-generated
config:
enabled: true
active: true
priority: 100
algorithm: RSA-OAEP
key_size: 2048
register: result
- name: Assert RSA encryption key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "rsa-enc-gen-test-key"
- result.end_state.providerId == "rsa-enc-generated"
- result.end_state.config.algorithm == ["RSA-OAEP"]
- result.end_state.config.keySize == ["2048"]
- result.msg == "Realm key rsa-enc-gen-test-key created"
- name: Create RSA encryption key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: rsa-enc-gen-test-key
state: present
parent_id: "{{ realm }}"
provider_id: rsa-enc-generated
config:
enabled: true
active: true
priority: 100
algorithm: RSA-OAEP
key_size: 2048
register: result
- name: Assert RSA encryption key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key rsa-enc-gen-test-key was in sync"
- name: Remove RSA encryption key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: rsa-enc-gen-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: rsa-enc-generated
config:
priority: 100
register: result
- name: Assert RSA encryption key was deleted
assert:
that:
- result is changed
- result.msg == "Realm key rsa-enc-gen-test-key deleted"
# ============================================================
# ECDH generated key tests (ecdh-generated)
# ============================================================
- name: Create ECDH key (ecdh-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: ecdh-test-key
state: present
parent_id: "{{ realm }}"
provider_id: ecdh-generated
config:
enabled: true
active: true
priority: 100
algorithm: ECDH_ES
elliptic_curve: P-256
register: result
- name: Assert ECDH key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "ecdh-test-key"
- result.end_state.providerId == "ecdh-generated"
- result.end_state.config.algorithm == ["ECDH_ES"]
- result.end_state.config.ecdhEllipticCurveKey == ["P-256"]
- result.msg == "Realm key ecdh-test-key created"
- name: Create ECDH key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: ecdh-test-key
state: present
parent_id: "{{ realm }}"
provider_id: ecdh-generated
config:
enabled: true
active: true
priority: 100
algorithm: ECDH_ES
elliptic_curve: P-256
register: result
- name: Assert ECDH key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key ecdh-test-key was in sync"
- name: Remove ECDH key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: ecdh-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: ecdh-generated
config:
priority: 100
register: result
- name: Assert ECDH key was deleted
assert:
that:
- result is changed
- result.msg == "Realm key ecdh-test-key deleted"
# ============================================================
# EdDSA generated key tests (eddsa-generated)
# ============================================================
- name: Create EdDSA key (eddsa-generated provider)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: eddsa-test-key
state: present
parent_id: "{{ realm }}"
provider_id: eddsa-generated
config:
enabled: true
active: true
priority: 100
elliptic_curve: Ed25519
register: result
- name: Assert EdDSA key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "eddsa-test-key"
- result.end_state.providerId == "eddsa-generated"
- result.end_state.config.eddsaEllipticCurveKey == ["Ed25519"]
- result.msg == "Realm key eddsa-test-key created"
- name: Create EdDSA key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: eddsa-test-key
state: present
parent_id: "{{ realm }}"
provider_id: eddsa-generated
config:
enabled: true
active: true
priority: 100
elliptic_curve: Ed25519
register: result
- name: Assert EdDSA key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key eddsa-test-key was in sync"
- name: Remove EdDSA key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: eddsa-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: eddsa-generated
config:
priority: 100
register: result
- name: Assert EdDSA key was deleted
assert:
that:
- result is changed
- result.msg == "Realm key eddsa-test-key deleted"
# ============================================================
# Java Keystore provider tests (java-keystore)
# Note: These tests require a keystore file on the Keycloak server
# They are conditionally skipped if test_keystore_path is not defined
# ============================================================
- name: Create java-keystore key (check mode)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-test-key
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
check_mode: true
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key would be created (check mode)
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "jks-test-key"
- result.end_state.providerId == "java-keystore"
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.config.keystore == [test_keystore_path]
- result.end_state.config.keyAlias == [test_key_alias]
- result.msg == "Realm key jks-test-key would be created"
when: test_keystore_path is defined
- name: Create java-keystore key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-test-key
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "jks-test-key"
- result.end_state.providerId == "java-keystore"
- result.end_state.providerType == "org.keycloak.keys.KeyProvider"
- result.end_state.config.algorithm == ["RS256"]
- result.end_state.key_info is defined
- result.end_state.key_info.kid is defined
- result.end_state.key_info.certificate_fingerprint is defined
- result.end_state.key_info.status == "ACTIVE"
- result.msg == "Realm key jks-test-key created"
when: test_keystore_path is defined
- name: Create java-keystore key (test for idempotency)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-test-key
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key is in sync
assert:
that:
- result is not changed
- result.msg == "Realm key jks-test-key was in sync"
when: test_keystore_path is defined
- name: Update java-keystore key priority
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-test-key
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
enabled: true
active: true
priority: 110
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key was updated
assert:
that:
- result is changed
- result.end_state.config.priority == ["110"]
- "'config.priority' in result.msg"
when: test_keystore_path is defined
- name: Remove java-keystore key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-test-key
state: absent
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
priority: 110
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key was deleted
assert:
that:
- result is changed
- result.end_state == {}
- result.msg == "Realm key jks-test-key deleted"
when: test_keystore_path is defined
# ============================================================
# Java Keystore update_password tests
# ============================================================
- name: Create java-keystore key with update_password=always (default)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
# update_password: always is the default
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key was created
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "jks-update-pw-test"
- result.msg == "Realm key jks-update-pw-test created"
when: test_keystore_path is defined
- name: Re-run with update_password=always (should NOT be idempotent - passwords always sent)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
update_password: always
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
# Note: With update_password=always, the module always sends passwords to Keycloak.
# Keycloak doesn't report back if passwords changed, so the module reports "in sync"
# for the config comparison (passwords are excluded from comparison).
# The key difference is: always sends real passwords, on_create sends masked values.
- name: Assert java-keystore key is in sync (no config changes detected)
assert:
that:
- result is not changed
- result.msg == "Realm key jks-update-pw-test was in sync"
when: test_keystore_path is defined
- name: Remove java-keystore key to test update_password=on_create
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: absent
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
priority: 100
register: result
when: test_keystore_path is defined
- name: Create java-keystore key with update_password=on_create
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
update_password: on_create
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key was created with on_create mode
assert:
that:
- result is changed
- result.end_state != {}
- result.end_state.name == "jks-update-pw-test"
- result.msg == "Realm key jks-update-pw-test created"
when: test_keystore_path is defined
- name: Re-run with update_password=on_create (should be idempotent)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
update_password: on_create
config:
enabled: true
active: true
priority: 100
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert java-keystore key is idempotent with on_create mode
assert:
that:
- result is not changed
- result.msg == "Realm key jks-update-pw-test was in sync"
when: test_keystore_path is defined
- name: Update priority with update_password=on_create (passwords preserved)
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: present
parent_id: "{{ realm }}"
provider_id: java-keystore
update_password: on_create
config:
enabled: true
active: true
priority: 110
algorithm: RS256
keystore: "{{ test_keystore_path }}"
keystore_password: "{{ test_keystore_password }}"
key_alias: "{{ test_key_alias }}"
register: result
when: test_keystore_path is defined
- name: Assert priority was updated but passwords preserved
assert:
that:
- result is changed
- result.end_state.config.priority == ["110"]
- "'config.priority' in result.msg"
when: test_keystore_path is defined
- name: Remove java-keystore update_password test key
community.general.keycloak_realm_key:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
name: jks-update-pw-test
state: absent
parent_id: "{{ realm }}"
provider_id: java-keystore
config:
priority: 110
register: result
when: test_keystore_path is defined
- name: Assert java-keystore update_password test key was deleted
assert:
that:
- result is changed
- result.end_state == {}
when: test_keystore_path is defined
- name: Remove Keycloak test realm
community.general.keycloak_realm:
auth_keycloak_url: "{{ url }}"
auth_realm: "{{ admin_realm }}"
auth_username: "{{ admin_user }}"
auth_password: "{{ admin_password }}"
realm: "{{ realm }}"
id: "{{ realm }}"
state: absent