java_keystore: add certificate_path and private_key_path options (#2230)

* java_keystore: add `certificate_path` and `private_key_path` options

* Update DOCUMENTATION and EXAMPLES accordingly.
* Refactor integration tests to play the same tasks twice.
* Add a changelog fragment (minor_changes).

refactor DOCUMENTATION

* Add useful info for better understanding of what options allow
  keystore regeneration on the fly, and what other options lead the
  module to fail, if their values change.
* Fix indentation and tenses.
* Add myself as author.

* readability-related stuff + changelog fragment
This commit is contained in:
quidame 2021-04-17 18:17:53 +02:00 committed by GitHub
commit 3a8206fe62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 328 additions and 201 deletions

View file

@ -0,0 +1,16 @@
---
java_keystore_certs:
- name: cert
commonName: example.com
- name: cert-pw
passphrase: hunter2
commonName: example.com
java_keystore_new_certs:
- name: cert2
keyname: cert
commonName: example.org
- name: cert2-pw
keyname: cert-pw
passphrase: hunter2
commonName: example.org

View file

@ -4,134 +4,22 @@
# and should not be used as examples of how to write Ansible roles #
####################################################################
- when: has_java_keytool
connection: local
block:
- name: Create private keys
community.crypto.openssl_privatekey:
path: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key' }}"
size: 2048 # this should work everywhere
# The following is more efficient, but might not work everywhere:
# type: ECC
# curve: secp384r1
cipher: "{{ 'auto' if item.passphrase is defined else omit }}"
passphrase: "{{ item.passphrase | default(omit) }}"
loop:
- name: cert
- name: cert-pw
passphrase: hunter2
- name: Include tasks to create ssl materials on the controller
include_tasks: prepare.yml
- name: Create CSRs
community.crypto.openssl_csr:
path: "{{ output_dir ~ '/' ~ item.name ~ '.csr' }}"
privatekey_path: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key' }}"
privatekey_passphrase: "{{ item.passphrase | default(omit) }}"
commonName: "{{ item.commonName }}"
loop:
- name: cert
commonName: example.com
- name: cert-pw
passphrase: hunter2
commonName: example.com
- name: cert2
keyname: cert
commonName: example.org
- name: cert2-pw
keyname: cert-pw
passphrase: hunter2
commonName: example.org
- when: has_java_keytool
block:
- name: Include tasks to play with 'certificate' and 'private_key' contents
include_tasks: tests.yml
vars:
remote_cert: false
- name: Create certificates
community.crypto.x509_certificate:
path: "{{ output_dir ~ '/' ~ item.name ~ '.pem' }}"
csr_path: "{{ output_dir ~ '/' ~ item.name ~ '.csr' }}"
privatekey_path: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key' }}"
privatekey_passphrase: "{{ item.passphrase | default(omit) }}"
provider: selfsigned
loop:
- name: cert
commonName: example.com
- name: cert-pw
passphrase: hunter2
commonName: example.com
- name: cert2
keyname: cert
commonName: example.org
- name: cert2-pw
keyname: cert-pw
passphrase: hunter2
commonName: example.org
- name: Include tasks to create ssl materials on the remote host
include_tasks: prepare.yml
- name: Create a Java key store for the given certificates (check mode)
community.general.java_keystore: &create_key_store_data
name: example
certificate: "{{ lookup('file', output_dir ~ '/' ~ item.name ~ '.pem') }}"
private_key: "{{ lookup('file', output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key') }}"
private_key_passphrase: "{{ item.passphrase | default(omit) }}"
password: changeit
dest: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.jks' }}"
loop: &create_key_store_loop
- name: cert
- name: cert-pw
passphrase: hunter2
check_mode: yes
register: result_check
- name: Create a Java key store for the given certificates
community.general.java_keystore: *create_key_store_data
loop: *create_key_store_loop
register: result
- name: Create a Java key store for the given certificates (idempotency, check mode)
community.general.java_keystore: *create_key_store_data
loop: *create_key_store_loop
check_mode: yes
register: result_idem_check
- name: Create a Java key store for the given certificates (idempotency)
community.general.java_keystore: *create_key_store_data
loop: *create_key_store_loop
register: result_idem
- name: Create a Java key store for the given certificates (certificate changed, check mode)
community.general.java_keystore: *create_key_store_data
loop: &create_key_store_loop_new_certs
- name: cert2
keyname: cert
- name: cert2-pw
keyname: cert-pw
passphrase: hunter2
check_mode: yes
register: result_change_check
- name: Create a Java key store for the given certificates (certificate changed)
community.general.java_keystore: *create_key_store_data
loop: *create_key_store_loop_new_certs
register: result_change
- name: Create a Java key store for the given certificates (password changed, check mode)
community.general.java_keystore:
<<: *create_key_store_data
password: hunter2
loop: *create_key_store_loop_new_certs
check_mode: yes
register: result_pw_change_check
when: false # FIXME: module currently crashes
- name: Create a Java key store for the given certificates (password changed)
community.general.java_keystore:
<<: *create_key_store_data
password: hunter2
loop: *create_key_store_loop_new_certs
register: result_pw_change
when: false # FIXME: module currently crashes
- name: Validate results
assert:
that:
- result is changed
- result_check is changed
- result_idem is not changed
- result_idem_check is not changed
- result_change is changed
- result_change_check is changed
# - result_pw_change is changed # FIXME: module currently crashes
# - result_pw_change_check is changed # FIXME: module currently crashes
- name: Include tasks to play with 'certificate_path' and 'private_key_path' locations
include_tasks: tests.yml
vars:
remote_cert: true

View file

@ -0,0 +1,33 @@
---
- name: Create test directory
ansible.builtin.file:
path: "{{ output_dir }}"
state: directory
- name: Create private keys
community.crypto.openssl_privatekey:
path: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key' }}"
size: 2048 # this should work everywhere
# The following is more efficient, but might not work everywhere:
# type: ECC
# curve: secp384r1
cipher: "{{ 'auto' if item.passphrase is defined else omit }}"
passphrase: "{{ item.passphrase | default(omit) }}"
loop: "{{ java_keystore_certs }}"
- name: Create CSRs
community.crypto.openssl_csr:
path: "{{ output_dir ~ '/' ~ item.name ~ '.csr' }}"
privatekey_path: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key' }}"
privatekey_passphrase: "{{ item.passphrase | default(omit) }}"
commonName: "{{ item.commonName }}"
loop: "{{ java_keystore_certs + java_keystore_new_certs }}"
- name: Create certificates
community.crypto.x509_certificate:
path: "{{ output_dir ~ '/' ~ item.name ~ '.pem' }}"
csr_path: "{{ output_dir ~ '/' ~ item.name ~ '.csr' }}"
privatekey_path: "{{ output_dir ~ '/' ~ (item.keyname | default(item.name)) ~ '.key' }}"
privatekey_passphrase: "{{ item.passphrase | default(omit) }}"
provider: selfsigned
loop: "{{ java_keystore_certs + java_keystore_new_certs }}"

View file

@ -0,0 +1,123 @@
---
- name: Create test directory
ansible.builtin.file:
path: "{{ output_dir }}"
state: directory
- name: Ensure the Java keystore does not exist (cleanup between tests)
ansible.builtin.file:
path: "{{ output_dir ~ '/' ~ item.name ~ '.jks' }}"
state: absent
loop: "{{ java_keystore_certs }}"
loop_control:
label: "{{ output_dir ~ '/' ~ item.name ~ '.jks' }}"
- name: Create a Java keystore for the given ({{ 'remote' if remote_cert else 'local' }}) certificates (check mode)
community.general.java_keystore: &java_keystore_params
name: example
dest: "{{ output_dir ~ '/' ~ (item.keyname | d(item.name)) ~ '.jks' }}"
certificate: "{{ omit if remote_cert else lookup('file', output_dir ~ '/' ~ item.name ~ '.pem') }}"
private_key: "{{ omit if remote_cert else lookup('file', output_dir ~ '/' ~ (item.keyname | d(item.name)) ~ '.key') }}"
certificate_path: "{{ omit if not remote_cert else output_dir ~ '/' ~ item.name ~ '.pem' }}"
private_key_path: "{{ omit if not remote_cert else output_dir ~ '/' ~ (item.keyname | d(item.name)) ~ '.key' }}"
private_key_passphrase: "{{ item.passphrase | d(omit) }}"
password: changeit
loop: "{{ java_keystore_certs }}"
check_mode: yes
register: result_check
- name: Create a Java keystore for the given certificates
community.general.java_keystore: *java_keystore_params
loop: "{{ java_keystore_certs }}"
register: result
- name: Create a Java keystore for the given certificates (idempotency, check mode)
community.general.java_keystore: *java_keystore_params
loop: "{{ java_keystore_certs }}"
check_mode: yes
register: result_idem_check
- name: Create a Java keystore for the given certificates (idempotency)
community.general.java_keystore: *java_keystore_params
loop: "{{ java_keystore_certs }}"
register: result_idem
- name: Create a Java keystore for the given certificates (certificate changed, check mode)
community.general.java_keystore: *java_keystore_params
loop: "{{ java_keystore_new_certs }}"
check_mode: yes
register: result_change_check
- name: Create a Java keystore for the given certificates (certificate changed)
community.general.java_keystore: *java_keystore_params
loop: "{{ java_keystore_new_certs }}"
register: result_change
- name: Create a Java keystore for the given certificates (alias changed, check mode)
community.general.java_keystore:
<<: *java_keystore_params
name: foobar
loop: "{{ java_keystore_new_certs }}"
check_mode: yes
register: result_alias_change_check
when: false # FIXME: module currently crashes
- name: Create a Java keystore for the given certificates (alias changed)
community.general.java_keystore:
<<: *java_keystore_params
name: foobar
loop: "{{ java_keystore_new_certs }}"
register: result_alias_change
when: false # FIXME: module currently crashes
- name: Create a Java keystore for the given certificates (password changed, check mode)
community.general.java_keystore:
<<: *java_keystore_params
name: foobar
password: hunter2
loop: "{{ java_keystore_new_certs }}"
check_mode: yes
register: result_pw_change_check
when: false # FIXME: module currently crashes
- name: Create a Java keystore for the given certificates (password changed)
community.general.java_keystore:
<<: *java_keystore_params
name: foobar
password: hunter2
loop: "{{ java_keystore_new_certs }}"
register: result_pw_change
when: false # FIXME: module currently crashes
- name: Check that the remote certificates have not been removed
ansible.builtin.file:
path: "{{ output_dir ~ '/' ~ item.name ~ '.pem' }}"
state: file
loop: "{{ java_keystore_certs + java_keystore_new_certs }}"
when: remote_cert
- name: Check that the remote private keys have not been removed
ansible.builtin.file:
path: "{{ output_dir ~ '/' ~ item.name ~ '.key' }}"
state: file
loop: "{{ java_keystore_certs }}"
when: remote_cert
- name: Validate results
assert:
that:
- result is changed
- result_check is changed
- result_idem is not changed
- result_idem_check is not changed
- result_change is changed
- result_change_check is changed
# - result_alias_change is changed # FIXME: module currently crashes
# - result_alias_change_check is changed # FIXME: module currently crashes
# - result_pw_change is changed # FIXME: module currently crashes
# - result_pw_change_check is changed # FIXME: module currently crashes