diff --git a/changelogs/fragments/289-assertonly-removed.yml b/changelogs/fragments/289-assertonly-removed.yml new file mode 100644 index 00000000..234d04b3 --- /dev/null +++ b/changelogs/fragments/289-assertonly-removed.yml @@ -0,0 +1,2 @@ +removed_features: + - "x509_certificate - remove ``assertonly`` provider (https://github.com/ansible-collections/community.crypto/pull/289)." diff --git a/plugins/doc_fragments/module_certificate.py b/plugins/doc_fragments/module_certificate.py index d9f391eb..18e8727f 100644 --- a/plugins/doc_fragments/module_certificate.py +++ b/plugins/doc_fragments/module_certificate.py @@ -16,7 +16,7 @@ description: - This module allows one to (re)generate OpenSSL certificates. - It uses the cryptography python library to interact with OpenSSL. requirements: - - cryptography >= 1.6 (if using C(selfsigned), C(ownca) or C(assertonly) provider) + - cryptography >= 1.6 (if using C(selfsigned) or C(ownca) provider) options: force: description: @@ -113,201 +113,6 @@ options: default: https://acme-v02.api.letsencrypt.org/directory ''' - BACKEND_ASSERTONLY_DOCUMENTATION = r''' -description: - - The C(assertonly) provider is intended for use cases where one is only interested in - checking properties of a supplied certificate. Please note that this provider has been - deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0. See the examples on how - to emulate C(assertonly) usage with M(community.crypto.x509_certificate_info), - M(community.crypto.openssl_csr_info), M(community.crypto.openssl_privatekey_info) and - M(ansible.builtin.assert). This also allows more flexible checks than - the ones offered by the C(assertonly) provider. - - 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). -options: - csr_path: - description: - - This is not required for the C(assertonly) provider. - - csr_content: - description: - - This is not required for the C(assertonly) provider. - - signature_algorithms: - description: - - A list of algorithms that you would accept the certificate to be signed with - (e.g. ['sha256WithRSAEncryption', 'sha512WithRSAEncryption']). - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: list - elements: str - - issuer: - description: - - The key/value pairs that must be present in the issuer name field of the certificate. - - If you need to specify more than one value with the same key, use a list as value. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: dict - - issuer_strict: - description: - - If set to C(yes), the I(issuer) field must contain only these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: bool - default: no - - subject: - description: - - The key/value pairs that must be present in the subject name field of the certificate. - - If you need to specify more than one value with the same key, use a list as value. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: dict - - subject_strict: - description: - - If set to C(yes), the I(subject) field must contain only these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: bool - default: no - - has_expired: - description: - - Checks if the certificate is expired/not expired at the time the module is executed. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: bool - default: no - - version: - description: - - The version of the certificate. - - Nowadays it should almost always be 3. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: int - - valid_at: - description: - - The certificate must be valid at this point in time. - - The timestamp is formatted as an ASN.1 TIME. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: str - - invalid_at: - description: - - The certificate must be invalid at this point in time. - - The timestamp is formatted as an ASN.1 TIME. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: str - - not_before: - description: - - The certificate must start to become valid at this point in time. - - The timestamp is formatted as an ASN.1 TIME. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: str - aliases: [ notBefore ] - - not_after: - description: - - The certificate must expire at this point in time. - - The timestamp is formatted as an ASN.1 TIME. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: str - aliases: [ notAfter ] - - valid_in: - description: - - The certificate must still be valid at this relative time offset from now. - - Valid format is C([+-]timespec | number_of_seconds) where timespec can be an integer - + C([w | d | h | m | s]) (e.g. C(+32w1d2h). - - Note that if using this parameter, this module is NOT idempotent. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: str - - key_usage: - description: - - The I(key_usage) extension field must contain all these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: list - elements: str - aliases: [ keyUsage ] - - key_usage_strict: - description: - - If set to C(yes), the I(key_usage) extension field must contain only these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: bool - default: no - aliases: [ keyUsage_strict ] - - extended_key_usage: - description: - - The I(extended_key_usage) extension field must contain all these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: list - elements: str - aliases: [ extendedKeyUsage ] - - extended_key_usage_strict: - description: - - If set to C(yes), the I(extended_key_usage) extension field must contain only these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: bool - default: no - aliases: [ extendedKeyUsage_strict ] - - subject_alt_name: - description: - - The I(subject_alt_name) extension field must contain these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: list - elements: str - aliases: [ subjectAltName ] - - subject_alt_name_strict: - description: - - If set to C(yes), the I(subject_alt_name) extension field must contain only these values. - - This is only used by the C(assertonly) provider. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). - type: bool - default: no - aliases: [ subjectAltName_strict ] -''' - BACKEND_ENTRUST_DOCUMENTATION = r''' options: entrust_cert_type: diff --git a/plugins/module_utils/crypto/module_backends/certificate_assertonly.py b/plugins/module_utils/crypto/module_backends/certificate_assertonly.py deleted file mode 100644 index a73f3288..00000000 --- a/plugins/module_utils/crypto/module_backends/certificate_assertonly.py +++ /dev/null @@ -1,500 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2016-2017, Yanis Guenane -# Copyright: (c) 2017, Markus Teufelberger -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -import abc -import datetime - -from ansible.module_utils.common.text.converters import to_native, to_bytes, to_text - -from ansible_collections.community.crypto.plugins.module_utils.crypto.support import ( - parse_name_field, - get_relative_time_option, -) - -from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import ( - cryptography_compare_public_keys, - cryptography_get_name, - cryptography_name_to_oid, - cryptography_parse_key_usage_params, -) - -from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate import ( - CertificateBackend, - CertificateProvider, -) - -try: - import OpenSSL - from OpenSSL import crypto -except ImportError: - pass - -try: - import cryptography - from cryptography import x509 - from cryptography.x509 import NameAttribute, Name -except ImportError: - pass - - -def compare_sets(subset, superset, equality=False): - if equality: - return set(subset) == set(superset) - else: - return all(x in superset for x in subset) - - -def compare_dicts(subset, superset, equality=False): - if equality: - return subset == superset - else: - return all(superset.get(x) == v for x, v in subset.items()) - - -NO_EXTENSION = 'no extension' - - -class AssertOnlyCertificateBackend(CertificateBackend): - def __init__(self, module, backend): - super(AssertOnlyCertificateBackend, self).__init__(module, backend) - - self.signature_algorithms = module.params['signature_algorithms'] - if module.params['subject']: - self.subject = parse_name_field(module.params['subject']) - else: - self.subject = [] - self.subject_strict = module.params['subject_strict'] - if module.params['issuer']: - self.issuer = parse_name_field(module.params['issuer']) - else: - self.issuer = [] - self.issuer_strict = module.params['issuer_strict'] - self.has_expired = module.params['has_expired'] - self.version = module.params['version'] - self.key_usage = module.params['key_usage'] - self.key_usage_strict = module.params['key_usage_strict'] - self.extended_key_usage = module.params['extended_key_usage'] - self.extended_key_usage_strict = module.params['extended_key_usage_strict'] - self.subject_alt_name = module.params['subject_alt_name'] - self.subject_alt_name_strict = module.params['subject_alt_name_strict'] - self.not_before = module.params['not_before'] - self.not_after = module.params['not_after'] - self.valid_at = module.params['valid_at'] - self.invalid_at = module.params['invalid_at'] - self.valid_in = module.params['valid_in'] - if self.valid_in and not self.valid_in.startswith("+") and not self.valid_in.startswith("-"): - try: - int(self.valid_in) - except ValueError: - module.fail_json(msg='The supplied value for "valid_in" (%s) is not an integer or a valid timespec' % self.valid_in) - self.valid_in = "+" + self.valid_in + "s" - - # Load objects - self._ensure_private_key_loaded() - self._ensure_csr_loaded() - - @abc.abstractmethod - def _validate_privatekey(self): - pass - - @abc.abstractmethod - def _validate_csr_signature(self): - pass - - @abc.abstractmethod - def _validate_csr_subject(self): - pass - - @abc.abstractmethod - def _validate_csr_extensions(self): - pass - - @abc.abstractmethod - def _validate_signature_algorithms(self): - pass - - @abc.abstractmethod - def _validate_subject(self): - pass - - @abc.abstractmethod - def _validate_issuer(self): - pass - - @abc.abstractmethod - def _validate_has_expired(self): - pass - - @abc.abstractmethod - def _validate_version(self): - pass - - @abc.abstractmethod - def _validate_key_usage(self): - pass - - @abc.abstractmethod - def _validate_extended_key_usage(self): - pass - - @abc.abstractmethod - def _validate_subject_alt_name(self): - pass - - @abc.abstractmethod - def _validate_not_before(self): - pass - - @abc.abstractmethod - def _validate_not_after(self): - pass - - @abc.abstractmethod - def _validate_valid_at(self): - pass - - @abc.abstractmethod - def _validate_invalid_at(self): - pass - - @abc.abstractmethod - def _validate_valid_in(self): - pass - - def assertonly(self): - messages = [] - if self.privatekey_path is not None or self.privatekey_content is not None: - if not self._validate_privatekey(): - messages.append( - 'Certificate and private key %s do not match' % - (self.privatekey_path or '(provided in module options)') - ) - - if self.csr_path is not None or self.csr_content is not None: - if not self._validate_csr_signature(): - messages.append( - 'Certificate and CSR %s do not match: private key mismatch' % - (self.csr_path or '(provided in module options)') - ) - if not self._validate_csr_subject(): - messages.append( - 'Certificate and CSR %s do not match: subject mismatch' % - (self.csr_path or '(provided in module options)') - ) - if not self._validate_csr_extensions(): - messages.append( - 'Certificate and CSR %s do not match: extensions mismatch' % - (self.csr_path or '(provided in module options)') - ) - - if self.signature_algorithms is not None: - wrong_alg = self._validate_signature_algorithms() - if wrong_alg: - messages.append( - 'Invalid signature algorithm (got %s, expected one of %s)' % - (wrong_alg, self.signature_algorithms) - ) - - if self.subject is not None: - failure = self._validate_subject() - if failure: - dummy, cert_subject = failure - messages.append( - 'Invalid subject component (got %s, expected all of %s to be present)' % - (cert_subject, self.subject) - ) - - if self.issuer is not None: - failure = self._validate_issuer() - if failure: - dummy, cert_issuer = failure - messages.append( - 'Invalid issuer component (got %s, expected all of %s to be present)' % (cert_issuer, self.issuer) - ) - - if self.has_expired is not None: - cert_expired = self._validate_has_expired() - if cert_expired != self.has_expired: - messages.append( - 'Certificate expiration check failed (certificate expiration is %s, expected %s)' % - (cert_expired, self.has_expired) - ) - - if self.version is not None: - cert_version = self._validate_version() - if cert_version != self.version: - messages.append( - 'Invalid certificate version number (got %s, expected %s)' % - (cert_version, self.version) - ) - - if self.key_usage is not None: - failure = self._validate_key_usage() - if failure == NO_EXTENSION: - messages.append('Found no keyUsage extension') - elif failure: - dummy, cert_key_usage = failure - messages.append( - 'Invalid keyUsage components (got %s, expected all of %s to be present)' % - (cert_key_usage, self.key_usage) - ) - - if self.extended_key_usage is not None: - failure = self._validate_extended_key_usage() - if failure == NO_EXTENSION: - messages.append('Found no extendedKeyUsage extension') - elif failure: - dummy, ext_cert_key_usage = failure - messages.append( - 'Invalid extendedKeyUsage component (got %s, expected all of %s to be present)' % (ext_cert_key_usage, self.extended_key_usage) - ) - - if self.subject_alt_name is not None: - failure = self._validate_subject_alt_name() - if failure == NO_EXTENSION: - messages.append('Found no subjectAltName extension') - elif failure: - dummy, cert_san = failure - messages.append( - 'Invalid subjectAltName component (got %s, expected all of %s to be present)' % - (cert_san, self.subject_alt_name) - ) - - if self.not_before is not None: - cert_not_valid_before = self._validate_not_before() - if cert_not_valid_before != get_relative_time_option(self.not_before, 'not_before', backend=self.backend): - messages.append( - 'Invalid not_before component (got %s, expected %s to be present)' % - (cert_not_valid_before, self.not_before) - ) - - if self.not_after is not None: - cert_not_valid_after = self._validate_not_after() - if cert_not_valid_after != get_relative_time_option(self.not_after, 'not_after', backend=self.backend): - messages.append( - 'Invalid not_after component (got %s, expected %s to be present)' % - (cert_not_valid_after, self.not_after) - ) - - if self.valid_at is not None: - not_before, valid_at, not_after = self._validate_valid_at() - if not (not_before <= valid_at <= not_after): - messages.append( - 'Certificate is not valid for the specified date (%s) - not_before: %s - not_after: %s' % - (self.valid_at, not_before, not_after) - ) - - if self.invalid_at is not None: - not_before, invalid_at, not_after = self._validate_invalid_at() - if not_before <= invalid_at <= not_after: - messages.append( - 'Certificate is not invalid for the specified date (%s) - not_before: %s - not_after: %s' % - (self.invalid_at, not_before, not_after) - ) - - if self.valid_in is not None: - not_before, valid_in, not_after = self._validate_valid_in() - if not not_before <= valid_in <= not_after: - messages.append( - 'Certificate is not valid in %s from now (that would be %s) - not_before: %s - not_after: %s' % - (self.valid_in, valid_in, not_before, not_after) - ) - return messages - - def needs_regeneration(self): - self._ensure_existing_certificate_loaded() - if self.existing_certificate is None: - self.messages = ['Certificate not provided'] - else: - self.messages = self.assertonly() - - return len(self.messages) != 0 - - def generate_certificate(self): - self.module.fail_json(msg=' | '.join(self.messages)) - - def get_certificate_data(self): - return self.existing_certificate_bytes - - -class AssertOnlyCertificateBackendCryptography(AssertOnlyCertificateBackend): - """Validate the supplied cert, using the cryptography backend""" - def __init__(self, module): - super(AssertOnlyCertificateBackendCryptography, self).__init__(module, 'cryptography') - - def _validate_privatekey(self): - return cryptography_compare_public_keys(self.existing_certificate.public_key(), self.privatekey.public_key()) - - def _validate_csr_signature(self): - if not self.csr.is_signature_valid: - return False - return cryptography_compare_public_keys(self.csr.public_key(), self.existing_certificate.public_key()) - - def _validate_csr_subject(self): - return self.csr.subject == self.existing_certificate.subject - - def _validate_csr_extensions(self): - cert_exts = self.existing_certificate.extensions - csr_exts = self.csr.extensions - if len(cert_exts) != len(csr_exts): - return False - for cert_ext in cert_exts: - try: - csr_ext = csr_exts.get_extension_for_oid(cert_ext.oid) - if cert_ext != csr_ext: - return False - except cryptography.x509.ExtensionNotFound as dummy: - return False - return True - - def _validate_signature_algorithms(self): - if self.existing_certificate.signature_algorithm_oid._name not in self.signature_algorithms: - return self.existing_certificate.signature_algorithm_oid._name - - def _validate_subject(self): - expected_subject = Name([NameAttribute(oid=cryptography_name_to_oid(sub[0]), value=to_text(sub[1])) - for sub in self.subject]) - cert_subject = self.existing_certificate.subject - if not compare_sets(expected_subject, cert_subject, self.subject_strict): - return expected_subject, cert_subject - - def _validate_issuer(self): - expected_issuer = Name([NameAttribute(oid=cryptography_name_to_oid(iss[0]), value=to_text(iss[1])) - for iss in self.issuer]) - cert_issuer = self.existing_certificate.issuer - if not compare_sets(expected_issuer, cert_issuer, self.issuer_strict): - return self.issuer, cert_issuer - - def _validate_has_expired(self): - cert_not_after = self.existing_certificate.not_valid_after - cert_expired = cert_not_after < datetime.datetime.utcnow() - return cert_expired - - def _validate_version(self): - if self.existing_certificate.version == x509.Version.v1: - return 1 - if self.existing_certificate.version == x509.Version.v3: - return 3 - return "unknown" - - def _validate_key_usage(self): - try: - current_key_usage = self.existing_certificate.extensions.get_extension_for_class(x509.KeyUsage).value - test_key_usage = dict( - digital_signature=current_key_usage.digital_signature, - content_commitment=current_key_usage.content_commitment, - key_encipherment=current_key_usage.key_encipherment, - data_encipherment=current_key_usage.data_encipherment, - key_agreement=current_key_usage.key_agreement, - key_cert_sign=current_key_usage.key_cert_sign, - crl_sign=current_key_usage.crl_sign, - encipher_only=False, - decipher_only=False - ) - if test_key_usage['key_agreement']: - test_key_usage.update(dict( - encipher_only=current_key_usage.encipher_only, - decipher_only=current_key_usage.decipher_only - )) - - key_usages = cryptography_parse_key_usage_params(self.key_usage) - if not compare_dicts(key_usages, test_key_usage, self.key_usage_strict): - return self.key_usage, [k for k, v in test_key_usage.items() if v is True] - - except cryptography.x509.ExtensionNotFound: - # This is only bad if the user specified a non-empty list - if self.key_usage: - return NO_EXTENSION - - def _validate_extended_key_usage(self): - try: - current_ext_keyusage = self.existing_certificate.extensions.get_extension_for_class(x509.ExtendedKeyUsage).value - usages = [cryptography_name_to_oid(usage) for usage in self.extended_key_usage] - expected_ext_keyusage = x509.ExtendedKeyUsage(usages) - if not compare_sets(expected_ext_keyusage, current_ext_keyusage, self.extended_key_usage_strict): - return [eku.value for eku in expected_ext_keyusage], [eku.value for eku in current_ext_keyusage] - - except cryptography.x509.ExtensionNotFound: - # This is only bad if the user specified a non-empty list - if self.extended_key_usage: - return NO_EXTENSION - - def _validate_subject_alt_name(self): - try: - current_san = self.existing_certificate.extensions.get_extension_for_class(x509.SubjectAlternativeName).value - expected_san = [cryptography_get_name(san) for san in self.subject_alt_name] - if not compare_sets(expected_san, current_san, self.subject_alt_name_strict): - return self.subject_alt_name, current_san - except cryptography.x509.ExtensionNotFound: - # This is only bad if the user specified a non-empty list - if self.subject_alt_name: - return NO_EXTENSION - - def _validate_not_before(self): - return self.existing_certificate.not_valid_before - - def _validate_not_after(self): - return self.existing_certificate.not_valid_after - - def _validate_valid_at(self): - rt = get_relative_time_option(self.valid_at, 'valid_at', backend=self.backend) - return self.existing_certificate.not_valid_before, rt, self.existing_certificate.not_valid_after - - def _validate_invalid_at(self): - rt = get_relative_time_option(self.invalid_at, 'invalid_at', backend=self.backend) - return self.existing_certificate.not_valid_before, rt, self.existing_certificate.not_valid_after - - def _validate_valid_in(self): - valid_in_date = get_relative_time_option(self.valid_in, "valid_in", backend=self.backend) - return self.existing_certificate.not_valid_before, valid_in_date, self.existing_certificate.not_valid_after - - -class AssertOnlyCertificateProvider(CertificateProvider): - def validate_module_args(self, module): - module.deprecate("The 'assertonly' provider is deprecated; please see the examples of " - "the 'x509_certificate' module on how to replace it with other modules", - version='2.0.0', collection_name='community.crypto') - - def needs_version_two_certs(self, module): - return False - - def create_backend(self, module, backend): - if backend == 'cryptography': - return AssertOnlyCertificateBackendCryptography(module) - - -def add_assertonly_provider_to_argument_spec(argument_spec): - argument_spec.argument_spec['provider']['choices'].append('assertonly') - argument_spec.argument_spec.update(dict( - signature_algorithms=dict(type='list', elements='str', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - subject=dict(type='dict', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - subject_strict=dict(type='bool', default=False, removed_in_version='2.0.0', removed_from_collection='community.crypto'), - issuer=dict(type='dict', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - issuer_strict=dict(type='bool', default=False, removed_in_version='2.0.0', removed_from_collection='community.crypto'), - has_expired=dict(type='bool', default=False, removed_in_version='2.0.0', removed_from_collection='community.crypto'), - version=dict(type='int', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - key_usage=dict(type='list', elements='str', aliases=['keyUsage'], - removed_in_version='2.0.0', removed_from_collection='community.crypto'), - key_usage_strict=dict(type='bool', default=False, aliases=['keyUsage_strict'], - removed_in_version='2.0.0', removed_from_collection='community.crypto'), - extended_key_usage=dict(type='list', elements='str', aliases=['extendedKeyUsage'], - removed_in_version='2.0.0', removed_from_collection='community.crypto'), - extended_key_usage_strict=dict(type='bool', default=False, aliases=['extendedKeyUsage_strict'], - removed_in_version='2.0.0', removed_from_collection='community.crypto'), - subject_alt_name=dict(type='list', elements='str', aliases=['subjectAltName'], - removed_in_version='2.0.0', removed_from_collection='community.crypto'), - subject_alt_name_strict=dict(type='bool', default=False, aliases=['subjectAltName_strict'], - removed_in_version='2.0.0', removed_from_collection='community.crypto'), - not_before=dict(type='str', aliases=['notBefore'], removed_in_version='2.0.0', removed_from_collection='community.crypto'), - not_after=dict(type='str', aliases=['notAfter'], removed_in_version='2.0.0', removed_from_collection='community.crypto'), - valid_at=dict(type='str', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - invalid_at=dict(type='str', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - valid_in=dict(type='str', removed_in_version='2.0.0', removed_from_collection='community.crypto'), - )) diff --git a/plugins/modules/x509_certificate.py b/plugins/modules/x509_certificate.py index da2710f2..9baee919 100644 --- a/plugins/modules/x509_certificate.py +++ b/plugins/modules/x509_certificate.py @@ -14,7 +14,7 @@ DOCUMENTATION = r''' module: x509_certificate short_description: Generate and/or check OpenSSL certificates description: - - It implements a notion of provider (ie. C(selfsigned), C(ownca), C(acme), C(assertonly), C(entrust)) + - It implements a notion of provider (one of C(selfsigned), C(ownca), C(acme), and C(entrust)) for your certificate. - "Please note that the module regenerates existing certificate if it does not match the module's options, or if it seems to be corrupt. If you are concerned that this could overwrite @@ -47,8 +47,6 @@ options: provider: description: - Name of the provider to use to generate/retrieve the OpenSSL certificate. - - The C(assertonly) provider will not generate files and fail if the certificate file is missing. - - The C(assertonly) provider has been deprecated in Ansible 2.9 and will be removed in community.crypto 2.0.0. Please see the examples on how to emulate it with M(community.crypto.x509_certificate_info), M(community.crypto.openssl_csr_info), M(community.crypto.openssl_privatekey_info) and M(ansible.builtin.assert). @@ -56,7 +54,7 @@ options: L(Entrust Certificate Services,https://www.entrustdatacard.com/products/categories/ssl-certificates) (ECS) API." - Required if I(state) is C(present). type: str - choices: [ acme, assertonly, entrust, ownca, selfsigned ] + choices: [ acme, entrust, ownca, selfsigned ] return_content: description: @@ -69,9 +67,6 @@ options: 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. - - This option is deprecated since Ansible 2.9 and will be removed with the C(assertonly) provider in community.crypto 2.0.0. - For alternatives, see the example on replacing C(assertonly). type: bool default: no @@ -96,7 +91,6 @@ extends_documentation_fragment: - ansible.builtin.files - community.crypto.module_certificate - community.crypto.module_certificate.backend_acme_documentation - - community.crypto.module_certificate.backend_assertonly_documentation - community.crypto.module_certificate.backend_entrust_documentation - community.crypto.module_certificate.backend_ownca_documentation - community.crypto.module_certificate.backend_selfsigned_documentation @@ -150,40 +144,9 @@ EXAMPLES = r''' entrust_api_client_cert_key_path: /etc/ssl/entrust/ecs-key.crt entrust_api_specification_path: /etc/ssl/entrust/api-docs/cms-api-2.1.0.yaml -# The following example shows one assertonly usage using all existing options for -# assertonly, and shows how to emulate the behavior with the x509_certificate_info, -# openssl_csr_info, openssl_privatekey_info and assert modules: -- name: Usage of assertonly with all existing options - community.crypto.x509_certificate: - provider: assertonly - path: /etc/ssl/crt/ansible.com.crt - csr_path: /etc/ssl/csr/ansible.com.csr - privatekey_path: /etc/ssl/csr/ansible.com.key - signature_algorithms: - - sha256WithRSAEncryption - - sha512WithRSAEncryption - subject: - commonName: ansible.com - subject_strict: yes - issuer: - commonName: ansible.com - issuer_strict: yes - has_expired: no - version: 3 - key_usage: - - Data Encipherment - key_usage_strict: yes - extended_key_usage: - - DVCS - extended_key_usage_strict: yes - subject_alt_name: - - dns:ansible.com - subject_alt_name_strict: yes - not_before: 20190331202428Z - not_after: 20190413202428Z - valid_at: "+1d10h" - invalid_at: 20200331202428Z - valid_in: 10 # in ten seconds +# The following example shows how to emulate the behavior of the removed +# "assertonly" provider with the x509_certificate_info, openssl_csr_info, +# openssl_privatekey_info and assert modules: - name: Get certificate information community.crypto.x509_certificate_info: @@ -208,9 +171,9 @@ EXAMPLES = r''' - assert: that: - # When private key is specified for assertonly, this will be checked: + # When private key was specified for assertonly, this was checked: - result.public_key == result_privatekey.public_key - # When CSR is specified for assertonly, this will be checked: + # When CSR was specified for assertonly, this was checked: - result.public_key == result_csr.public_key - result.subject_ordered == result_csr.subject_ordered - result.extensions_by_oid == result_csr.extensions_by_oid @@ -242,103 +205,6 @@ EXAMPLES = r''' - "result.valid_at.one_day_ten_hours" # for valid_at - "not result.valid_at.fixed_timestamp" # for invalid_at - "result.valid_at.ten_seconds" # for valid_in - -# Examples for some checks one could use the assertonly provider for: -# (Please note that assertonly has been deprecated!) - -# How to use the assertonly provider to implement and trigger your own custom certificate generation workflow: -- name: Check if a certificate is currently still valid, ignoring failures - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - has_expired: no - ignore_errors: yes - register: validity_check - -- name: Run custom task(s) to get a new, valid certificate in case the initial check failed - command: superspecialSSL recreate /etc/ssl/crt/example.com.crt - when: validity_check.failed - -- name: Check the new certificate again for validity with the same parameters, this time failing the play if it is still invalid - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - has_expired: no - when: validity_check.failed - -# Some other checks that assertonly could be used for: -- name: Verify that an existing certificate was issued by the Let's Encrypt CA and is currently still valid - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - issuer: - O: Let's Encrypt - has_expired: no - -- name: Ensure that a certificate uses a modern signature algorithm (no SHA1, MD5 or DSA) - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - signature_algorithms: - - sha224WithRSAEncryption - - sha256WithRSAEncryption - - sha384WithRSAEncryption - - sha512WithRSAEncryption - - sha224WithECDSAEncryption - - sha256WithECDSAEncryption - - sha384WithECDSAEncryption - - sha512WithECDSAEncryption - -- name: Ensure that the existing certificate belongs to the specified private key - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - privatekey_path: /etc/ssl/private/example.com.pem - provider: assertonly - -- name: Ensure that the existing certificate is still valid at the winter solstice 2017 - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - valid_at: 20171221162800Z - -- name: Ensure that the existing certificate is still valid 2 weeks (1209600 seconds) from now - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - valid_in: 1209600 - -- name: Ensure that the existing certificate is only used for digital signatures and encrypting other keys - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - key_usage: - - digitalSignature - - keyEncipherment - key_usage_strict: true - -- name: Ensure that the existing certificate can be used for client authentication - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - extended_key_usage: - - clientAuth - -- name: Ensure that the existing certificate can only be used for client authentication and time stamping - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - extended_key_usage: - - clientAuth - - 1.3.6.1.5.5.7.3.8 - extended_key_usage_strict: true - -- name: Ensure that the existing certificate has a certain domain in its subjectAltName - community.crypto.x509_certificate: - path: /etc/ssl/crt/example.com.crt - provider: assertonly - subject_alt_name: - - www.example.com - - test.example.com ''' RETURN = r''' @@ -374,11 +240,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac add_acme_provider_to_argument_spec, ) -from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate_assertonly import ( - AssertOnlyCertificateProvider, - add_assertonly_provider_to_argument_spec, -) - from ansible_collections.community.crypto.plugins.module_utils.crypto.module_backends.certificate_entrust import ( EntrustCertificateProvider, add_entrust_provider_to_argument_spec, @@ -495,7 +356,6 @@ class GenericCertificate(OpenSSLObject): def main(): argument_spec = get_certificate_argument_spec() add_acme_provider_to_argument_spec(argument_spec) - add_assertonly_provider_to_argument_spec(argument_spec) add_entrust_provider_to_argument_spec(argument_spec) add_ownca_provider_to_argument_spec(argument_spec) add_selfsigned_provider_to_argument_spec(argument_spec) @@ -537,7 +397,6 @@ def main(): provider = module.params['provider'] provider_map = { 'acme': AcmeCertificateProvider, - 'assertonly': AssertOnlyCertificateProvider, 'entrust': EntrustCertificateProvider, 'ownca': OwnCACertificateProvider, 'selfsigned': SelfSignedCertificateProvider, diff --git a/tests/integration/targets/x509_certificate/tasks/assertonly.yml b/tests/integration/targets/x509_certificate/tasks/assertonly.yml deleted file mode 100644 index 9dca76e0..00000000 --- a/tests/integration/targets/x509_certificate/tasks/assertonly.yml +++ /dev/null @@ -1,166 +0,0 @@ ---- -- name: (Assertonly, {{select_crypto_backend}}) - Generate privatekey - openssl_privatekey: - path: '{{ remote_tmp_dir }}/privatekey.pem' - size: '{{ default_rsa_key_size_certifiates }}' - -- name: (Assertonly, {{select_crypto_backend}}) - Generate privatekey with password - openssl_privatekey: - path: '{{ remote_tmp_dir }}/privatekeypw.pem' - passphrase: hunter2 - cipher: auto - select_crypto_backend: cryptography - size: '{{ default_rsa_key_size_certifiates }}' - -- name: (Assertonly, {{select_crypto_backend}}) - Generate CSR (no extensions) - openssl_csr: - path: '{{ remote_tmp_dir }}/csr_noext.csr' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - subject: - commonName: www.example.com - useCommonNameForSAN: no - -- name: (Assertonly, {{select_crypto_backend}}) - Generate CSR (with SANs) - openssl_csr: - path: '{{ remote_tmp_dir }}/csr_sans.csr' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - subject: - commonName: www.example.com - subject_alt_name: - - "DNS:ansible.com" - - "IP:127.0.0.1" - - "IP:::1" - useCommonNameForSAN: no - -- name: (Assertonly, {{select_crypto_backend}}) - Generate selfsigned certificate (no extensions) - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - csr_path: '{{ remote_tmp_dir }}/csr_noext.csr' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - provider: selfsigned - selfsigned_digest: sha256 - select_crypto_backend: '{{ select_crypto_backend }}' - -- name: (Assertonly, {{select_crypto_backend}}) - Generate selfsigned certificate (with SANs) - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_sans.pem' - csr_path: '{{ remote_tmp_dir }}/csr_sans.csr' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - provider: selfsigned - selfsigned_digest: sha256 - select_crypto_backend: '{{ select_crypto_backend }}' - -- name: (Assertonly, {{select_crypto_backend}}) - Assert that subject_alt_name is there (should fail) - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - provider: assertonly - subject_alt_name: - - "DNS:example.com" - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: extension_missing_san - -- name: (Assertonly, {{select_crypto_backend}}) - Assert that subject_alt_name is there - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_sans.pem' - provider: assertonly - subject_alt_name: - - "DNS:ansible.com" - - "IP:127.0.0.1" - - "IP:::1" - select_crypto_backend: '{{ select_crypto_backend }}' - register: extension_san - -- name: (Assertonly, {{select_crypto_backend}}) - Assert that subject_alt_name is there (strict) - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_sans.pem' - provider: assertonly - subject_alt_name: - - "DNS:ansible.com" - - "IP:127.0.0.1" - - "IP:::1" - subject_alt_name_strict: yes - select_crypto_backend: '{{ select_crypto_backend }}' - register: extension_san_strict - -- name: (Assertonly, {{select_crypto_backend}}) - Assert that key_usage is there (should fail) - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - provider: assertonly - key_usage: - - digitalSignature - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: extension_missing_ku - -- name: (Assertonly, {{select_crypto_backend}}) - Assert that extended_key_usage is there (should fail) - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - provider: assertonly - extended_key_usage: - - biometricInfo - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: extension_missing_eku - -- assert: - that: - - extension_missing_san is failed - - "'Found no subjectAltName extension' in extension_missing_san.msg" - - extension_san is succeeded - - extension_san_strict is succeeded - - extension_missing_ku is failed - - "'Found no keyUsage extension' in extension_missing_ku.msg" - - extension_missing_eku is failed - - "'Found no extendedKeyUsage extension' in extension_missing_eku.msg" - -- name: (Assertonly, {{select_crypto_backend}}) - Check wrong key fail - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem' - privatekey_passphrase: hunter2 - provider: assertonly - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: private_key_error - -- name: (Assertonly, {{select_crypto_backend}}) - Check private key passphrase fail 1 - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - privatekey_passphrase: hunter2 - provider: assertonly - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: passphrase_error_1 - -- name: (Assertonly, {{select_crypto_backend}}) - Check private key passphrase fail 2 - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem' - privatekey_passphrase: wrong_password - provider: assertonly - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: passphrase_error_2 - -- name: (Assertonly, {{select_crypto_backend}}) - Check private key passphrase fail 3 - x509_certificate: - path: '{{ remote_tmp_dir }}/cert_noext.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekeypw.pem' - provider: assertonly - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: yes - register: passphrase_error_3 - -- name: (Assertonly, {{select_crypto_backend}}) - - assert: - that: - - private_key_error is failed - - "'Certificate and private key ' in private_key_error.msg and ' do not match' in private_key_error.msg" - - passphrase_error_1 is failed - - "'assphrase' in passphrase_error_1.msg or 'assword' in passphrase_error_1.msg" - - passphrase_error_2 is failed - - "'assphrase' in passphrase_error_2.msg or 'assword' in passphrase_error_2.msg or 'serializ' in passphrase_error_2.msg" - - passphrase_error_3 is failed - - "'assphrase' in passphrase_error_3.msg or 'assword' in passphrase_error_3.msg or 'serializ' in passphrase_error_3.msg" diff --git a/tests/integration/targets/x509_certificate/tasks/expired.yml b/tests/integration/targets/x509_certificate/tasks/expired.yml deleted file mode 100644 index dd88fee4..00000000 --- a/tests/integration/targets/x509_certificate/tasks/expired.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -- name: (Expired, {{select_crypto_backend}}) Generate privatekey - openssl_privatekey: - path: '{{ remote_tmp_dir }}/has_expired_privatekey.pem' - size: '{{ default_rsa_key_size_certifiates }}' - -- name: (Expired, {{select_crypto_backend}}) Generate CSR - openssl_csr: - path: '{{ remote_tmp_dir }}/has_expired_csr.csr' - privatekey_path: '{{ remote_tmp_dir }}/has_expired_privatekey.pem' - subject: - commonName: www.example.com - -- name: (Expired, {{select_crypto_backend}}) Generate expired selfsigned certificate - # Cryptography won't allow creating expired certificates; so we create it with 'command' - command: "{{ openssl_binary }} x509 -req -days -1 -in {{ remote_tmp_dir }}/has_expired_csr.csr -signkey {{ remote_tmp_dir }}/has_expired_privatekey.pem -out {{ remote_tmp_dir }}/has_expired_cert.pem" - -- name: "(Expired) Check task fails because cert is expired (has_expired: false)" - x509_certificate: - provider: assertonly - path: "{{ remote_tmp_dir }}/has_expired_cert.pem" - has_expired: false - select_crypto_backend: '{{ select_crypto_backend }}' - ignore_errors: true - register: expired_cert_check - -- name: (Expired, {{select_crypto_backend}}) Ensure previous task failed - assert: - that: expired_cert_check is failed - -- name: "(Expired) Check expired cert check is ignored (has_expired: true)" - x509_certificate: - provider: assertonly - path: "{{ remote_tmp_dir }}/has_expired_cert.pem" - has_expired: true - select_crypto_backend: '{{ select_crypto_backend }}' - register: expired_cert_skip diff --git a/tests/integration/targets/x509_certificate/tasks/impl.yml b/tests/integration/targets/x509_certificate/tasks/impl.yml index f215591f..ce57df3d 100644 --- a/tests/integration/targets/x509_certificate/tasks/impl.yml +++ b/tests/integration/targets/x509_certificate/tasks/impl.yml @@ -1,8 +1,6 @@ --- - debug: msg: "Executing tests with backend {{ select_crypto_backend }}" -- import_tasks: assertonly.yml -- import_tasks: expired.yml - import_tasks: selfsigned.yml - import_tasks: ownca.yml - import_tasks: removal.yml diff --git a/tests/integration/targets/x509_certificate/tasks/ownca.yml b/tests/integration/targets/x509_certificate/tasks/ownca.yml index 32630bdb..dd402b10 100644 --- a/tests/integration/targets/x509_certificate/tasks/ownca.yml +++ b/tests/integration/targets/x509_certificate/tasks/ownca.yml @@ -110,21 +110,27 @@ select_crypto_backend: '{{ select_crypto_backend }}' check_mode: yes -- name: (OwnCA, {{select_crypto_backend}}) Check ownca certificate - x509_certificate: +- name: (OwnCA, {{select_crypto_backend}}) Get certificate information + community.crypto.x509_certificate_info: path: '{{ remote_tmp_dir }}/ownca_cert.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - provider: assertonly - has_expired: False - version: 3 - signature_algorithms: - - sha256WithRSAEncryption - - sha256WithECDSAEncryption - subject: - commonName: www.example.com - issuer: - commonName: Example CA select_crypto_backend: '{{ select_crypto_backend }}' + register: result + +- name: (OwnCA, {{select_crypto_backend}}) Get private key information + community.crypto.openssl_privatekey_info: + path: '{{ remote_tmp_dir }}/privatekey.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + register: result_privatekey + +- name: (OwnCA, {{select_crypto_backend}}) Check ownca certificate + assert: + that: + - result.public_key == result_privatekey.public_key + - "result.signature_algorithm == 'sha256WithRSAEncryption' or result.signature_algorithm == 'sha256WithECDSAEncryption'" + - "result.subject.commonName == 'www.example.com'" + - "result.issuer.commonName == 'Example CA'" + - not result.expired + - result.version == 3 - name: (OwnCA, {{select_crypto_backend}}) Generate ownca v2 certificate x509_certificate: @@ -151,33 +157,35 @@ ownca_digest: sha256 select_crypto_backend: '{{ select_crypto_backend }}' -- name: (OwnCA, {{select_crypto_backend}}) Check ownca certificate2 - x509_certificate: +- name: (OwnCA, {{select_crypto_backend}}) Get certificate information + community.crypto.x509_certificate_info: path: '{{ remote_tmp_dir }}/ownca_cert2.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem' - provider: assertonly - has_expired: False - version: 3 - signature_algorithms: - - sha256WithRSAEncryption - - sha256WithECDSAEncryption - subject: - commonName: www.example.com - C: US - ST: California - L: Los Angeles - O: ACME Inc. - OU: - - Roadrunner pest control - - Pyrotechnics - keyUsage: - - digitalSignature - extendedKeyUsage: - - ipsecUser - - biometricInfo - issuer: - commonName: Example CA select_crypto_backend: '{{ select_crypto_backend }}' + register: result + +- name: (OwnCA, {{select_crypto_backend}}) Get private key information + community.crypto.openssl_privatekey_info: + path: '{{ remote_tmp_dir }}/privatekey2.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + register: result_privatekey + +- name: (OwnCA, {{select_crypto_backend}}) Check ownca certificate2 + assert: + that: + - result.public_key == result_privatekey.public_key + - "result.signature_algorithm == 'sha256WithRSAEncryption' or result.signature_algorithm == 'sha256WithECDSAEncryption'" + - "result.subject.commonName == 'www.example.com'" + - "result.subject.countryName == 'US'" + - "result.subject.localityName == 'Los Angeles'" # L + - "result.subject.organizationName == 'ACME Inc.'" + - "['organizationalUnitName', 'Pyrotechnics'] in result.subject_ordered" + - "['organizationalUnitName', 'Roadrunner pest control'] in result.subject_ordered" + - "result.issuer.commonName == 'Example CA'" + - not result.expired + - result.version == 3 + - "'Digital Signature' in result.key_usage" + - "'IPSec User' in result.extended_key_usage" + - "'Biometric Info' in result.extended_key_usage" - name: (OwnCA, {{select_crypto_backend}}) Create ownca certificate with notBefore and notAfter x509_certificate: diff --git a/tests/integration/targets/x509_certificate/tasks/selfsigned.yml b/tests/integration/targets/x509_certificate/tasks/selfsigned.yml index 8cdab30e..ab90cf5a 100644 --- a/tests/integration/targets/x509_certificate/tasks/selfsigned.yml +++ b/tests/integration/targets/x509_certificate/tasks/selfsigned.yml @@ -99,19 +99,26 @@ check_mode: yes register: selfsigned_certificate_csr_minimal_change -- name: (Selfsigned, {{select_crypto_backend}}) Check selfsigned certificate - x509_certificate: +- name: (Selfsigned, {{select_crypto_backend}}) Get certificate information + community.crypto.x509_certificate_info: path: '{{ remote_tmp_dir }}/cert.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekey.pem' - provider: assertonly - has_expired: False - version: 3 - signature_algorithms: - - sha256WithRSAEncryption - - sha256WithECDSAEncryption - subject: - commonName: www.example.com select_crypto_backend: '{{ select_crypto_backend }}' + register: result + +- name: (Selfsigned, {{select_crypto_backend}}) Get private key information + community.crypto.openssl_privatekey_info: + path: '{{ remote_tmp_dir }}/privatekey.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + register: result_privatekey + +- name: (Selfsigned, {{select_crypto_backend}}) Check selfsigned certificate + assert: + that: + - result.public_key == result_privatekey.public_key + - "result.signature_algorithm == 'sha256WithRSAEncryption' or result.signature_algorithm == 'sha256WithECDSAEncryption'" + - "result.subject.commonName == 'www.example.com'" + - not result.expired + - result.version == 3 - name: (Selfsigned, {{select_crypto_backend}}) Generate selfsigned v2 certificate x509_certificate: @@ -158,31 +165,34 @@ selfsigned_digest: sha256 select_crypto_backend: '{{ select_crypto_backend }}' -- name: (Selfsigned, {{select_crypto_backend}}) Check selfsigned certificate2 - x509_certificate: +- name: (Selfsigned, {{select_crypto_backend}}) Get certificate information + community.crypto.x509_certificate_info: path: '{{ remote_tmp_dir }}/cert2.pem' - privatekey_path: '{{ remote_tmp_dir }}/privatekey2.pem' - provider: assertonly - has_expired: False - version: 3 - signature_algorithms: - - sha256WithRSAEncryption - - sha256WithECDSAEncryption - subject: - commonName: www.example.com - C: US - ST: California - L: Los Angeles - O: ACME Inc. - OU: - - Roadrunner pest control - - Pyrotechnics - keyUsage: - - digitalSignature - extendedKeyUsage: - - ipsecUser - - biometricInfo select_crypto_backend: '{{ select_crypto_backend }}' + register: result + +- name: (Selfsigned, {{select_crypto_backend}}) Get private key information + community.crypto.openssl_privatekey_info: + path: '{{ remote_tmp_dir }}/privatekey2.pem' + select_crypto_backend: '{{ select_crypto_backend }}' + register: result_privatekey + +- name: (Selfsigned, {{select_crypto_backend}}) Check selfsigned certificate2 + assert: + that: + - result.public_key == result_privatekey.public_key + - "result.signature_algorithm == 'sha256WithRSAEncryption' or result.signature_algorithm == 'sha256WithECDSAEncryption'" + - "result.subject.commonName == 'www.example.com'" + - "result.subject.countryName == 'US'" + - "result.subject.localityName == 'Los Angeles'" # L + - "result.subject.organizationName == 'ACME Inc.'" + - "['organizationalUnitName', 'Pyrotechnics'] in result.subject_ordered" + - "['organizationalUnitName', 'Roadrunner pest control'] in result.subject_ordered" + - not result.expired + - result.version == 3 + - "'Digital Signature' in result.key_usage" + - "'IPSec User' in result.extended_key_usage" + - "'Biometric Info' in result.extended_key_usage" - name: (Selfsigned, {{select_crypto_backend}}) Create private key 3 openssl_privatekey: