ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
819 stars 1.5k forks source link

java_cert: module does not detect failure conditions of keytool #6685

Open navoooo opened 1 year ago

navoooo commented 1 year ago

Summary

The OpenJDK issue of keytool does not appear to return RCs > 0 for at least some errors, which is the only check performed in java_cert. Some errors may be caught if the keystore is newly created (for PKCS12 only), but modifications and failures to modify are not necessarily identified correctly.

Relevant code segments:

Issue Type

Bug Report

Component Name

java_cert

Ansible Version

$ ansible --version
ansible [core 2.12.10]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.8.10 (default, May 26 2023, 14:05:08) [GCC 9.4.0]
  jinja version = 3.1.2
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general

# /usr/lib/python3/dist-packages/ansible_collections
Collection        Version
----------------- -------
community.general 4.8.3

Configuration

$ ansible-config dump --only-changed
CACHE_PLUGIN(/home/user/code/ansible/ansible.cfg) = jsonfile
CACHE_PLUGIN_CONNECTION(/home/user/code/ansible/ansible.cfg) = .fact_cache/
CACHE_PLUGIN_TIMEOUT(/home/user/code/ansible/ansible.cfg) = 86400
DEFAULT_FILTER_PLUGIN_PATH(env: ANSIBLE_FILTER_PLUGINS) = ['/home/user/code/ansible/filter_plugins']
DEFAULT_FORKS(/home/user/code/ansible/ansible.cfg) = 16
DEFAULT_GATHERING(/home/user/code/ansible/ansible.cfg) = implicit
DEFAULT_HOST_LIST(/home/user/code/ansible/ansible.cfg) = ['/home/user/code/ansible/hosts']
DEFAULT_LOG_PATH(/home/user/code/ansible/ansible.cfg) = /home/user/code/ansible/ansible.log
DEFAULT_MODULE_PATH(/home/user/code/ansible/ansible.cfg) = ['/home/user/code/ansible/library']
DEFAULT_REMOTE_USER(/home/user/code/ansible/ansible.cfg) = user
DEFAULT_ROLES_PATH(/home/user/code/ansible/ansible.cfg) = ['/home/user/code/ansible/roles']
DEFAULT_VAULT_IDENTITY_LIST(/home/user/code/ansible/ansible.cfg) = ['omitted']
RETRY_FILES_ENABLED(/home/user/code/ansible/ansible.cfg) = False

OS / Environment

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.6 LTS
Release:        20.04
Codename:       focal

keytool is provided by openjdk-11-jre-headless in version 11.0.19+7~us1-0ubuntu1~20.04.1

Steps to Reproduce

- name: Test faulty create with pkcs12
  hosts: localhost
  gather_facts: false
  vars:
    test_pkcs12_path: testpkcs.p12
    test_keystore_path: keystore.dat
  tasks:
    - name: Setup tempdir
      ansible.builtin.tempfile:
        state: directory
      register: tmpdir
    - name: Use cert from test suite
      ansible.builtin.get_url:
        dest: "{{ tmpdir.path }}/{{ test_pkcs12_path }}"
        url: "https://github.com/ansible-collections/community.general/blob/main/tests/integration/targets/java_cert/files/testpkcs.p12?raw=true"
    - name: This incidentally fails properly due to no file being created
      community.general.java_cert:
        pkcs12_path: "{{ remote_tmp_dir }}/{{ test_pkcs12_path }}"
        pkcs12_password: changeit
        pkcs12_alias: default
        cert_alias: default
        keystore_path: "{{ remote_tmp_dir }}/{{ test_keystore_path }}"
        keystore_pass: ""
        keystore_create: true
        state: present
      vars:
        remote_tmp_dir: "{{ tmpdir.path }}"
      ignore_errors: true
      register: pkcs12store
    - ansible.builtin.assert:
        that:
          - pkcs12store.failed
        fail_msg: "Keystore setup should have failed"

- name: Test faulty create with pem
  hosts: localhost
  gather_facts: false
  vars:
    test_keystore_path: keystore.dat
  tasks:
    - name: Setup tempdir
      ansible.builtin.tempfile:
        state: directory
      register: tmpdir
    - name: Create private key
      community.crypto.openssl_privatekey:
        path: "{{ tmpdir.path }}/test.key"
    - name: Create simple self-signed certificate
      community.crypto.x509_certificate:
        path: "{{ tmpdir.path }}/test.pem"
        privatekey_path: "{{ tmpdir.path }}/test.key"
        provider: selfsigned
    - name: This does not fail properly
      community.general.java_cert:
        cert_path: "{{ tmpdir.path }}/test.pem"
        cert_alias: default
        keystore_path: "{{ remote_tmp_dir }}/{{ test_keystore_path }}"
        keystore_pass: ""
        keystore_create: true
        state: present
      vars:
        remote_tmp_dir: "{{ tmpdir.path }}"
      ignore_errors: true
      register: certstore
    - ansible.builtin.assert:
        that:
          - certstore.failed
        fail_msg: "Keystore setup should have failed"

