Get rid of backend parameter whenever possible (#883)

* Get rid of backend parameter whenever possible.

* Always auto-detect if backend choices are 'cryptography' and 'auto', resp. always check cryptography version.

* Improve error message.

* Update documentation.
This commit is contained in:
Felix Fontein
2025-05-03 10:46:53 +02:00
committed by GitHub
parent fbcb89f092
commit 645b7bf9ed
50 changed files with 502 additions and 1093 deletions

View File

@@ -166,6 +166,9 @@ options:
- The default choice is V(auto), which tries to use C(cryptography) if available.
- If set to V(cryptography), will try to use the L(cryptography,https://cryptography.io/) library.
- The value V(pyopenssl) has been removed for community.crypto 3.0.0.
- Note that with community.crypto 3.0.0, all remaining values behave the same.
This option will be deprecated in a later version.
We recommend to not set it explicitly.
type: str
default: auto
choices: [auto, cryptography]
@@ -278,7 +281,7 @@ import os
import stat
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_bytes, to_native
from ansible_collections.community.crypto.plugins.module_utils.crypto.basic import (
OpenSSLBadPassphraseError,
@@ -297,32 +300,23 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im
)
from ansible_collections.community.crypto.plugins.module_utils.cryptography_dep import (
COLLECTION_MINIMUM_CRYPTOGRAPHY_VERSION,
assert_required_cryptography_version,
)
from ansible_collections.community.crypto.plugins.module_utils.io import (
load_file_if_exists,
write_file,
)
from ansible_collections.community.crypto.plugins.module_utils.version import (
LooseVersion,
)
MINIMAL_CRYPTOGRAPHY_VERSION = COLLECTION_MINIMUM_CRYPTOGRAPHY_VERSION
CRYPTOGRAPHY_IMP_ERR = None
try:
import cryptography
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization.pkcs12 import (
serialize_key_and_certificates,
)
CRYPTOGRAPHY_VERSION = LooseVersion(cryptography.__version__)
except ImportError:
CRYPTOGRAPHY_IMP_ERR = traceback.format_exc()
CRYPTOGRAPHY_FOUND = False
else:
CRYPTOGRAPHY_FOUND = True
pass
CRYPTOGRAPHY_COMPATIBILITY2022_ERR = None
try:
@@ -340,14 +334,14 @@ else:
CRYPTOGRAPHY_HAS_COMPATIBILITY2022 = True
def load_certificate_set(filename, backend):
def load_certificate_set(filename):
"""
Load list of concatenated PEM files, and return a list of parsed certificates.
"""
with open(filename, "rb") as f:
data = f.read().decode("utf-8")
return [
load_certificate(None, content=cert.encode("utf-8"), backend=backend)
load_certificate(None, content=cert.encode("utf-8"))
for cert in split_pem_list(data)
]
@@ -357,14 +351,13 @@ class PkcsError(OpenSSLObjectError):
class Pkcs(OpenSSLObject):
def __init__(self, module, backend, iter_size_default=2048):
def __init__(self, module, iter_size_default=2048):
super(Pkcs, self).__init__(
module.params["path"],
module.params["state"],
module.params["force"],
module.check_mode,
)
self.backend = backend
self.action = module.params["action"]
self.other_certificates = module.params["other_certificates"]
self.other_certificates_parse_all = module.params[
@@ -416,11 +409,11 @@ class Pkcs(OpenSSLObject):
self.other_certificates = []
for other_cert_bundle in filenames:
self.other_certificates.extend(
load_certificate_set(other_cert_bundle, self.backend)
load_certificate_set(other_cert_bundle)
)
else:
self.other_certificates = [
load_certificate(other_cert, backend=self.backend)
load_certificate(other_cert)
for other_cert in self.other_certificates
]
elif self.other_certificates_content:
@@ -432,9 +425,7 @@ class Pkcs(OpenSSLObject):
)
)
self.other_certificates = [
load_certificate(
None, content=to_bytes(other_cert), backend=self.backend
)
load_certificate(None, content=to_bytes(other_cert))
for other_cert in certs
]
@@ -475,7 +466,6 @@ class Pkcs(OpenSSLObject):
None,
content=self.privatekey_content,
passphrase=self.privatekey_passphrase,
backend=self.backend,
)
except OpenSSLObjectError:
return False
@@ -606,9 +596,7 @@ class Pkcs(OpenSSLObject):
class PkcsCryptography(Pkcs):
def __init__(self, module):
super(PkcsCryptography, self).__init__(
module, "cryptography", iter_size_default=50000
)
super(PkcsCryptography, self).__init__(module, iter_size_default=50000)
if (
self.encryption_level == "compatibility2022"
and not CRYPTOGRAPHY_HAS_COMPATIBILITY2022
@@ -628,16 +616,13 @@ class PkcsCryptography(Pkcs):
None,
content=self.privatekey_content,
passphrase=self.privatekey_passphrase,
backend=self.backend,
)
except OpenSSLBadPassphraseError as exc:
raise PkcsError(exc)
cert = None
if self.certificate_content:
cert = load_certificate(
None, content=self.certificate_content, backend=self.backend
)
cert = load_certificate(None, content=self.certificate_content)
friendly_name = (
to_bytes(self.friendly_name) if self.friendly_name is not None else None
@@ -726,33 +711,9 @@ class PkcsCryptography(Pkcs):
return pkcs12[3]
def select_backend(module, backend):
if backend == "auto":
# Detection what is possible
can_use_cryptography = (
CRYPTOGRAPHY_FOUND
and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION)
)
if can_use_cryptography:
backend = "cryptography"
# Success?
if backend == "auto":
module.fail_json(
msg=f"Cannot detect the required Python library cryptography (>= {MINIMAL_CRYPTOGRAPHY_VERSION})"
)
if backend == "cryptography":
if not CRYPTOGRAPHY_FOUND:
module.fail_json(
msg=missing_required_lib(
f"cryptography >= {MINIMAL_CRYPTOGRAPHY_VERSION}"
),
exception=CRYPTOGRAPHY_IMP_ERR,
)
return backend, PkcsCryptography(module)
else:
raise ValueError(f"Unsupported value for backend: {backend}")
def select_backend(module):
assert_required_cryptography_version(MINIMAL_CRYPTOGRAPHY_VERSION)
return PkcsCryptography(module)
def main():
@@ -804,7 +765,7 @@ def main():
supports_check_mode=True,
)
backend, pkcs12 = select_backend(module, module.params["select_crypto_backend"])
pkcs12 = select_backend(module)
base_dir = os.path.dirname(module.params["path"]) or "."
if not os.path.isdir(base_dir):