From a1dfce3aa170aee7ccf7fd9800aeb6d0a644af50 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Wed, 26 Dec 2018 14:26:46 +0100 Subject: [PATCH] ACME: add seealso references (#50320) * Add seealso references to ACME modules. * Bump to latest drafts. --- lib/ansible/module_utils/acme.py | 20 ++++---- .../modules/crypto/acme/acme_account.py | 18 +++++-- .../modules/crypto/acme/acme_account_facts.py | 5 +- .../modules/crypto/acme/acme_certificate.py | 49 +++++++++++++------ .../crypto/acme/acme_certificate_revoke.py | 14 +++++- .../crypto/acme/acme_challenge_cert_helper.py | 7 +++ .../modules/crypto/acme/acme_inspect.py | 11 ++++- 7 files changed, 89 insertions(+), 35 deletions(-) diff --git a/lib/ansible/module_utils/acme.py b/lib/ansible/module_utils/acme.py index 7a60a681d69..1effe9ce7e8 100644 --- a/lib/ansible/module_utils/acme.py +++ b/lib/ansible/module_utils/acme.py @@ -429,7 +429,7 @@ class ACMEDirectory(object): and allows to obtain a Replay-Nonce. The acme_directory URL needs to support unauthenticated GET requests; ACME endpoints requiring authentication are not supported. - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.1.1 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.1.1 ''' def __init__(self, module, account): @@ -500,7 +500,7 @@ class ACMEAccount(object): def get_keyauthorization(self, token): ''' Returns the key authorization for the given token - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-8.1 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-8.1 ''' accountkey_json = json.dumps(self.jwk, sort_keys=True, separators=(',', ':')) thumbprint = nopad_b64(hashlib.sha256(accountkey_json.encode('utf8')).digest()) @@ -541,10 +541,10 @@ class ACMEAccount(object): ''' Sends a JWS signed HTTP POST request to the ACME server and returns the response as dictionary - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-6.2 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-6.2 If payload is None, a POST-as-GET is performed. - (https://tools.ietf.org/html/draft-ietf-acme-acme-15#section-6.3) + (https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-6.3) ''' key_data = key_data or self.key_data jws_header = jws_header or self.jws_header @@ -575,7 +575,7 @@ class ACMEAccount(object): try: decoded_result = self.module.from_json(content.decode('utf8')) # In case of badNonce error, try again (up to 5 times) - # (https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-6.6) + # (https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-6.7) if (400 <= info['status'] < 600 and decoded_result.get('type') == 'urn:ietf:params:acme:error:badNonce' and failed_tries <= 5): @@ -651,7 +651,7 @@ class ACMEAccount(object): ``False`` if it already existed (e.g. it was not newly created), or does not exist. In case the account was created or exists, ``data`` contains the account data; otherwise, it is ``None``. - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.3 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3 ''' contact = contact or [] @@ -670,7 +670,7 @@ class ACMEAccount(object): 'contact': contact } if not allow_creation: - # https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.3.1 + # https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3.1 new_reg['onlyReturnExisting'] = True if terms_agreed: new_reg['termsOfServiceAgreed'] = True @@ -688,7 +688,7 @@ class ACMEAccount(object): if result.get('status') == 'deactivated': # A probable bug in Pebble (https://github.com/letsencrypt/pebble/issues/179) # and Boulder: this should not return a valid account object according to - # https://tools.ietf.org/html/draft-ietf-acme-acme-16#section-7.3.6: + # https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3.6: # "Once an account is deactivated, the server MUST NOT accept further # requests authorized by that account's key." if not allow_creation: @@ -755,7 +755,7 @@ class ACMEAccount(object): The account URI will be stored in ``self.uri``; if it is ``None``, the account does not exist. - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.3 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3 ''' if self.uri is not None: @@ -793,7 +793,7 @@ class ACMEAccount(object): would be changed (check mode), and ``account_data`` the updated account data. - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.3.2 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3.2 ''' # Create request update_request = {} diff --git a/lib/ansible/modules/crypto/acme/acme_account.py b/lib/ansible/modules/crypto/acme/acme_account.py index a07f4c8889d..5e0585d38b9 100644 --- a/lib/ansible/modules/crypto/acme/acme_account.py +++ b/lib/ansible/modules/crypto/acme/acme_account.py @@ -21,16 +21,24 @@ version_added: "2.6" short_description: Create, modify or delete ACME accounts description: - "Allows to create, modify or delete accounts with a CA supporting the - L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-14), + L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-18), such as L(Let's Encrypt,https://letsencrypt.org/)." - "This module only works with the ACME v2 protocol." notes: - - "Facts about an ACME account can be retrieved with the M(acme_account_facts) - module." - "The M(acme_certificate) module also allows to do basic account management. When using both modules, it is recommended to disable account management for M(acme_certificate). For that, use the C(modify_account) option of M(acme_certificate)." +seealso: + - name: Automatic Certificate Management Environment (ACME) + description: The current draft specification of the ACME protocol. + link: https://tools.ietf.org/html/draft-ietf-acme-acme-18 + - module: acme_account_facts + description: Retrieves facts about an ACME account. + - module: openssl_privatekey + description: Can be used to create a private account key. + - module: acme_inspect + description: Allows to debug problems. extends_documentation_fragment: - acme options: @@ -55,7 +63,7 @@ options: description: - "A list of contact URLs." - "Email addresses must be prefixed with C(mailto:)." - - "See https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.1.2 + - "See https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.1.2 for what is allowed." - "Must be specified when state is C(present). Will be ignored if state is C(absent) or C(changed_key)." @@ -230,7 +238,7 @@ def main(): # Now we can start the account key rollover if not module.check_mode: # Compose inner signed message - # https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.3.6 + # https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3.5 url = account.directory['keyChange'] protected = { "alg": new_key_data['alg'], diff --git a/lib/ansible/modules/crypto/acme/acme_account_facts.py b/lib/ansible/modules/crypto/acme/acme_account_facts.py index 4a50efcff4c..a92e71b8bbb 100644 --- a/lib/ansible/modules/crypto/acme/acme_account_facts.py +++ b/lib/ansible/modules/crypto/acme/acme_account_facts.py @@ -21,11 +21,14 @@ version_added: "2.7" short_description: Retrieves information on ACME accounts description: - "Allows to retrieve information on accounts a CA supporting the - L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-14), + L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-18), such as L(Let's Encrypt,https://letsencrypt.org/)." - "This module only works with the ACME v2 protocol." notes: - "The M(acme_account) module allows to modify, create and delete ACME accounts." +seealso: + - module: acme_account + description: Allows to create, modify or delete an ACME account. extends_documentation_fragment: - acme ''' diff --git a/lib/ansible/modules/crypto/acme/acme_certificate.py b/lib/ansible/modules/crypto/acme/acme_certificate.py index dfbf5ceb77f..4e392d5f560 100644 --- a/lib/ansible/modules/crypto/acme/acme_certificate.py +++ b/lib/ansible/modules/crypto/acme/acme_certificate.py @@ -21,7 +21,7 @@ version_added: "2.2" short_description: Create SSL/TLS certificates with the ACME protocol description: - "Create and renew SSL/TLS certificates with a CA supporting the - L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-14), + L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-18), such as L(Let's Encrypt,https://letsencrypt.org/). The current implementation supports the C(http-01), C(dns-01) and C(tls-alpn-01) challenges." @@ -36,7 +36,7 @@ description: the necessary certificate has to be created and served. It is I(not) the responsibility of this module to perform these steps." - "For details on how to fulfill these challenges, you might have to read through - L(the main ACME specification,https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-8) + L(the main ACME specification,https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-8) and the L(TLS-ALPN-01 specification,https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-3). Also, consider the examples provided for this module." notes: @@ -47,12 +47,31 @@ notes: option." - "This module was called C(letsencrypt) before Ansible 2.6. The usage did not change." - - "If you want to use the C(tls-alpn-01) challenge, you can use the - M(acme_challenge_cert_helper) module to prepare the challenge certificate." - - "You can use the M(certificate_complete_chain) module to find the root certificate - for the returned fullchain." - - "In case you want to debug problems, you might be interested in the M(acme_inspect) - module." +seealso: + - name: The Let's Encrypt documentation + description: Documentation for the Let's Encrypt Certification Authority. + Provides useful information for example on rate limits. + link: https://letsencrypt.org/docs/ + - name: Automatic Certificate Management Environment (ACME) + description: The current draft specification of the ACME protocol. + link: https://tools.ietf.org/html/draft-ietf-acme-acme-18 + - name: ACME TLS ALPN Challenge Extension + description: The current draft specification of the C(tls-alpn-01) challenge. + link: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05 + - module: acme_challenge_cert_helper + description: Helps preparing C(tls-alpn-01) challenges. + - module: openssl_privatekey + description: Can be used to create private keys (both for certificates and accounts). + - module: openssl_csr + description: Can be used to create a Certificate Signing Request (CSR). + - module: certificate_complete_chain + description: Allows to find the root certificate for the returned fullchain. + - module: acme_certificate_revoke + description: Allows to revoke certificates. + - module: acme_account + description: Allows to create, modify or delete an ACME account. + - module: acme_inspect + description: Allows to debug problems. extends_documentation_fragment: - acme options: @@ -313,7 +332,7 @@ authorizations: type: complex contains: authorization: - description: ACME authorization object. See U(https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.1.4) + description: ACME authorization object. See U(https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.1.4) returned: success type: dict order_uri: @@ -503,11 +522,11 @@ class ACMEClient(object): keyauthorization = self.account.get_keyauthorization(token) if type == 'http-01': - # https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-8.3 + # https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-8.3 resource = '.well-known/acme-challenge/' + token data[type] = {'resource': resource, 'resource_value': keyauthorization} elif type == 'dns-01': - # https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-8.4 + # https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-8.4 resource = '_acme-challenge' value = nopad_b64(hashlib.sha256(to_bytes(keyauthorization)).digest()) record = (resource + domain[1:]) if domain.startswith('*.') else (resource + '.' + domain) @@ -584,7 +603,7 @@ class ACMEClient(object): ''' Create a new certificate based on the csr. Return the certificate object as dict - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.4 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.4 ''' csr = pem_to_der(self.csr) new_cert = { @@ -618,7 +637,7 @@ class ACMEClient(object): def _download_cert(self, url): ''' Download and parse the certificate chain. - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.4.2 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.4.2 ''' content, info = self.account.get_request(url, parse_json_result=False, headers={'Accept': 'application/pem-certificate-chain'}) @@ -686,7 +705,7 @@ class ACMEClient(object): def _new_order_v2(self): ''' Start a new certificate order (ACME v2 protocol). - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.4 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.4 ''' identifiers = [] for domain in self.domains: @@ -843,7 +862,7 @@ class ACMEClient(object): ''' Deactivates all valid authz's. Does not raise exceptions. https://community.letsencrypt.org/t/authorization-deactivation/19860/2 - https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.5.2 + https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.5.2 ''' authz_deactivate = { 'status': 'deactivated' diff --git a/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py b/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py index c1386f38ead..d13f8d90e5e 100644 --- a/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py +++ b/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py @@ -21,7 +21,7 @@ version_added: "2.7" short_description: Revoke certificates with the ACME protocol description: - "Allows to revoke certificates issued by a CA supporting the - L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-14), + L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-18), such as L(Let's Encrypt,https://letsencrypt.org/)." notes: - "Exactly one of C(account_key_src), C(account_key_content), @@ -31,6 +31,16 @@ notes: was different than the one specified here. Also, depending on the server, it can happen that some other error is returned if the certificate has already been revoked." +seealso: + - name: The Let's Encrypt documentation + description: Documentation for the Let's Encrypt Certification Authority. + Provides useful information for example on rate limits. + link: https://letsencrypt.org/docs/ + - name: Automatic Certificate Management Environment (ACME) + description: The current draft specification of the ACME protocol. + link: https://tools.ietf.org/html/draft-ietf-acme-acme-18 + - module: acme_inspect + description: Allows to debug problems. extends_documentation_fragment: - acme options: @@ -186,7 +196,7 @@ def main(): result, info = account.send_signed_request(endpoint, payload) if info['status'] != 200: already_revoked = False - # Standarized error in draft 14 (https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.6) + # Standarized error from draft 14 on (https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.6) if result.get('type') == 'urn:ietf:params:acme:error:alreadyRevoked': already_revoked = True else: diff --git a/lib/ansible/modules/crypto/acme/acme_challenge_cert_helper.py b/lib/ansible/modules/crypto/acme/acme_challenge_cert_helper.py index 6efd6823c7b..d843a40855b 100644 --- a/lib/ansible/modules/crypto/acme/acme_challenge_cert_helper.py +++ b/lib/ansible/modules/crypto/acme/acme_challenge_cert_helper.py @@ -26,6 +26,13 @@ description: provides a simple way to generate the required certificates." - "The C(tls-alpn-01) implementation is based on L(the draft-05 version of the specification,https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05)." +seealso: + - name: Automatic Certificate Management Environment (ACME) + description: The current draft specification of the ACME protocol. + link: https://tools.ietf.org/html/draft-ietf-acme-acme-18 + - name: ACME TLS ALPN Challenge Extension + description: The current draft specification of the C(tls-alpn-01) challenge. + link: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05 requirements: - "cryptography >= 1.3" options: diff --git a/lib/ansible/modules/crypto/acme/acme_inspect.py b/lib/ansible/modules/crypto/acme/acme_inspect.py index 89007364e15..0de8db09dea 100644 --- a/lib/ansible/modules/crypto/acme/acme_inspect.py +++ b/lib/ansible/modules/crypto/acme/acme_inspect.py @@ -21,7 +21,7 @@ version_added: "2.8" short_description: Send direct requests to an ACME server description: - "Allows to send direct requests to an ACME server with the - L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-14), + L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-18), which is supported by CAs such as L(Let's Encrypt,https://letsencrypt.org/)." - "This module can be used to debug failed certificate request attempts, for example when M(acme_certificate) fails or encounters a problem which @@ -39,6 +39,13 @@ notes: acme_directory=https://acme-v02.api.letsencrypt.org/directory acme_version=2 account_uri=https://acme-v02.api.letsencrypt.org/acme/acct/1 method=get url=https://acme-v02.api.letsencrypt.org/acme/acct/1\")" +seealso: + - name: Automatic Certificate Management Environment (ACME) + description: The current draft specification of the ACME protocol. + link: https://tools.ietf.org/html/draft-ietf-acme-acme-18 + - name: ACME TLS ALPN Challenge Extension + description: The current draft specification of the C(tls-alpn-01) challenge. + link: https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05 extends_documentation_fragment: - acme options: @@ -116,7 +123,7 @@ EXAMPLES = r''' vars: account_info: # For valid values, see - # https://tools.ietf.org/html/draft-ietf-acme-acme-16#section-7.3 + # https://tools.ietf.org/html/draft-ietf-acme-acme-18#section-7.3 contact: - mailto:me@example.com