Expected Results

Neither assertion should be triggered because the underlying command does not complete in either case and the keystore is not created. I would have expected either call to java_cert to result in a fail.

Actual Results

$ ansible-playbook test.yml 
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match
'all'

PLAY [Test faulty create with pkcs12] *********************************************************************************

TASK [Setup tempdir] **************************************************************************************************
changed: [localhost]

TASK [Use cert from test suite] ***************************************************************************************
changed: [localhost]

TASK [This incidentally fails properly due to no file being created] **************************************************
fatal: [localhost]: FAILED! => {"changed": false, "cmd": ["keytool", "-importkeystore", "-noprompt", "-srcstoretype", "pkcs12", "-srckeystore", "/tmp/ansible.vu3wpgm2/testpkcs.p12", "-srcalias", "default", "-destkeystore", "/tmp/ansible.vu3wpgm2/keystore.dat", "-destalias", "default"], "error": "Keystore /tmp/ansible.vu3wpgm2/testpkcs.p12 wird in /tmp/ansible.vu3wpgm2/keystore.dat importiert...\nZiel-Keystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nZiel-Keystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nZiel-Keystore-Kennwort eingeben:  Neues Kennwort erneut eingeben: Keine Übereinstimmung. Wiederholen Sie den Vorgang\nZu viele Fehler. Versuchen Sie es später erneut\n", "msg": "", "rc": 0}
...ignoring

TASK [ansible.builtin.assert] *****************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY [Test faulty create with pem] ************************************************************************************

TASK [Setup tempdir] **************************************************************************************************
changed: [localhost]

TASK [Create private key] *********************************************************************************************
changed: [localhost]

TASK [Create simple self-signed certificate] **************************************************************************
changed: [localhost]

TASK [This does not fail properly] ************************************************************************************
changed: [localhost]

TASK [ansible.builtin.assert] *****************************************************************************************
fatal: [localhost]: FAILED! => {
    "assertion": "certstore.failed",
    "changed": false,
    "evaluated_to": false,
    "msg": "Keystore setup should have failed"
}

PLAY RECAP ************************************************************************************************************
localhost                  : ok=8    changed=6    unreachable=0    failed=1    skipped=0    rescued=0    ignored=1

Output of the relevant tasks with -v:

TASK [This incidentally fails properly due to no file being created] **************************************************
fatal: [localhost]: FAILED! => {"changed": false, "cmd": ["keytool", "-importkeystore", "-noprompt", "-srcstoretype", "pkcs12", "-srckeystore", "/tmp/ansible.m3s37ttz/testpkcs.p12", "-srcalias", "default", "-destkeystore", "/tmp/ansible.m3s37ttz/keystore.dat", "-destalias", "default"], "error": "Keystore /tmp/ansible.m3s37ttz/testpkcs.p12 wird in /tmp/ansible.m3s37ttz/keystore.dat importiert...\nZiel-Keystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nZiel-Keystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nZiel-Keystore-Kennwort eingeben:  Neues Kennwort erneut eingeben: Keine Übereinstimmung. Wiederholen Sie den Vorgang\nZu viele Fehler. Versuchen Sie es später erneut\n", "msg": "", "rc": 0}

[...]

TASK [This does not fail properly] ************************************************************************************
changed: [localhost] => {"changed": true, "cmd": ["keytool", "-importcert", "-noprompt", "-keystore", "/tmp/ansible.3bs7p9h9/keystore.dat", "-file", "/tmp/ansible.3bs7p9h9/test.pem", "-alias", "default"], "error": "Keystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nKeystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nKeystore-Kennwort eingeben:  Keystore-Kennwort ist zu kurz. Es muss mindestens sechs Zeichen lang sein\nZu viele Fehler. Versuchen Sie es später erneut\n", "msg": "", "rc": 0, "stdout": "", "stdout_lines": []}

The equivalent output of keytool in an english locale is

Enter keystore password: Keystore password is too short - must be at least 6 characters Enter keystore password: Keystore password is too short - must be at least 6 characters Enter keystore password: Keystore password is too short - must be at least 6 characters Too many failures - try later

Code of Conduct

ansibullbot commented 1 year ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 1 year ago

cc @absynth76 @haad click here for bot help