From 188903448ab26dfd025cbea2abbba2b54cc93f55 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 30 Mar 2019 15:38:43 +0100 Subject: [PATCH] openssl_*: add backup option (#54294) --- .../fragments/54294-openssl-backup.yaml | 6 +++ .../modules/crypto/openssl_certificate.py | 48 ++++++++++++++++++ lib/ansible/modules/crypto/openssl_csr.py | 28 +++++++++++ lib/ansible/modules/crypto/openssl_dhparam.py | 26 ++++++++++ lib/ansible/modules/crypto/openssl_pkcs12.py | 25 ++++++++++ .../modules/crypto/openssl_privatekey.py | 2 +- .../modules/crypto/openssl_publickey.py | 25 ++++++++++ .../openssl_certificate/tasks/ownca.yml | 50 +++++++++++++++++++ .../openssl_certificate/tasks/selfsigned.yml | 47 +++++++++++++++++ .../tests/validate_ownca.yml | 14 ++++++ .../tests/validate_selfsigned.yml | 14 ++++++ .../targets/openssl_csr/tasks/impl.yml | 42 ++++++++++++++++ .../targets/openssl_csr/tests/validate.yml | 14 ++++++ .../targets/openssl_dhparam/tasks/main.yml | 32 ++++++++++++ .../openssl_dhparam/tests/validate.yml | 14 ++++++ .../targets/openssl_pkcs12/tasks/impl.yml | 42 ++++++++++++++++ .../targets/openssl_pkcs12/tests/validate.yml | 16 +++++- .../targets/openssl_publickey/tasks/main.yml | 33 ++++++++++++ .../openssl_publickey/tests/validate.yml | 18 +++++++ 19 files changed, 494 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/54294-openssl-backup.yaml diff --git a/changelogs/fragments/54294-openssl-backup.yaml b/changelogs/fragments/54294-openssl-backup.yaml new file mode 100644 index 00000000000..9582dbe355b --- /dev/null +++ b/changelogs/fragments/54294-openssl-backup.yaml @@ -0,0 +1,6 @@ +minor_changes: +- "openssl_certificate - add ``backup`` option." +- "openssl_csr - add ``backup`` option." +- "openssl_dhparam - add ``backup`` option." +- "openssl_pkcs12 - add ``backup`` option." +- "openssl_publickey - add ``backup`` option." diff --git a/lib/ansible/modules/crypto/openssl_certificate.py b/lib/ansible/modules/crypto/openssl_certificate.py index baf56d4cc5d..c65eef8f03a 100644 --- a/lib/ansible/modules/crypto/openssl_certificate.py +++ b/lib/ansible/modules/crypto/openssl_certificate.py @@ -28,6 +28,9 @@ description: - Many properties that can be specified in this module are for validation of an existing or newly generated certificate. The proper place to specify them, if you want to receive a certificate with these properties is a CSR (Certificate Signing Request). + - "Please note that the module regenerates existing certificate if it doesn't match the module's + options, or if it seems to be corrupt. If you are concerned that this could overwrite + your existing certificate, consider using the I(backup) option." - It uses the pyOpenSSL or cryptography python library to interact with OpenSSL. - If both the cryptography and PyOpenSSL libraries are available (and meet the minimum version requirements) cryptography will be preferred as a backend over PyOpenSSL (unless the backend is forced with C(select_crypto_backend)) @@ -359,6 +362,15 @@ options: choices: [ auto, cryptography, pyopenssl ] version_added: "2.8" + backup: + description: + - Create a backup file including a timestamp so you can get the original + certificate back if you overwrote it with a new one by accident. + - This is not used by the C(assertonly) provider. + type: bool + default: no + version_added: "2.8" + extends_documentation_fragment: files notes: - All ASN.1 TIME values should be specified following the YYYYMMDDHHMMSSZ pattern. @@ -510,6 +522,11 @@ filename: returned: changed or success type: str sample: /etc/ssl/crt/www.ansible.com.crt +backup_file: + description: Name of backup file created. + returned: changed and if I(backup) is C(yes) + type: str + sample: /path/to/www.ansible.com.crt.2019-03-09@11:22~ ''' @@ -576,6 +593,9 @@ class Certificate(crypto_utils.OpenSSLObject): self.backend = backend self.module = module + self.backup = module.params['backup'] + self.backup_file = None + def get_relative_time_option(self, input_string, input_name): """Return an ASN1 formatted string if a relative timespec or an ASN1 formatted string is provided.""" @@ -663,6 +683,11 @@ class Certificate(crypto_utils.OpenSSLObject): return False return True + def remove(self, module): + if self.backup: + self.backup_file = module.backup_local(self.path) + super(Certificate, self).remove(module) + def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" @@ -711,6 +736,8 @@ class CertificateAbsent(Certificate): 'privatekey': self.privatekey_path, 'csr': self.csr_path } + if self.backup_file: + result['backup_file'] = self.backup_file return result @@ -769,6 +796,8 @@ class SelfSignedCertificateCryptography(Certificate): self.cert = certificate + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, certificate.public_bytes(Encoding.PEM)) self.changed = True else: @@ -786,6 +815,8 @@ class SelfSignedCertificateCryptography(Certificate): 'privatekey': self.privatekey_path, 'csr': self.csr_path } + if self.backup_file: + result['backup_file'] = self.backup_file if check_mode: result.update({ @@ -847,6 +878,8 @@ class SelfSignedCertificate(Certificate): cert.sign(self.privatekey, self.digest) self.cert = cert + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert)) self.changed = True @@ -862,6 +895,8 @@ class SelfSignedCertificate(Certificate): 'privatekey': self.privatekey_path, 'csr': self.csr_path } + if self.backup_file: + result['backup_file'] = self.backup_file if check_mode: result.update({ @@ -935,6 +970,8 @@ class OwnCACertificateCryptography(Certificate): self.cert = certificate + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, certificate.public_bytes(Encoding.PEM)) self.changed = True else: @@ -954,6 +991,8 @@ class OwnCACertificateCryptography(Certificate): 'ca_cert': self.ca_cert_path, 'ca_privatekey': self.ca_privatekey_path } + if self.backup_file: + result['backup_file'] = self.backup_file if check_mode: result.update({ @@ -1024,6 +1063,8 @@ class OwnCACertificate(Certificate): cert.sign(self.ca_privatekey, self.digest) self.cert = cert + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert)) self.changed = True @@ -1041,6 +1082,8 @@ class OwnCACertificate(Certificate): 'ca_cert': self.ca_cert_path, 'ca_privatekey': self.ca_privatekey_path } + if self.backup_file: + result['backup_file'] = self.backup_file if check_mode: result.update({ @@ -1614,6 +1657,8 @@ class AcmeCertificate(Certificate): self.csr_path, self.challenge_path), check_rc=True)[1] + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, to_bytes(crt)) self.changed = True except OSError as exc: @@ -1632,6 +1677,8 @@ class AcmeCertificate(Certificate): 'accountkey': self.accountkey_path, 'csr': self.csr_path, } + if self.backup_file: + result['backup_file'] = self.backup_file return result @@ -1644,6 +1691,7 @@ def main(): provider=dict(type='str', choices=['acme', 'assertonly', 'ownca', 'selfsigned']), force=dict(type='bool', default=False,), csr_path=dict(type='path'), + backup=dict(type='bool', default=False), select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), # General properties of a certificate diff --git a/lib/ansible/modules/crypto/openssl_csr.py b/lib/ansible/modules/crypto/openssl_csr.py index f5e32ac60b1..d9932bf5321 100644 --- a/lib/ansible/modules/crypto/openssl_csr.py +++ b/lib/ansible/modules/crypto/openssl_csr.py @@ -21,6 +21,9 @@ description: - It uses the pyOpenSSL python library to interact with openssl. This module supports the subjectAltName, keyUsage, extendedKeyUsage, basicConstraints and OCSP Must Staple extensions. + - "Please note that the module regenerates existing CSR if it doesn't match the module's + options, or if it seems to be corrupt. If you are concerned that this could overwrite + your existing CSR, consider using the I(backup) option." requirements: - Either cryptography >= 1.3 - Or pyOpenSSL >= 0.15 @@ -190,6 +193,13 @@ options: default: auto choices: [ auto, cryptography, pyopenssl ] version_added: '2.8' + backup: + description: + - Create a backup file including a timestamp so you can get the original + CSR back if you overwrote it with a new one by accident. + type: bool + default: no + version_added: "2.8" extends_documentation_fragment: - files notes: @@ -311,6 +321,11 @@ ocsp_must_staple: returned: changed or success type: bool sample: false +backup_file: + description: Name of backup file created. + returned: changed and if I(backup) is C(yes) + type: str + sample: /path/to/www.ansible.com.csr.2019-03-09@11:22~ ''' import abc @@ -394,6 +409,9 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject): self.request = None self.privatekey = None + self.backup = module.params['backup'] + self.backup_file = None + self.subject = [ ('C', module.params['country_name']), ('ST', module.params['state_or_province_name']), @@ -422,6 +440,8 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject): '''Generate the certificate signing request.''' if not self.check(module, perms_required=False) or self.force: result = self._generate_csr() + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, result) self.changed = True @@ -448,6 +468,11 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject): return self._check_csr() + def remove(self, module): + if self.backup: + self.backup_file = module.backup_local(self.path) + super(CertificateSigningRequestBase, self).remove(module) + def dump(self): '''Serialize the object into a dictionary.''' @@ -462,6 +487,8 @@ class CertificateSigningRequestBase(crypto_utils.OpenSSLObject): 'ocspMustStaple': self.ocspMustStaple, 'changed': self.changed } + if self.backup_file: + result['backup_file'] = self.backup_file return result @@ -829,6 +856,7 @@ def main(): basic_constraints_critical=dict(type='bool', default=False, aliases=['basicConstraints_critical']), ocsp_must_staple=dict(type='bool', default=False, aliases=['ocspMustStaple']), ocsp_must_staple_critical=dict(type='bool', default=False, aliases=['ocspMustStaple_critical']), + backup=dict(type='bool', default=False), select_crypto_backend=dict(type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), ), add_file_common_args=True, diff --git a/lib/ansible/modules/crypto/openssl_dhparam.py b/lib/ansible/modules/crypto/openssl_dhparam.py index 16c8a297e55..4cefb10823b 100644 --- a/lib/ansible/modules/crypto/openssl_dhparam.py +++ b/lib/ansible/modules/crypto/openssl_dhparam.py @@ -19,6 +19,9 @@ short_description: Generate OpenSSL Diffie-Hellman Parameters description: - This module allows one to (re)generate OpenSSL DH-params. - This module uses file common arguments to specify generated file permissions. + - "Please note that the module regenerates existing DH params if they don't + match the module's options. If you are concerned that this could overwrite + your existing DH params, consider using the I(backup) option." requirements: - OpenSSL author: @@ -46,6 +49,13 @@ options: - Name of the file in which the generated parameters will be saved. type: path required: true + backup: + description: + - Create a backup file including a timestamp so you can get the original + DH params back if you overwrote them with new ones by accident. + type: bool + default: no + version_added: "2.8" extends_documentation_fragment: - files seealso: @@ -83,6 +93,11 @@ filename: returned: changed or success type: str sample: /etc/ssl/dhparams.pem +backup_file: + description: Name of backup file created. + returned: changed and if I(backup) is C(yes) + type: str + sample: /path/to/dhparams.pem.2019-03-09@11:22~ ''' import os @@ -107,6 +122,9 @@ class DHParameter(object): self.changed = False self.openssl_bin = module.get_bin_path('openssl', True) + self.backup = module.params['backup'] + self.backup_file = None + def generate(self, module): """Generate a keypair.""" changed = False @@ -122,6 +140,8 @@ class DHParameter(object): rc, dummy, err = module.run_command(command, check_rc=False) if rc != 0: raise DHParameterError(to_native(err)) + if self.backup: + self.backup_file = module.backup_local(self.path) try: module.atomic_move(tmpsrc, self.path) except Exception as e: @@ -137,6 +157,8 @@ class DHParameter(object): self.changed = changed def remove(self, module): + if self.backup: + self.backup_file = module.backup_local(self.path) try: os.remove(self.path) self.changed = True @@ -186,6 +208,9 @@ class DHParameter(object): 'filename': self.path, 'changed': self.changed, } + if self.backup_file: + result['backup_file'] = self.backup_file + return result @@ -198,6 +223,7 @@ def main(): size=dict(type='int', default=4096), force=dict(type='bool', default=False), path=dict(type='path', required=True), + backup=dict(type='bool', default=False), ), supports_check_mode=True, add_file_common_args=True, diff --git a/lib/ansible/modules/crypto/openssl_pkcs12.py b/lib/ansible/modules/crypto/openssl_pkcs12.py index f0a912d043b..41ed7031398 100644 --- a/lib/ansible/modules/crypto/openssl_pkcs12.py +++ b/lib/ansible/modules/crypto/openssl_pkcs12.py @@ -86,6 +86,13 @@ options: description: - PKCS#12 file path to parse. type: path + backup: + description: + - Create a backup file including a timestamp so you can get the original + output file back if you overwrote it with a new one by accident. + type: bool + default: no + version_added: "2.8" extends_documentation_fragment: - files seealso: @@ -155,6 +162,11 @@ privatekey: returned: changed or success type: str sample: /etc/ssl/private/ansible.com.pem +backup_file: + description: Name of backup file created. + returned: changed and if I(backup) is C(yes) + type: str + sample: /path/to/ansible.com.pem.2019-03-09@11:22~ ''' import stat @@ -203,6 +215,9 @@ class Pkcs(crypto_utils.OpenSSLObject): if module.params['mode'] is None: module.params['mode'] = '0400' + self.backup = module.params['backup'] + self.backup_file = None + def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" @@ -232,6 +247,8 @@ class Pkcs(crypto_utils.OpenSSLObject): } if self.privatekey_path: result['privatekey_path'] = self.privatekey_path + if self.backup_file: + result['backup_file'] = self.backup_file return result @@ -261,12 +278,19 @@ class Pkcs(crypto_utils.OpenSSLObject): except crypto_utils.OpenSSLBadPassphraseError as exc: raise PkcsError(exc) + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file( module, self.pkcs12.export(self.passphrase, self.iter_size, self.maciter_size), 0o600 ) + def remove(self, module): + if self.backup: + self.backup_file = module.backup_local(self.path) + super(Pkcs, self).remove(module) + def parse(self, module): """Read PKCS#12 file.""" @@ -301,6 +325,7 @@ def main(): privatekey_path=dict(type='path'), state=dict(type='str', default='present', choices=['absent', 'present']), src=dict(type='path'), + backup=dict(type='bool', default=False), ) required_if = [ diff --git a/lib/ansible/modules/crypto/openssl_privatekey.py b/lib/ansible/modules/crypto/openssl_privatekey.py index c4eb51f4172..494b9c90c60 100644 --- a/lib/ansible/modules/crypto/openssl_privatekey.py +++ b/lib/ansible/modules/crypto/openssl_privatekey.py @@ -26,7 +26,7 @@ description: - "Please note that the module regenerates private keys if they don't match the module's options. In particular, if you provide another passphrase (or specify none), change the keysize, etc., the private key will be - regenerated. If you are concerned that this could overwrite your private key, + regenerated. If you are concerned that this could **overwrite your private key**, consider using the I(backup) option." - The module can use the cryptography Python library, or the pyOpenSSL Python library. By default, it tries to detect which one is available. This can be diff --git a/lib/ansible/modules/crypto/openssl_publickey.py b/lib/ansible/modules/crypto/openssl_publickey.py index b8144e362d5..b189dffaadb 100644 --- a/lib/ansible/modules/crypto/openssl_publickey.py +++ b/lib/ansible/modules/crypto/openssl_publickey.py @@ -59,6 +59,13 @@ options: - The passphrase for the private key. type: str version_added: "2.4" + backup: + description: + - Create a backup file including a timestamp so you can get the original + public key back if you overwrote it with a different one by accident. + type: bool + default: no + version_added: "2.8" extends_documentation_fragment: - files seealso: @@ -129,6 +136,11 @@ fingerprint: sha256: "41:ab:c7:cb:d5:5f:30:60:46:99:ac:d4:00:70:cf:a1:76:4f:24:5d:10:24:57:5d:51:6e:09:97:df:2f:de:c7" sha384: "85:39:50:4e:de:d9:19:33:40:70:ae:10:ab:59:24:19:51:c3:a2:e4:0b:1c:b1:6e:dd:b3:0c:d9:9e:6a:46:af:da:18:f8:ef:ae:2e:c0:9a:75:2c:9b:b3:0f:3a:5f:3d" sha512: "fd:ed:5e:39:48:5f:9f:fe:7f:25:06:3f:79:08:cd:ee:a5:e7:b3:3d:13:82:87:1f:84:e1:f5:c7:28:77:53:94:86:56:38:69:f0:d9:35:22:01:1e:a6:60:...:0f:9b" +backup_file: + description: Name of backup file created. + returned: changed and if I(backup) is C(yes) + type: str + sample: /path/to/publickey.pem.2019-03-09@11:22~ ''' import os @@ -169,6 +181,9 @@ class PublicKey(crypto_utils.OpenSSLObject): self.privatekey = None self.fingerprint = {} + self.backup = module.params['backup'] + self.backup_file = None + def generate(self, module): """Generate the public key.""" @@ -197,6 +212,8 @@ class PublicKey(crypto_utils.OpenSSLObject): ) publickey_content = crypto.dump_publickey(crypto.FILETYPE_PEM, self.privatekey) + if self.backup: + self.backup_file = module.backup_local(self.path) crypto_utils.write_file(module, publickey_content) self.changed = True @@ -253,6 +270,11 @@ class PublicKey(crypto_utils.OpenSSLObject): return _check_privatekey() + def remove(self, module): + if self.backup: + self.backup_file = module.backup_local(self.path) + super(PublicKey, self).remove(module) + def dump(self): """Serialize the object into a dictionary.""" @@ -263,6 +285,8 @@ class PublicKey(crypto_utils.OpenSSLObject): 'changed': self.changed, 'fingerprint': self.fingerprint, } + if self.backup_file: + result['backup_file'] = self.backup_file return result @@ -277,6 +301,7 @@ def main(): privatekey_path=dict(type='path'), format=dict(type='str', default='PEM', choices=['OpenSSH', 'PEM']), privatekey_passphrase=dict(type='str', no_log=True), + backup=dict(type='bool', default=False), ), supports_check_mode=True, add_file_common_args=True, diff --git a/test/integration/targets/openssl_certificate/tasks/ownca.yml b/test/integration/targets/openssl_certificate/tasks/ownca.yml index 59f544a3d43..acdc2a437c9 100644 --- a/test/integration/targets/openssl_certificate/tasks/ownca.yml +++ b/test/integration/targets/openssl_certificate/tasks/ownca.yml @@ -217,4 +217,54 @@ ownca_digest: sha256 register: ownca_broken +- name: (OwnCA, {{select_crypto_backend}}) Backup test + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_backup.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + ownca_path: '{{ output_dir }}/ca_cert.pem' + ownca_privatekey_path: '{{ output_dir }}/privatekey.pem' + provider: ownca + ownca_digest: sha256 + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: ownca_backup_1 +- name: (OwnCA, {{select_crypto_backend}}) Backup test (idempotent) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_backup.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + ownca_path: '{{ output_dir }}/ca_cert.pem' + ownca_privatekey_path: '{{ output_dir }}/privatekey.pem' + provider: ownca + ownca_digest: sha256 + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: ownca_backup_2 +- name: (OwnCA, {{select_crypto_backend}}) Backup test (change) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_backup.pem' + csr_path: '{{ output_dir }}/csr.csr' + ownca_path: '{{ output_dir }}/ca_cert.pem' + ownca_privatekey_path: '{{ output_dir }}/privatekey.pem' + provider: ownca + ownca_digest: sha256 + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: ownca_backup_3 +- name: (OwnCA, {{select_crypto_backend}}) Backup test (remove) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_backup.pem' + state: absent + provider: ownca + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: ownca_backup_4 +- name: (OwnCA, {{select_crypto_backend}}) Backup test (remove, idempotent) + openssl_certificate: + path: '{{ output_dir }}/ownca_cert_backup.pem' + state: absent + provider: ownca + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: ownca_backup_5 + - import_tasks: ../tests/validate_ownca.yml diff --git a/test/integration/targets/openssl_certificate/tasks/selfsigned.yml b/test/integration/targets/openssl_certificate/tasks/selfsigned.yml index 06c73ded9c2..2398639a45e 100644 --- a/test/integration/targets/openssl_certificate/tasks/selfsigned.yml +++ b/test/integration/targets/openssl_certificate/tasks/selfsigned.yml @@ -224,4 +224,51 @@ selfsigned_digest: sha256 register: selfsigned_broken +- name: (Selfsigned, {{select_crypto_backend}}) Backup test + openssl_certificate: + path: '{{ output_dir }}/selfsigned_cert_backup.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + privatekey_path: '{{ output_dir }}/privatekey_ecc.pem' + provider: selfsigned + selfsigned_digest: sha256 + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: selfsigned_backup_1 +- name: (Selfsigned, {{select_crypto_backend}}) Backup test (idempotent) + openssl_certificate: + path: '{{ output_dir }}/selfsigned_cert_backup.pem' + csr_path: '{{ output_dir }}/csr_ecc.csr' + privatekey_path: '{{ output_dir }}/privatekey_ecc.pem' + provider: selfsigned + selfsigned_digest: sha256 + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: selfsigned_backup_2 +- name: (Selfsigned, {{select_crypto_backend}}) Backup test (change) + openssl_certificate: + path: '{{ output_dir }}/selfsigned_cert_backup.pem' + csr_path: '{{ output_dir }}/csr.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + provider: selfsigned + selfsigned_digest: sha256 + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: selfsigned_backup_3 +- name: (Selfsigned, {{select_crypto_backend}}) Backup test (remove) + openssl_certificate: + path: '{{ output_dir }}/selfsigned_cert_backup.pem' + state: absent + provider: selfsigned + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: selfsigned_backup_4 +- name: (Selfsigned, {{select_crypto_backend}}) Backup test (remove, idempotent) + openssl_certificate: + path: '{{ output_dir }}/selfsigned_cert_backup.pem' + state: absent + provider: selfsigned + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: selfsigned_backup_5 + - import_tasks: ../tests/validate_selfsigned.yml diff --git a/test/integration/targets/openssl_certificate/tests/validate_ownca.yml b/test/integration/targets/openssl_certificate/tests/validate_ownca.yml index b3f07ba3522..3d90d75fcca 100644 --- a/test/integration/targets/openssl_certificate/tests/validate_ownca.yml +++ b/test/integration/targets/openssl_certificate/tests/validate_ownca.yml @@ -106,3 +106,17 @@ assert: that: - ownca_broken is changed + +- name: Check backup + assert: + that: + - ownca_backup_1 is changed + - ownca_backup_1.backup_file is undefined + - ownca_backup_2 is not changed + - ownca_backup_2.backup_file is undefined + - ownca_backup_3 is changed + - ownca_backup_3.backup_file is string + - ownca_backup_4 is changed + - ownca_backup_4.backup_file is string + - ownca_backup_5 is not changed + - ownca_backup_5.backup_file is undefined diff --git a/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml b/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml index b77b44885d0..a357f7f8160 100644 --- a/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml +++ b/test/integration/targets/openssl_certificate/tests/validate_selfsigned.yml @@ -107,3 +107,17 @@ assert: that: - selfsigned_broken is changed + +- name: Check backup + assert: + that: + - selfsigned_backup_1 is changed + - selfsigned_backup_1.backup_file is undefined + - selfsigned_backup_2 is not changed + - selfsigned_backup_2.backup_file is undefined + - selfsigned_backup_3 is changed + - selfsigned_backup_3.backup_file is string + - selfsigned_backup_4 is changed + - selfsigned_backup_4.backup_file is string + - selfsigned_backup_5 is not changed + - selfsigned_backup_5.backup_file is undefined diff --git a/test/integration/targets/openssl_csr/tasks/impl.yml b/test/integration/targets/openssl_csr/tasks/impl.yml index d5861d86353..f5af14cfa77 100644 --- a/test/integration/targets/openssl_csr/tasks/impl.yml +++ b/test/integration/targets/openssl_csr/tasks/impl.yml @@ -288,3 +288,45 @@ useCommonNameForSAN: no select_crypto_backend: '{{ select_crypto_backend }}' register: output_broken + +- name: Generate CSR + openssl_csr: + path: '{{ output_dir }}/csr_backup.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + subject: + commonName: www.ansible.com + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: csr_backup_1 +- name: Generate CSR (idempotent) + openssl_csr: + path: '{{ output_dir }}/csr_backup.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + subject: + commonName: www.ansible.com + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: csr_backup_2 +- name: Generate CSR (change) + openssl_csr: + path: '{{ output_dir }}/csr_backup.csr' + privatekey_path: '{{ output_dir }}/privatekey.pem' + subject: + commonName: ansible.com + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: csr_backup_3 +- name: Generate CSR (remove) + openssl_csr: + path: '{{ output_dir }}/csr_backup.csr' + state: absent + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: csr_backup_4 +- name: Generate CSR (remove, idempotent) + openssl_csr: + path: '{{ output_dir }}/csr_backup.csr' + state: absent + backup: yes + select_crypto_backend: '{{ select_crypto_backend }}' + register: csr_backup_5 diff --git a/test/integration/targets/openssl_csr/tests/validate.yml b/test/integration/targets/openssl_csr/tests/validate.yml index a6d36a8d07f..585cf64c0a2 100644 --- a/test/integration/targets/openssl_csr/tests/validate.yml +++ b/test/integration/targets/openssl_csr/tests/validate.yml @@ -124,3 +124,17 @@ assert: that: - output_broken is changed + +- name: Check backup + assert: + that: + - csr_backup_1 is changed + - csr_backup_1.backup_file is undefined + - csr_backup_2 is not changed + - csr_backup_2.backup_file is undefined + - csr_backup_3 is changed + - csr_backup_3.backup_file is string + - csr_backup_4 is changed + - csr_backup_4.backup_file is string + - csr_backup_5 is not changed + - csr_backup_5.backup_file is undefined diff --git a/test/integration/targets/openssl_dhparam/tasks/main.yml b/test/integration/targets/openssl_dhparam/tasks/main.yml index 7612ec8932f..bf788abbd8c 100644 --- a/test/integration/targets/openssl_dhparam/tasks/main.yml +++ b/test/integration/targets/openssl_dhparam/tasks/main.yml @@ -53,4 +53,36 @@ force: yes register: output_broken + - name: Generate params + openssl_dhparam: + path: '{{ output_dir }}/dh_backup.pem' + size: 512 + backup: yes + register: dhparam_backup_1 + - name: Generate params (idempotent) + openssl_dhparam: + path: '{{ output_dir }}/dh_backup.pem' + size: 512 + backup: yes + register: dhparam_backup_2 + - name: Generate params (change) + openssl_dhparam: + path: '{{ output_dir }}/dh_backup.pem' + size: 512 + force: yes + backup: yes + register: dhparam_backup_3 + - name: Generate params (remove) + openssl_dhparam: + path: '{{ output_dir }}/dh_backup.pem' + state: absent + backup: yes + register: dhparam_backup_4 + - name: Generate params (remove, idempotent) + openssl_dhparam: + path: '{{ output_dir }}/dh_backup.pem' + state: absent + backup: yes + register: dhparam_backup_5 + - import_tasks: ../tests/validate.yml diff --git a/test/integration/targets/openssl_dhparam/tests/validate.yml b/test/integration/targets/openssl_dhparam/tests/validate.yml index 380cd2cba51..b4a2857255f 100644 --- a/test/integration/targets/openssl_dhparam/tests/validate.yml +++ b/test/integration/targets/openssl_dhparam/tests/validate.yml @@ -35,3 +35,17 @@ assert: that: - output_broken is changed + +- name: Check backup + assert: + that: + - dhparam_backup_1 is changed + - dhparam_backup_1.backup_file is undefined + - dhparam_backup_2 is not changed + - dhparam_backup_2.backup_file is undefined + - dhparam_backup_3 is changed + - dhparam_backup_3.backup_file is string + - dhparam_backup_4 is changed + - dhparam_backup_4.backup_file is string + - dhparam_backup_5 is not changed + - dhparam_backup_5.backup_file is undefined diff --git a/test/integration/targets/openssl_pkcs12/tasks/impl.yml b/test/integration/targets/openssl_pkcs12/tasks/impl.yml index f4634013330..54318610021 100644 --- a/test/integration/targets/openssl_pkcs12/tasks/impl.yml +++ b/test/integration/targets/openssl_pkcs12/tasks/impl.yml @@ -1,3 +1,4 @@ +--- - block: - name: 'Generate privatekey with' openssl_privatekey: @@ -115,6 +116,47 @@ mode: 0644 register: output_broken + - name: 'Generate PKCS#12 file' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_backup.p12" + friendly_name: 'abracadabra' + privatekey_path: "{{ output_dir }}/ansible_pkey.pem" + certificate_path: "{{ output_dir }}/ansible.crt" + state: present + backup: yes + register: p12_backup_1 + - name: 'Generate PKCS#12 file (idempotent)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_backup.p12" + friendly_name: 'abracadabra' + privatekey_path: "{{ output_dir }}/ansible_pkey.pem" + certificate_path: "{{ output_dir }}/ansible.crt" + state: present + backup: yes + register: p12_backup_2 + - name: 'Generate PKCS#12 file (change)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_backup.p12" + friendly_name: 'abra' + privatekey_path: "{{ output_dir }}/ansible_pkey.pem" + certificate_path: "{{ output_dir }}/ansible.crt" + state: present + force: yes # FIXME: idempotency does not work, so we have to force! (https://github.com/ansible/ansible/issues/53221) + backup: yes + register: p12_backup_3 + - name: 'Generate PKCS#12 file (remove)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_backup.p12" + state: absent + backup: yes + register: p12_backup_4 + - name: 'Generate PKCS#12 file (remove, idempotent)' + openssl_pkcs12: + path: "{{ output_dir }}/ansible_backup.p12" + state: absent + backup: yes + register: p12_backup_5 + - import_tasks: ../tests/validate.yml always: diff --git a/test/integration/targets/openssl_pkcs12/tests/validate.yml b/test/integration/targets/openssl_pkcs12/tests/validate.yml index a44622d8a04..da88d0c7b7e 100644 --- a/test/integration/targets/openssl_pkcs12/tests/validate.yml +++ b/test/integration/targets/openssl_pkcs12/tests/validate.yml @@ -22,7 +22,7 @@ - p12_force.changed - p12_force_and_mode.mode == '0644' and p12_force_and_mode.changed -- name: +- name: Check passphrase on private key assert: that: - passphrase_error_1 is failed @@ -36,3 +36,17 @@ assert: that: - output_broken is changed + +- name: Check backup + assert: + that: + - p12_backup_1 is changed + - p12_backup_1.backup_file is undefined + - p12_backup_2 is not changed + - p12_backup_2.backup_file is undefined + - p12_backup_3 is changed + - p12_backup_3.backup_file is string + - p12_backup_4 is changed + - p12_backup_4.backup_file is string + - p12_backup_5 is not changed + - p12_backup_5.backup_file is undefined diff --git a/test/integration/targets/openssl_publickey/tasks/main.yml b/test/integration/targets/openssl_publickey/tasks/main.yml index 9ab1c24487a..c83c3971cbd 100644 --- a/test/integration/targets/openssl_publickey/tasks/main.yml +++ b/test/integration/targets/openssl_publickey/tasks/main.yml @@ -74,9 +74,23 @@ curve: secp256k1 - name: Generate publickey 5 - PEM format + openssl_publickey: + path: '{{ output_dir }}/publickey5.pub' + privatekey_path: '{{ output_dir }}/privatekey.pem' + backup: yes + register: privatekey5_1 + - name: Generate publickey 5 - PEM format (idempotent) + openssl_publickey: + path: '{{ output_dir }}/publickey5.pub' + privatekey_path: '{{ output_dir }}/privatekey.pem' + backup: yes + register: privatekey5_2 + - name: Generate publickey 5 - PEM format (different private key) openssl_publickey: path: '{{ output_dir }}/publickey5.pub' privatekey_path: '{{ output_dir }}/privatekey5.pem' + backup: yes + register: privatekey5_3 - name: Generate privatekey with password openssl_privatekey: @@ -118,6 +132,25 @@ privatekey_path: '{{ output_dir }}/privatekey5.pem' register: output_broken + - name: Generate publickey - PEM format (for removal) + openssl_publickey: + path: '{{ output_dir }}/publickey_removal.pub' + privatekey_path: '{{ output_dir }}/privatekey.pem' + - name: Generate publickey - PEM format (removal) + openssl_publickey: + state: absent + path: '{{ output_dir }}/publickey_removal.pub' + privatekey_path: '{{ output_dir }}/privatekey.pem' + backup: yes + register: remove_1 + - name: Generate publickey - PEM format (removal, idempotent) + openssl_publickey: + state: absent + path: '{{ output_dir }}/publickey_removal.pub' + privatekey_path: '{{ output_dir }}/privatekey.pem' + backup: yes + register: remove_2 + - import_tasks: ../tests/validate.yml when: pyopenssl_version.stdout is version('16.0.0', '>=') diff --git a/test/integration/targets/openssl_publickey/tests/validate.yml b/test/integration/targets/openssl_publickey/tests/validate.yml index 2a012884fdf..83011b210ca 100644 --- a/test/integration/targets/openssl_publickey/tests/validate.yml +++ b/test/integration/targets/openssl_publickey/tests/validate.yml @@ -83,6 +83,16 @@ - publickey4_modulus.stdout == privatekey4_modulus.stdout when: openssl_version.stdout is version('0.9.8zh', '>=') +- name: Validate idempotency and backup + assert: + that: + - privatekey5_1 is changed + - privatekey5_1.backup_file is undefined + - privatekey5_2 is not changed + - privatekey5_2.backup_file is undefined + - privatekey5_3 is changed + - privatekey5_3.backup_file is string + - name: Validate public key 5 (test - privatekey's pubkey) command: 'openssl ec -in {{ output_dir }}/privatekey5.pem -pubout' register: privatekey5_pubkey @@ -111,3 +121,11 @@ assert: that: - output_broken is changed + +- name: Validate remove + assert: + that: + - remove_1 is changed + - remove_2 is not changed + - remove_1.backup_file is string + - remove_2.backup_file is undefined