Skip to content

Commit

Permalink
keycloak_quarkus: allow setting "sensitive options" using a Java KeyS…
Browse files Browse the repository at this point in the history
…tore file #188
  • Loading branch information
hwo-wd committed Apr 17, 2024
1 parent 6b64865 commit 0dd86bb
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 0 deletions.
3 changes: 3 additions & 0 deletions roles/keycloak_quarkus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ Role Defaults
|`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` |
|`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` |
|`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwardedPassword`) | `""` |
|`keycloak_quarkus_config_key_store_file`| Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty | `{{ keycloak.home }}/conf/conf_store.p12` if `keycloak_quarkus_keystore_password`!='', else '' |
|`keycloak_quarkus_config_key_store_password`| Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text | `""` |


* Hostname configuration

Expand Down
3 changes: 3 additions & 0 deletions roles/keycloak_quarkus/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ keycloak_quarkus_https_key_store_password: ''
keycloak_quarkus_https_trust_store_enabled: false
keycloak_quarkus_https_trust_store_file: "{{ keycloak.home }}/conf/trust_store.p12"
keycloak_quarkus_https_trust_store_password: ''
### configuration key store configuration
keycloak_quarkus_config_key_store_file: "{{ keycloak.home }}/conf/conf_store.p12"
keycloak_quarkus_config_key_store_password: ''

### Enable configuration for database backend, clustering and remote caches on infinispan
keycloak_quarkus_ha_enabled: false
Expand Down
8 changes: 8 additions & 0 deletions roles/keycloak_quarkus/meta/argument_specs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,14 @@ argument_specs:
default: ""
description: "Password for the trust store"
type: "str"
keycloak_quarkus_config_key_store_file:
default: "{{ keycloak.home }}/conf/conf_store.p12"
description: "Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty"
type: "str"
keycloak_quarkus_config_key_store_password:
default: ""
description: "Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text"
type: "str"
keycloak_quarkus_https_port:
default: 8443
description: "HTTPS port"
Expand Down
64 changes: 64 additions & 0 deletions roles/keycloak_quarkus/tasks/config_store.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
- name: "Check if keytool exists in path"
block:
- name: "Attempt to run keytool"
ansible.builtin.command: keytool -help
register: keytool_check
ignore_errors: true

- name: "Fail when no keytool found"
when: keytool_check.rc != 0
ansible.builtin.fail:
msg: "keytool NOT found in the PATH, but is required for setting up the configuration key store"

- name: "Initialize configuration key store variables to be written"
ansible.builtin.set_fact:
store_items:
- key: "kc.db-password"
value: "{{ keycloak_quarkus_db_pass }}"

- name: "Initialize empty configuration key store"
become: true
# keytool doesn't allow creating an empty key store, so this is a hacky way around it
ansible.builtin.shell: |
set -o nounset # abort on unbound variable
set -o pipefail # do not hide errors within pipes
set -o errexit # abort on nonzero exit status
echo dummy | keytool -noprompt -importpass -alias dummy -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} -storetype PKCS12
keytool -delete -alias dummy -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }}
args:
creates: "{{ keycloak_quarkus_config_key_store_file }}"

- name: "Set configuration key store using keytool"
ansible.builtin.shell: |
set -o nounset # abort on unbound variable
set -o pipefail # do not hide errors within pipes
keytool -list -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }}
retVal=$?
set -o errexit # abort on nonzero exit status
if [ $retVal -eq 0 ]; then
# value is already in keystore, but keytool has no replace function: delete and re-create instead
# note that we can not read whether the value has changed either[^1], so we need to override it
# [^1]: https://stackoverflow.com/a/37491400
keytool -delete -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }}
fi
echo {{ item.value | quote }} | keytool -noprompt -importpass -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} -storetype PKCS12
with_items: "{{ store_items }}"
no_log: true
become: true
changed_when: true
notify:
- restart keycloak

- name: "Set owner of configuration key store {{ keycloak_quarkus_config_key_store_file }}"
ansible.builtin.file:
path: "{{ keycloak_quarkus_config_key_store_file }}"
owner: "{{ keycloak.service_user }}"
group: "{{ keycloak.service_group }}"
mode: '0400'
become: true
6 changes: 6 additions & 0 deletions roles/keycloak_quarkus/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
tags:
- systemd

- name: Include configuration key store tasks
when: keycloak.config_key_store_enabled
ansible.builtin.include_tasks: config_store.yml
tags:
- install

- name: "Configure config for keycloak service"
ansible.builtin.template:
src: keycloak.conf.j2
Expand Down
9 changes: 9 additions & 0 deletions roles/keycloak_quarkus/templates/keycloak.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@
db={{ keycloak_quarkus_jdbc_engine }}
db-url={{ keycloak_quarkus_jdbc_url }}
db-username={{ keycloak_quarkus_db_user }}
{% if not keycloak.config_key_store_enabled %}
db-password={{ keycloak_quarkus_db_pass }}
{% endif %}
{% endif %}

{% if keycloak.config_key_store_enabled %}
# Config store
config-keystore={{ keycloak_quarkus_config_key_store_file }}
config-keystore-password={{ keycloak_quarkus_config_key_store_password }}
config-keystore-type=PKCS12
{% endif %}

# Observability
metrics-enabled={{ keycloak_quarkus_metrics_enabled | lower }}
Expand Down
1 change: 1 addition & 0 deletions roles/keycloak_quarkus/vars/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ keycloak:
service_user: "{{ keycloak_quarkus_service_user }}"
service_group: "{{ keycloak_quarkus_service_group }}"
offline_install: "{{ keycloak_quarkus_offline_install }}"
config_key_store_enabled: "{{ keycloak_quarkus_config_key_store_password != '' }}"
log:
file: "{{ keycloak_quarkus_home }}/{{ keycloak_quarkus_log_file }}"
level: "{{ keycloak_quarkus_log_level }}"
Expand Down

0 comments on commit 0dd86bb

Please sign in to comment.