mirror of
https://github.com/ansible-collections/community.crypto.git
synced 2026-05-07 05:43:06 +00:00
Revert all non-bugfixes merged since the last release.
Revert "Fix documentation. (#751)" Revert "ACME modules: simplify code, refactor argspec handling code, move csr/csr_content to own docs fragment (#750)" Revert "Refactor and extend argument spec helper, use for ACME modules (#749)" Revert "Avoid exception if certificate has no AKI in acme_certificate. (#748)" Revert "ACME: improve acme_certificate docs, include cert_id in acme_certificate_renewal_info return value (#747)" Revert "Add acme_certificate_renewal_info module (#746)" Revert "Refactor time code, add tests, fix bug when parsing absolute timestamps that omit seconds (#745)" Revert "Add tests for acme_certificate_deactivate_authz module. (#744)" Revert "Create acme_certificate_deactivate_authz module (#741)" Revert "acme_certificate: allow to request renewal of a certificate according to ARI (#739)" Revert "Implement basic acme_ari_info module. (#732)" Revert "Add function for retrieval of ARI information. (#738)" Revert "acme module utils: add functions for parsing Retry-After header values and computation of ARI certificate IDs (#737)" Revert "Implement certificate information retrieval code in the ACME backends. (#736)" Revert "Split up the default acme docs fragment to allow modules ot not need account data. (#735)" This reverts commits5e59c5261e,aa82575a78,f3c9cb7a8a,f82b335916,553ab45f46,59606d48ad,0a15be1017,9501a28a93,d906914737,33d278ad8f,6d4fc589ae,9614b09f7a,af5f4b57f8,c6fbe58382, andafe7f7522c.
This commit is contained in:
@@ -37,8 +37,7 @@ seealso:
|
||||
- module: community.crypto.acme_inspect
|
||||
description: Allows to debug problems.
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.account
|
||||
- community.crypto.acme
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.actiongroup_acme
|
||||
attributes:
|
||||
@@ -170,9 +169,11 @@ account_uri:
|
||||
|
||||
import base64
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
get_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
@@ -187,8 +188,8 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.errors impor
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec()
|
||||
argument_spec.update_argspec(
|
||||
argument_spec = get_default_argspec()
|
||||
argument_spec.update(dict(
|
||||
terms_agreed=dict(type='bool', default=False),
|
||||
state=dict(type='str', required=True, choices=['absent', 'present', 'changed_key']),
|
||||
allow_creation=dict(type='bool', default=True),
|
||||
@@ -201,9 +202,14 @@ def main():
|
||||
alg=dict(type='str', required=True, choices=['HS256', 'HS384', 'HS512']),
|
||||
key=dict(type='str', required=True, no_log=True),
|
||||
))
|
||||
)
|
||||
argument_spec.update(
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_one_of=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
),
|
||||
mutually_exclusive=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
['new_account_key_src', 'new_account_key_content'],
|
||||
),
|
||||
required_if=(
|
||||
@@ -211,8 +217,8 @@ def main():
|
||||
# new_account_key_src and new_account_key_content are specified
|
||||
['state', 'changed_key', ['new_account_key_src', 'new_account_key_content'], True],
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module = argument_spec.create_ansible_module(supports_check_mode=True)
|
||||
backend = create_backend(module, True)
|
||||
|
||||
if module.params['external_account_binding']:
|
||||
|
||||
@@ -25,8 +25,7 @@ notes:
|
||||
- "This module was called C(acme_account_facts) before Ansible 2.8. The usage
|
||||
did not change."
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.account
|
||||
- community.crypto.acme
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.actiongroup_acme
|
||||
- community.crypto.attributes.info_module
|
||||
@@ -214,9 +213,11 @@ order_uris:
|
||||
version_added: 1.5.0
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
get_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
@@ -269,11 +270,20 @@ def get_order(client, order_url):
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec()
|
||||
argument_spec.update_argspec(
|
||||
argument_spec = get_default_argspec()
|
||||
argument_spec.update(dict(
|
||||
retrieve_orders=dict(type='str', default='ignore', choices=['ignore', 'url_list', 'object_list']),
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_one_of=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
),
|
||||
mutually_exclusive=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module = argument_spec.create_ansible_module(supports_check_mode=True)
|
||||
backend = create_backend(module, True)
|
||||
|
||||
try:
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2018 Felix Fontein <felix@fontein.de>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: acme_ari_info
|
||||
author: "Felix Fontein (@felixfontein)"
|
||||
version_added: 2.20.0
|
||||
short_description: Retrieves ACME Renewal Information (ARI) for a certificate
|
||||
description:
|
||||
- "Allows to retrieve renewal information on a certificate obtained with the
|
||||
L(ACME protocol,https://tools.ietf.org/html/rfc8555)."
|
||||
- "This module only works with the ACME v2 protocol, and requires the ACME server
|
||||
to support the ARI extension (U(https://datatracker.ietf.org/doc/draft-ietf-acme-ari/)).
|
||||
This module implements version 3 of the ARI draft."
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.no_account
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.info_module
|
||||
options:
|
||||
certificate_path:
|
||||
description:
|
||||
- A path to the X.509 certificate to request information for.
|
||||
- Exactly one of O(certificate_path) and O(certificate_content) must be provided.
|
||||
type: path
|
||||
certificate_content:
|
||||
description:
|
||||
- The content of the X.509 certificate to request information for.
|
||||
- Exactly one of O(certificate_path) and O(certificate_content) must be provided.
|
||||
type: str
|
||||
seealso:
|
||||
- module: community.crypto.acme_certificate
|
||||
description: Allows to obtain a certificate using the ACME protocol
|
||||
- module: community.crypto.acme_certificate_revoke
|
||||
description: Allows to revoke a certificate using the ACME protocol
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Retrieve renewal information for a certificate
|
||||
community.crypto.acme_ari_info:
|
||||
certificate_path: /etc/httpd/ssl/sample.com.crt
|
||||
register: cert_data
|
||||
|
||||
- name: Show the certificate renewal information
|
||||
ansible.builtin.debug:
|
||||
var: cert_data.renewal_info
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
renewal_info:
|
||||
description: The ARI renewal info object (U(https://www.ietf.org/archive/id/draft-ietf-acme-ari-03.html#section-4.2)).
|
||||
returned: success
|
||||
type: dict
|
||||
contains:
|
||||
suggestedWindow:
|
||||
description:
|
||||
- Describes the window during which the certificate should be renewed.
|
||||
type: dict
|
||||
returned: always
|
||||
contains:
|
||||
start:
|
||||
description:
|
||||
- The start of the window during which the certificate should be renewed.
|
||||
- The format is specified in L(RFC 3339,https://www.rfc-editor.org/info/rfc3339).
|
||||
returned: always
|
||||
type: str
|
||||
sample: '2021-01-03T00:00:00Z'
|
||||
end:
|
||||
description:
|
||||
- The end of the window during which the certificate should be renewed.
|
||||
- The format is specified in L(RFC 3339,https://www.rfc-editor.org/info/rfc3339).
|
||||
returned: always
|
||||
type: str
|
||||
sample: '2021-01-03T00:00:00Z'
|
||||
explanationURL:
|
||||
description:
|
||||
- A URL pointing to a page which may explain why the suggested renewal window is what it is.
|
||||
- For example, it may be a page explaining the CA's dynamic load-balancing strategy, or a
|
||||
page documenting which certificates are affected by a mass revocation event. Should be shown
|
||||
to the user.
|
||||
returned: depends on the ACME server
|
||||
type: str
|
||||
sample: https://example.com/docs/ari
|
||||
retryAfter:
|
||||
description:
|
||||
- A timestamp before the next retry to ask for this information should not be made.
|
||||
returned: depends on the ACME server
|
||||
type: str
|
||||
sample: '2024-04-29T01:17:10.236921+00:00'
|
||||
'''
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.errors import ModuleFailException
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec(with_account=False)
|
||||
argument_spec.update_argspec(
|
||||
certificate_path=dict(type='path'),
|
||||
certificate_content=dict(type='str'),
|
||||
)
|
||||
argument_spec.update(
|
||||
required_one_of=(
|
||||
['certificate_path', 'certificate_content'],
|
||||
),
|
||||
mutually_exclusive=(
|
||||
['certificate_path', 'certificate_content'],
|
||||
),
|
||||
)
|
||||
module = argument_spec.create_ansible_module(supports_check_mode=True)
|
||||
backend = create_backend(module, True)
|
||||
|
||||
try:
|
||||
client = ACMEClient(module, backend)
|
||||
if not client.directory.has_renewal_info_endpoint():
|
||||
module.fail_json(msg='The ACME endpoint does not support ACME Renewal Information retrieval')
|
||||
renewal_info = client.get_renewal_info(
|
||||
cert_filename=module.params['certificate_path'],
|
||||
cert_content=module.params['certificate_content'],
|
||||
include_retry_after=True,
|
||||
)
|
||||
module.exit_json(renewal_info=renewal_info)
|
||||
except ModuleFailException as e:
|
||||
e.do_fail(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -58,7 +58,7 @@ seealso:
|
||||
link: https://tools.ietf.org/html/rfc8555
|
||||
- name: ACME TLS ALPN Challenge Extension
|
||||
description: The specification of the V(tls-alpn-01) challenge (RFC 8737).
|
||||
link: https://www.rfc-editor.org/rfc/rfc8737.html
|
||||
link: https://www.rfc-editor.org/rfc/rfc8737.html-05
|
||||
- module: community.crypto.acme_challenge_cert_helper
|
||||
description: Helps preparing V(tls-alpn-01) challenges.
|
||||
- module: community.crypto.openssl_privatekey
|
||||
@@ -77,12 +77,8 @@ seealso:
|
||||
description: Allows to create, modify or delete an ACME account.
|
||||
- module: community.crypto.acme_inspect
|
||||
description: Allows to debug problems.
|
||||
- module: community.crypto.acme_certificate_deactivate_authz
|
||||
description: Allows to deactivate (invalidate) ACME v2 orders.
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.account
|
||||
- community.crypto.acme.certificate
|
||||
- community.crypto.acme
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.files
|
||||
- community.crypto.attributes.actiongroup_acme
|
||||
@@ -142,8 +138,32 @@ options:
|
||||
- 'tls-alpn-01'
|
||||
- 'no challenge'
|
||||
csr:
|
||||
description:
|
||||
- "File containing the CSR for the new certificate."
|
||||
- "Can be created with M(community.crypto.openssl_csr) or C(openssl req ...)."
|
||||
- "The CSR may contain multiple Subject Alternate Names, but each one
|
||||
will lead to an individual challenge that must be fulfilled for the
|
||||
CSR to be signed."
|
||||
- "I(Note): the private key used to create the CSR I(must not) be the
|
||||
account key. This is a bad idea from a security point of view, and
|
||||
the CA should not accept the CSR. The ACME server should return an
|
||||
error in this case."
|
||||
- Precisely one of O(csr) or O(csr_content) must be specified.
|
||||
type: path
|
||||
aliases: ['src']
|
||||
csr_content:
|
||||
description:
|
||||
- "Content of the CSR for the new certificate."
|
||||
- "Can be created with M(community.crypto.openssl_csr_pipe) or C(openssl req ...)."
|
||||
- "The CSR may contain multiple Subject Alternate Names, but each one
|
||||
will lead to an individual challenge that must be fulfilled for the
|
||||
CSR to be signed."
|
||||
- "I(Note): the private key used to create the CSR I(must not) be the
|
||||
account key. This is a bad idea from a security point of view, and
|
||||
the CA should not accept the CSR. The ACME server should return an
|
||||
error in this case."
|
||||
- Precisely one of O(csr) or O(csr_content) must be specified.
|
||||
type: str
|
||||
version_added: 1.2.0
|
||||
data:
|
||||
description:
|
||||
@@ -272,32 +292,6 @@ options:
|
||||
- "The identifier must be of the form
|
||||
V(C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10)."
|
||||
type: str
|
||||
include_renewal_cert_id:
|
||||
description:
|
||||
- Determines whether to request renewal of an existing certificate according to
|
||||
L(the ACME ARI draft 3, https://www.ietf.org/archive/id/draft-ietf-acme-ari-03.html#section-5).
|
||||
- This is only used when the certificate specified in O(dest) or O(fullchain_dest) already exists.
|
||||
- V(never) never sends the certificate ID of the certificate to renew. V(always) will always send it.
|
||||
- V(when_ari_supported) only sends the certificate ID if the ARI endpoint is found in the ACME directory.
|
||||
- Generally you should use V(when_ari_supported) if you know that the ACME service supports a compatible
|
||||
draft (or final version, once it is out) of the ARI extension. V(always) should never be necessary.
|
||||
If you are not sure, or if you receive strange errors on invalid C(replaces) values in order objects,
|
||||
use V(never), which also happens to be the default.
|
||||
- ACME servers might refuse to create new orders with C(replaces) for certificates that already have an
|
||||
existing order. This can happen if this module is used to create an order, and then the playbook/role
|
||||
fails in case the challenges cannot be set up. If the playbook/role does not record the order data to
|
||||
continue with the existing order, but tries to create a new one on the next run, creating the new order
|
||||
might fail. For this reason, this option should only be set to a value different from V(never) if the
|
||||
role/playbook using it keeps track of order data accross restarts, or if it takes care to deactivate
|
||||
orders whose processing is aborted. Orders can be deactivated with the
|
||||
M(community.crypto.acme_certificate_deactivate_authz) module.
|
||||
type: str
|
||||
choices:
|
||||
- never
|
||||
- when_ari_supported
|
||||
- always
|
||||
default: never
|
||||
version_added: 2.20.0
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -381,7 +375,7 @@ EXAMPLES = r'''
|
||||
# state: present
|
||||
# wait: true
|
||||
# # Note: route53 requires TXT entries to be enclosed in quotes
|
||||
# value: "{{ sample_com_challenge.challenge_data['sample.com']['dns-01'].resource_value | community.dns.quote_txt(always_quote=true) }}"
|
||||
# value: "{{ sample_com_challenge.challenge_data['sample.com']['dns-01'].resource_value | regex_replace('^(.*)$', '\"\\1\"') }}"
|
||||
# when: sample_com_challenge is changed and 'sample.com' in sample_com_challenge.challenge_data
|
||||
#
|
||||
# Alternative way:
|
||||
@@ -396,7 +390,7 @@ EXAMPLES = r'''
|
||||
# wait: true
|
||||
# # Note: item.value is a list of TXT entries, and route53
|
||||
# # requires every entry to be enclosed in quotes
|
||||
# value: "{{ item.value | map('community.dns.quote_txt', always_quote=true) | list }}"
|
||||
# value: "{{ item.value | map('regex_replace', '^(.*)$', '\"\\1\"' ) | list }}"
|
||||
# loop: "{{ sample_com_challenge.challenge_data_dns | dict2items }}"
|
||||
# when: sample_com_challenge is changed
|
||||
|
||||
@@ -452,55 +446,39 @@ challenge_data:
|
||||
- Per identifier / challenge type challenge data.
|
||||
- Since Ansible 2.8.5, only challenges which are not yet valid are returned.
|
||||
returned: changed
|
||||
type: dict
|
||||
type: list
|
||||
elements: dict
|
||||
contains:
|
||||
identifier:
|
||||
description:
|
||||
- For every identifier, provides a dictionary of challenge types mapping to challenge data.
|
||||
- The keys in this dictionary are the identifiers. C(identifier) is a placeholder used in the documentation.
|
||||
- Note that the keys are not valid Jinja2 identifiers.
|
||||
resource:
|
||||
description: The challenge resource that must be created for validation.
|
||||
returned: changed
|
||||
type: dict
|
||||
contains:
|
||||
challenge-type:
|
||||
description:
|
||||
- Data for every challenge type.
|
||||
- The keys in this dictionary are the challenge types. C(challenge-type) is a placeholder used in the documentation.
|
||||
Possible keys are V(http-01), V(dns-01), and V(tls-alpn-01).
|
||||
- Note that the keys are not valid Jinja2 identifiers.
|
||||
returned: changed
|
||||
type: dict
|
||||
contains:
|
||||
resource:
|
||||
description: The challenge resource that must be created for validation.
|
||||
returned: changed
|
||||
type: str
|
||||
sample: .well-known/acme-challenge/evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA
|
||||
resource_original:
|
||||
description:
|
||||
- The original challenge resource including type identifier for V(tls-alpn-01)
|
||||
challenges.
|
||||
returned: changed and O(challenge) is V(tls-alpn-01)
|
||||
type: str
|
||||
sample: DNS:example.com
|
||||
resource_value:
|
||||
description:
|
||||
- The value the resource has to produce for the validation.
|
||||
- For V(http-01) and V(dns-01) challenges, the value can be used as-is.
|
||||
- "For V(tls-alpn-01) challenges, note that this return value contains a
|
||||
Base64 encoded version of the correct binary blob which has to be put
|
||||
into the acmeValidation x509 extension; see
|
||||
U(https://www.rfc-editor.org/rfc/rfc8737.html#section-3)
|
||||
for details. To do this, you might need the P(ansible.builtin.b64decode#filter) Jinja filter
|
||||
to extract the binary blob from this return value."
|
||||
returned: changed
|
||||
type: str
|
||||
sample: IlirfxKKXA...17Dt3juxGJ-PCt92wr-oA
|
||||
record:
|
||||
description: The full DNS record's name for the challenge.
|
||||
returned: changed and challenge is V(dns-01)
|
||||
type: str
|
||||
sample: _acme-challenge.example.com
|
||||
type: str
|
||||
sample: .well-known/acme-challenge/evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA
|
||||
resource_original:
|
||||
description:
|
||||
- The original challenge resource including type identifier for V(tls-alpn-01)
|
||||
challenges.
|
||||
returned: changed and O(challenge) is V(tls-alpn-01)
|
||||
type: str
|
||||
sample: DNS:example.com
|
||||
resource_value:
|
||||
description:
|
||||
- The value the resource has to produce for the validation.
|
||||
- For V(http-01) and V(dns-01) challenges, the value can be used as-is.
|
||||
- "For V(tls-alpn-01) challenges, note that this return value contains a
|
||||
Base64 encoded version of the correct binary blob which has to be put
|
||||
into the acmeValidation x509 extension; see
|
||||
U(https://www.rfc-editor.org/rfc/rfc8737.html#section-3)
|
||||
for details. To do this, you might need the P(ansible.builtin.b64decode#filter) Jinja filter
|
||||
to extract the binary blob from this return value."
|
||||
returned: changed
|
||||
type: str
|
||||
sample: IlirfxKKXA...17Dt3juxGJ-PCt92wr-oA
|
||||
record:
|
||||
description: The full DNS record's name for the challenge.
|
||||
returned: changed and challenge is V(dns-01)
|
||||
type: str
|
||||
sample: _acme-challenge.example.com
|
||||
challenge_data_dns:
|
||||
description:
|
||||
- List of TXT values per DNS record, in case challenge is V(dns-01).
|
||||
@@ -569,9 +547,11 @@ all_chains:
|
||||
|
||||
import os
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
get_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
@@ -605,7 +585,6 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.orders impor
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.utils import (
|
||||
compute_cert_id,
|
||||
pem_to_der,
|
||||
)
|
||||
|
||||
@@ -642,7 +621,6 @@ class ACMECertificateClient(object):
|
||||
self.order_uri = self.data.get('order_uri') if self.data else None
|
||||
self.all_chains = None
|
||||
self.select_chain_matcher = []
|
||||
self.include_renewal_cert_id = module.params['include_renewal_cert_id']
|
||||
|
||||
if self.module.params['select_chain']:
|
||||
for criterium_idx, criterium in enumerate(self.module.params['select_chain']):
|
||||
@@ -700,15 +678,6 @@ class ACMECertificateClient(object):
|
||||
# stored in self.order_uri by the constructor).
|
||||
return self.order_uri is None
|
||||
|
||||
def _get_cert_info_or_none(self):
|
||||
if self.module.params.get('dest'):
|
||||
filename = self.module.params['dest']
|
||||
else:
|
||||
filename = self.module.params['fullchain_dest']
|
||||
if not os.path.exists(filename):
|
||||
return None
|
||||
return self.client.backend.get_cert_information(cert_filename=filename)
|
||||
|
||||
def start_challenges(self):
|
||||
'''
|
||||
Create new authorizations for all identifiers of the CSR,
|
||||
@@ -723,19 +692,7 @@ class ACMECertificateClient(object):
|
||||
authz = Authorization.create(self.client, identifier_type, identifier)
|
||||
self.authorizations[authz.combined_identifier] = authz
|
||||
else:
|
||||
replaces_cert_id = None
|
||||
if (
|
||||
self.include_renewal_cert_id == 'always' or
|
||||
(self.include_renewal_cert_id == 'when_ari_supported' and self.client.directory.has_renewal_info_endpoint())
|
||||
):
|
||||
cert_info = self._get_cert_info_or_none()
|
||||
if cert_info is not None:
|
||||
replaces_cert_id = compute_cert_id(
|
||||
self.client.backend,
|
||||
cert_info=cert_info,
|
||||
none_if_required_information_is_missing=True,
|
||||
)
|
||||
self.order = Order.create(self.client, self.identifiers, replaces_cert_id)
|
||||
self.order = Order.create(self.client, self.identifiers)
|
||||
self.order_uri = self.order.url
|
||||
self.order.load_authorizations(self.client)
|
||||
self.authorizations.update(self.order.authorizations)
|
||||
@@ -897,14 +854,15 @@ class ACMECertificateClient(object):
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec(with_certificate=True)
|
||||
argument_spec.argument_spec['csr']['aliases'] = ['src']
|
||||
argument_spec.update_argspec(
|
||||
argument_spec = get_default_argspec()
|
||||
argument_spec.update(dict(
|
||||
modify_account=dict(type='bool', default=True),
|
||||
account_email=dict(type='str'),
|
||||
agreement=dict(type='str'),
|
||||
terms_agreed=dict(type='bool', default=False),
|
||||
challenge=dict(type='str', default='http-01', choices=['http-01', 'dns-01', 'tls-alpn-01', NO_CHALLENGE]),
|
||||
csr=dict(type='path', aliases=['src']),
|
||||
csr_content=dict(type='str'),
|
||||
data=dict(type='dict'),
|
||||
dest=dict(type='path', aliases=['cert']),
|
||||
fullchain_dest=dict(type='path', aliases=['fullchain']),
|
||||
@@ -920,14 +878,20 @@ def main():
|
||||
subject_key_identifier=dict(type='str'),
|
||||
authority_key_identifier=dict(type='str'),
|
||||
)),
|
||||
include_renewal_cert_id=dict(type='str', choices=['never', 'when_ari_supported', 'always'], default='never'),
|
||||
)
|
||||
argument_spec.update(
|
||||
required_one_of=[
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_one_of=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
['dest', 'fullchain_dest'],
|
||||
],
|
||||
['csr', 'csr_content'],
|
||||
),
|
||||
mutually_exclusive=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
['csr', 'csr_content'],
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module = argument_spec.create_ansible_module(supports_check_mode=True)
|
||||
backend = create_backend(module, False)
|
||||
|
||||
try:
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2016 Michael Gruener <michael.gruener@chaosmoon.net>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: acme_certificate_deactivate_authz
|
||||
author: "Felix Fontein (@felixfontein)"
|
||||
version_added: 2.20.0
|
||||
short_description: Deactivate all authz for an ACME v2 order
|
||||
description:
|
||||
- "Deactivate all authentication objects (authz) for an ACME v2 order,
|
||||
which effectively deactivates (invalidates) the order itself."
|
||||
- "Authentication objects are bound to an account key and remain valid
|
||||
for a certain amount of time, and can be used to issue certificates
|
||||
without having to re-authenticate the domain. This can be a security
|
||||
concern."
|
||||
- "Another reason to use this module is to deactivate an order whose
|
||||
processing failed when using O(community.crypto.acme_certificate#module:include_renewal_cert_id)."
|
||||
seealso:
|
||||
- module: community.crypto.acme_certificate
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.account
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.actiongroup_acme
|
||||
attributes:
|
||||
check_mode:
|
||||
support: full
|
||||
diff_mode:
|
||||
support: none
|
||||
options:
|
||||
order_uri:
|
||||
description:
|
||||
- The ACME v2 order to deactivate.
|
||||
- Can be obtained from RV(community.crypto.acme_certificate#module:order_uri).
|
||||
type: str
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Deactivate all authzs for an order
|
||||
community.crypto.acme_certificate_deactivate_authz:
|
||||
account_key_content: "{{ account_private_key }}"
|
||||
order_uri: "{{ certificate_result.order_uri }}"
|
||||
'''
|
||||
|
||||
RETURN = '''#'''
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.account import (
|
||||
ACMEAccount,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.errors import (
|
||||
ModuleFailException,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.orders import (
|
||||
Order,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec()
|
||||
argument_spec.update_argspec(
|
||||
order_uri=dict(type='str', required=True),
|
||||
)
|
||||
module = argument_spec.create_ansible_module(supports_check_mode=True)
|
||||
if module.params['acme_version'] == 1:
|
||||
module.fail_json('The module does not support acme_version=1')
|
||||
|
||||
backend = create_backend(module, False)
|
||||
|
||||
try:
|
||||
client = ACMEClient(module, backend)
|
||||
account = ACMEAccount(client)
|
||||
|
||||
dummy, account_data = account.setup_account(allow_creation=False)
|
||||
if account_data is None:
|
||||
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
||||
|
||||
order = Order.from_url(client, module.params['order_uri'])
|
||||
order.load_authorizations(client)
|
||||
|
||||
changed = False
|
||||
for authz in order.authorizations.values():
|
||||
if not authz.can_deactivate():
|
||||
continue
|
||||
changed = True
|
||||
if module.check_mode:
|
||||
continue
|
||||
try:
|
||||
authz.deactivate(client)
|
||||
except Exception:
|
||||
# ignore errors
|
||||
pass
|
||||
if authz.status != 'deactivated':
|
||||
module.warn(warning='Could not deactivate authz object {0}.'.format(authz.url))
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
except ModuleFailException as e:
|
||||
e.do_fail(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,245 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2018 Felix Fontein <felix@fontein.de>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: acme_certificate_renewal_info
|
||||
author: "Felix Fontein (@felixfontein)"
|
||||
version_added: 2.20.0
|
||||
short_description: Determine whether a certificate should be renewed or not
|
||||
description:
|
||||
- Uses various information to determine whether a certificate should be renewed or not.
|
||||
- If available, the ARI extension (ACME Renewal Information, U(https://datatracker.ietf.org/doc/draft-ietf-acme-ari/))
|
||||
is used. This module implements version 3 of the ARI draft."
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.no_account
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.info_module
|
||||
options:
|
||||
certificate_path:
|
||||
description:
|
||||
- A path to the X.509 certificate to determine renewal of.
|
||||
- In case the certificate does not exist, the module will always return RV(should_renew=true).
|
||||
- O(certificate_path) and O(certificate_content) are mutually exclusive.
|
||||
type: path
|
||||
certificate_content:
|
||||
description:
|
||||
- The content of the X.509 certificate to determine renewal of.
|
||||
- O(certificate_path) and O(certificate_content) are mutually exclusive.
|
||||
type: str
|
||||
use_ari:
|
||||
description:
|
||||
- Whether to use ARI information, if available.
|
||||
- Set this to V(false) if the ACME server implements ARI in a way that is incompatible with this module.
|
||||
type: bool
|
||||
default: true
|
||||
ari_algorithm:
|
||||
description:
|
||||
- If ARI information is used, selects which algorithm is used to determine whether to renew now.
|
||||
- V(standard) selects the L(algorithm provided in the the ARI specification,
|
||||
https://www.ietf.org/archive/id/draft-ietf-acme-ari-03.html#name-renewalinfo-objects).
|
||||
- V(start) returns RV(should_renew=true) once the start of the renewal interval has been reached.
|
||||
type: str
|
||||
choices:
|
||||
- standard
|
||||
- start
|
||||
default: standard
|
||||
remaining_days:
|
||||
description:
|
||||
- The number of days the certificate must have left being valid.
|
||||
- For example, if O(remaining_days=20), this check causes RV(should_renew=true) if the
|
||||
certificate is valid for less than 20 days.
|
||||
type: int
|
||||
remaining_percentage:
|
||||
description:
|
||||
- The percentage of the certificate's validity period that should be left.
|
||||
- For example, if O(remaining_percentage=0.1), and the certificate's validity period is 90 days,
|
||||
this check causes RV(should_renew=true) if the certificate is valid for less than 9 days.
|
||||
- Must be a value between 0 and 1.
|
||||
type: float
|
||||
now:
|
||||
description:
|
||||
- Use this timestamp instead of the current timestamp to determine whether a certificate should be renewed.
|
||||
- Time can be specified either as relative time or as absolute timestamp.
|
||||
- Time will always be interpreted as UTC.
|
||||
- Valid format is C([+-]timespec | ASN.1 TIME) where timespec can be an integer
|
||||
+ C([w | d | h | m | s]) (for example V(+32w1d2h)).
|
||||
type: str
|
||||
seealso:
|
||||
- module: community.crypto.acme_certificate
|
||||
description: Allows to obtain a certificate using the ACME protocol
|
||||
- module: community.crypto.acme_ari_info
|
||||
description: Obtain renewal information for a certificate
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Retrieve renewal information for a certificate
|
||||
community.crypto.acme_certificate_renewal_info:
|
||||
certificate_path: /etc/httpd/ssl/sample.com.crt
|
||||
register: cert_data
|
||||
|
||||
- name: Should the certificate be renewed?
|
||||
ansible.builtin.debug:
|
||||
var: cert_data.should_renew
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
should_renew:
|
||||
description:
|
||||
- Whether the certificate should be renewed.
|
||||
- If no certificate is provided, or the certificate is expired, will always be V(true).
|
||||
returned: success
|
||||
type: bool
|
||||
sample: true
|
||||
|
||||
msg:
|
||||
description:
|
||||
- Information on the reason for renewal.
|
||||
- Should be shown to the user, as in case of ARI triggered renewal it can contain important
|
||||
information, for example on forced revocations for misissued certificates.
|
||||
type: str
|
||||
returned: success
|
||||
sample: The certificate does not exist.
|
||||
|
||||
supports_ari:
|
||||
description:
|
||||
- Whether ARI information was used to determine renewal. This can be used to determine whether to
|
||||
specify O(community.crypto.acme_certificate#module:include_renewal_cert_id=when_ari_supported)
|
||||
for the M(community.crypto.acme_certificate) module.
|
||||
- If O(use_ari=false), this will always be V(false).
|
||||
returned: success
|
||||
type: bool
|
||||
sample: true
|
||||
|
||||
cert_id:
|
||||
description:
|
||||
- The certificate ID according to the L(ARI specification, https://www.ietf.org/archive/id/draft-ietf-acme-ari-03.html#section-4.1).
|
||||
returned: success, the certificate exists, and has an Authority Key Identifier X.509 extension
|
||||
type: str
|
||||
sample: aYhba4dGQEHhs3uEe6CuLN4ByNQ.AIdlQyE
|
||||
'''
|
||||
|
||||
import os
|
||||
import random
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.errors import ModuleFailException
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.utils import compute_cert_id
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec(with_account=False)
|
||||
argument_spec.update_argspec(
|
||||
certificate_path=dict(type='path'),
|
||||
certificate_content=dict(type='str'),
|
||||
use_ari=dict(type='bool', default=True),
|
||||
ari_algorithm=dict(type='str', choices=['standard', 'start'], default='standard'),
|
||||
remaining_days=dict(type='int'),
|
||||
remaining_percentage=dict(type='float'),
|
||||
now=dict(type='str'),
|
||||
)
|
||||
argument_spec.update(
|
||||
mutually_exclusive=(
|
||||
['certificate_path', 'certificate_content'],
|
||||
),
|
||||
)
|
||||
module = argument_spec.create_ansible_module(supports_check_mode=True)
|
||||
backend = create_backend(module, True)
|
||||
|
||||
result = dict(
|
||||
changed=False,
|
||||
msg='The certificate is still valid and no condition was reached',
|
||||
supports_ari=False,
|
||||
)
|
||||
|
||||
def complete(should_renew, **kwargs):
|
||||
result['should_renew'] = should_renew
|
||||
result.update(kwargs)
|
||||
module.exit_json(**result)
|
||||
|
||||
if not module.params['certificate_path'] and not module.params['certificate_content']:
|
||||
complete(True, msg='No certificate was specified')
|
||||
|
||||
if module.params['certificate_path'] is not None and not os.path.exists(module.params['certificate_path']):
|
||||
complete(True, msg='The certificate file does not exist')
|
||||
|
||||
try:
|
||||
cert_info = backend.get_cert_information(
|
||||
cert_filename=module.params['certificate_path'],
|
||||
cert_content=module.params['certificate_content'],
|
||||
)
|
||||
cert_id = compute_cert_id(backend, cert_info=cert_info, none_if_required_information_is_missing=True)
|
||||
if cert_id is not None:
|
||||
result['cert_id'] = cert_id
|
||||
|
||||
if module.params['now']:
|
||||
now = backend.parse_module_parameter(module.params['now'], 'now')
|
||||
else:
|
||||
now = backend.get_now()
|
||||
|
||||
if now >= cert_info.not_valid_after:
|
||||
complete(True, msg='The certificate has already expired')
|
||||
|
||||
client = ACMEClient(module, backend)
|
||||
if cert_id is not None and module.params['use_ari'] and client.directory.has_renewal_info_endpoint():
|
||||
renewal_info = client.get_renewal_info(cert_id=cert_id)
|
||||
window_start = backend.parse_acme_timestamp(renewal_info['suggestedWindow']['start'])
|
||||
window_end = backend.parse_acme_timestamp(renewal_info['suggestedWindow']['end'])
|
||||
msg_append = ''
|
||||
if 'explanationURL' in renewal_info:
|
||||
msg_append = '. Information on renewal interval: {0}'.format(renewal_info['explanationURL'])
|
||||
result['supports_ari'] = True
|
||||
if now > window_end:
|
||||
complete(True, msg='The suggested renewal interval provided by ARI is in the past{0}'.format(msg_append))
|
||||
if module.params['ari_algorithm'] == 'start':
|
||||
if now > window_start:
|
||||
complete(True, msg='The suggested renewal interval provided by ARI has begun{0}'.format(msg_append))
|
||||
else:
|
||||
random_time = backend.interpolate_timestamp(window_start, window_end, random.random())
|
||||
if now > random_time:
|
||||
complete(
|
||||
True,
|
||||
msg='The picked random renewal time {0} in sugested renewal internal provided by ARI is in the past{1}'.format(
|
||||
random_time,
|
||||
msg_append,
|
||||
),
|
||||
)
|
||||
|
||||
if module.params['remaining_days'] is not None:
|
||||
remaining_days = (cert_info.not_valid_after - now).days
|
||||
if remaining_days < module.params['remaining_days']:
|
||||
complete(True, msg='The certificate expires in {0} days'.format(remaining_days))
|
||||
|
||||
if module.params['remaining_percentage'] is not None:
|
||||
timestamp = backend.interpolate_timestamp(cert_info.not_valid_before, cert_info.not_valid_after, 1 - module.params['remaining_percentage'])
|
||||
if timestamp < now:
|
||||
complete(
|
||||
True,
|
||||
msg="The remaining percentage {0}% of the certificate's lifespan was reached on {1}".format(
|
||||
module.params['remaining_percentage'] * 100,
|
||||
timestamp,
|
||||
),
|
||||
)
|
||||
|
||||
complete(False)
|
||||
except ModuleFailException as e:
|
||||
e.do_fail(module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -37,8 +37,7 @@ seealso:
|
||||
- module: community.crypto.acme_inspect
|
||||
description: Allows to debug problems.
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.account
|
||||
- community.crypto.acme
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.actiongroup_acme
|
||||
attributes:
|
||||
@@ -128,9 +127,11 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''#'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
get_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
@@ -151,23 +152,24 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.utils import
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec(require_account_key=False)
|
||||
argument_spec.update_argspec(
|
||||
argument_spec = get_default_argspec()
|
||||
argument_spec.update(dict(
|
||||
private_key_src=dict(type='path'),
|
||||
private_key_content=dict(type='str', no_log=True),
|
||||
private_key_passphrase=dict(type='str', no_log=True),
|
||||
certificate=dict(type='path', required=True),
|
||||
revoke_reason=dict(type='int'),
|
||||
)
|
||||
argument_spec.update(
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_one_of=(
|
||||
['account_key_src', 'account_key_content', 'private_key_src', 'private_key_content'],
|
||||
),
|
||||
mutually_exclusive=(
|
||||
['account_key_src', 'account_key_content', 'private_key_src', 'private_key_content'],
|
||||
),
|
||||
supports_check_mode=False,
|
||||
)
|
||||
module = argument_spec.create_ansible_module()
|
||||
backend = create_backend(module, False)
|
||||
|
||||
try:
|
||||
|
||||
@@ -165,16 +165,16 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.io import (
|
||||
read_file,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
||||
get_now_datetime,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
|
||||
CRYPTOGRAPHY_TIMEZONE,
|
||||
set_not_valid_after,
|
||||
set_not_valid_before,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
get_now_datetime,
|
||||
)
|
||||
|
||||
CRYPTOGRAPHY_IMP_ERR = None
|
||||
try:
|
||||
import cryptography
|
||||
|
||||
@@ -42,8 +42,7 @@ seealso:
|
||||
description: The specification of the C(tls-alpn-01) challenge (RFC 8737).
|
||||
link: https://www.rfc-editor.org/rfc/rfc8737.html
|
||||
extends_documentation_fragment:
|
||||
- community.crypto.acme.basic
|
||||
- community.crypto.acme.account
|
||||
- community.crypto.acme
|
||||
- community.crypto.attributes
|
||||
- community.crypto.attributes.actiongroup_acme
|
||||
attributes:
|
||||
@@ -248,11 +247,12 @@ output_json:
|
||||
- ...
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native, to_bytes, to_text
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.acme.acme import (
|
||||
create_backend,
|
||||
create_default_argspec,
|
||||
get_default_argspec,
|
||||
ACMEClient,
|
||||
)
|
||||
|
||||
@@ -263,14 +263,18 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.errors impor
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = create_default_argspec(require_account_key=False)
|
||||
argument_spec.update_argspec(
|
||||
argument_spec = get_default_argspec()
|
||||
argument_spec.update(dict(
|
||||
url=dict(type='str'),
|
||||
method=dict(type='str', choices=['get', 'post', 'directory-only'], default='get'),
|
||||
content=dict(type='str'),
|
||||
fail_on_acme_error=dict(type='bool', default=True),
|
||||
)
|
||||
argument_spec.update(
|
||||
))
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=(
|
||||
['account_key_src', 'account_key_content'],
|
||||
),
|
||||
required_if=(
|
||||
['method', 'get', ['url']],
|
||||
['method', 'post', ['url', 'content']],
|
||||
@@ -278,7 +282,6 @@ def main():
|
||||
['method', 'post', ['account_key_src', 'account_key_content'], True],
|
||||
),
|
||||
)
|
||||
module = argument_spec.create_ansible_module()
|
||||
backend = create_backend(module, False)
|
||||
|
||||
result = dict()
|
||||
|
||||
@@ -220,6 +220,10 @@ from ansible.module_utils.common.text.converters import to_bytes
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.version import LooseVersion
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
||||
get_now_datetime,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
|
||||
CRYPTOGRAPHY_TIMEZONE,
|
||||
cryptography_oid_to_name,
|
||||
@@ -228,10 +232,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptograp
|
||||
get_not_valid_before,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
get_now_datetime,
|
||||
)
|
||||
|
||||
MINIMAL_CRYPTOGRAPHY_VERSION = '1.6'
|
||||
|
||||
CREATE_DEFAULT_CONTEXT_IMP_ERR = None
|
||||
|
||||
@@ -406,6 +406,10 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.basic impo
|
||||
OpenSSLObjectError,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.support import (
|
||||
get_relative_time_option,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.crypto.cryptography_support import (
|
||||
CRYPTOGRAPHY_TIMEZONE,
|
||||
)
|
||||
@@ -414,10 +418,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac
|
||||
select_backend,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
get_relative_time_option,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
|
||||
@@ -470,6 +470,7 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.support im
|
||||
load_certificate,
|
||||
parse_name_field,
|
||||
parse_ordered_name_field,
|
||||
get_relative_time_option,
|
||||
select_message_digest,
|
||||
)
|
||||
|
||||
@@ -505,10 +506,6 @@ from ansible_collections.community.crypto.plugins.module_utils.crypto.module_bac
|
||||
get_crl_info,
|
||||
)
|
||||
|
||||
from ansible_collections.community.crypto.plugins.module_utils.time import (
|
||||
get_relative_time_option,
|
||||
)
|
||||
|
||||
MINIMAL_CRYPTOGRAPHY_VERSION = '1.2'
|
||||
|
||||
CRYPTOGRAPHY_IMP_ERR = None
|
||||
|
||||
Reference in New Issue
Block a user