ACME modules: documentation improvements (#42165)

* Always using current draft when referring to ACME v2.

* Adding URL for ACME v1 protocol.

* Improve cross-referencing of acme_* modules.

* General improvements.

* Fixing syntax error.
This commit is contained in:
Felix Fontein 2018-07-04 15:22:11 +02:00 committed by René Moser
parent 6412cbf84b
commit 6b6c017dd1
5 changed files with 44 additions and 29 deletions

View file

@ -147,7 +147,7 @@ class ACMEDirectory(object):
and allows to obtain a Replay-Nonce. The acme_directory URL and allows to obtain a Replay-Nonce. The acme_directory URL
needs to support unauthenticated GET requests; ACME endpoints needs to support unauthenticated GET requests; ACME endpoints
requiring authentication are not supported. requiring authentication are not supported.
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.1.1 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.1.1
''' '''
def __init__(self, module): def __init__(self, module):
@ -228,7 +228,7 @@ class ACMEAccount(object):
def get_keyauthorization(self, token): def get_keyauthorization(self, token):
''' '''
Returns the key authorization for the given token Returns the key authorization for the given token
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-8.1 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8.1
''' '''
accountkey_json = json.dumps(self.jwk, sort_keys=True, separators=(',', ':')) accountkey_json = json.dumps(self.jwk, sort_keys=True, separators=(',', ':'))
thumbprint = nopad_b64(hashlib.sha256(accountkey_json.encode('utf8')).digest()) thumbprint = nopad_b64(hashlib.sha256(accountkey_json.encode('utf8')).digest())
@ -360,7 +360,7 @@ class ACMEAccount(object):
''' '''
Sends a JWS signed HTTP POST request to the ACME server and returns Sends a JWS signed HTTP POST request to the ACME server and returns
the response as dictionary the response as dictionary
https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-6.2 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-6.2
''' '''
key_data = key_data or self.key_data key_data = key_data or self.key_data
key = key or self.key key = key or self.key
@ -392,7 +392,7 @@ class ACMEAccount(object):
try: try:
result = self.module.from_json(content.decode('utf8')) result = self.module.from_json(content.decode('utf8'))
# In case of badNonce error, try again (up to 5 times) # In case of badNonce error, try again (up to 5 times)
# (https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-6.6) # (https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-6.6)
if (400 <= info['status'] < 600 and if (400 <= info['status'] < 600 and
result.get('type') == 'urn:ietf:params:acme:error:badNonce' and result.get('type') == 'urn:ietf:params:acme:error:badNonce' and
failed_tries <= 5): failed_tries <= 5):
@ -420,7 +420,7 @@ class ACMEAccount(object):
Registers a new ACME account. Returns True if the account was Registers a new ACME account. Returns True if the account was
created and False if it already existed (e.g. it was not newly created and False if it already existed (e.g. it was not newly
created). created).
https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.3 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.3
''' '''
contact = [] if contact is None else contact contact = [] if contact is None else contact
@ -498,7 +498,7 @@ class ACMEAccount(object):
will be stored in self.uri; if it is None, the account does not will be stored in self.uri; if it is None, the account does not
exist. exist.
https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.3 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.3
''' '''
new_account = True new_account = True

View file

@ -23,6 +23,10 @@ description:
- "Allows to create, modify or delete accounts with Let's Encrypt. - "Allows to create, modify or delete accounts with Let's Encrypt.
Let's Encrypt is a free, automated, and open certificate authority Let's Encrypt is a free, automated, and open certificate authority
(CA), run for the public's benefit. For details see U(https://letsencrypt.org)." (CA), run for the public's benefit. For details see U(https://letsencrypt.org)."
- "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)."
- "This module only works with the ACME v2 protocol." - "This module only works with the ACME v2 protocol."
extends_documentation_fragment: extends_documentation_fragment:
- acme - acme
@ -48,7 +52,7 @@ options:
description: description:
- "A list of contact URLs." - "A list of contact URLs."
- "Email addresses must be prefixed with C(mailto:)." - "Email addresses must be prefixed with C(mailto:)."
- "See https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.1.2 - "See https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.1.2
for what is allowed." for what is allowed."
- "Must be specified when state is C(present). Will be ignored - "Must be specified when state is C(present). Will be ignored
if state is C(absent) or C(changed_key)." if state is C(absent) or C(changed_key)."

View file

@ -20,10 +20,10 @@ author: "Michael Gruener (@mgruener)"
version_added: "2.2" version_added: "2.2"
short_description: Create SSL certificates with an ACME protocol endpoint short_description: Create SSL certificates with an ACME protocol endpoint
description: description:
- "Create and renew SSL certificates with a CA supporting the ACME protocol, - "Create and renew SSL certificates with a CA supporting the
such as Let's Encrypt (U(https://letsencrypt.org)). For details see L(ACME protocol,https://tools.ietf.org/html/draft-ietf-acme-acme-12),
U(https://letsencrypt.org). The current implementation supports the such as L(Let's Encrypt,https://letsencrypt.org/). The current
C(http-01) and C(dns-01) challenges." implementation supports the C(http-01) and C(dns-01) challenges."
- "To use this module, it has to be executed twice. Either as two - "To use this module, it has to be executed twice. Either as two
different tasks in the same run or during two runs. Note that the output different tasks in the same run or during two runs. Note that the output
of the first run needs to be recorded and passed to the second run as the of the first run needs to be recorded and passed to the second run as the
@ -34,12 +34,16 @@ description:
C(dns-01) the necessary dns record has to be created. C(dns-01) the necessary dns record has to be created.
It is I(not) the responsibility of this module to perform these steps." 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 - "For details on how to fulfill these challenges, you might have to read through
U(https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8). L(the specification,https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8).
Also, consider the examples provided for this module." Also, consider the examples provided for this module."
- "Although the defaults are chosen so that the module can be used with - "Although the defaults are chosen so that the module can be used with
the Let's Encrypt CA, the module can be used with any service using the ACME the Let's Encrypt CA, the module can be used with any service using the ACME
v1 or v2 protocol." v1 or v2 protocol."
- "At least one of C(dest) and C(fullchain_dest) must be specified." - "At least one of C(dest) and C(fullchain_dest) must be specified."
- "Note that this module includes basic account management functionality.
If you want to have more control over your ACME account, use the M(acme_account)
module and disable account management for this module using the C(modify_account)
option."
- "Note: this module was called C(letsencrypt) before Ansible 2.6. The usage - "Note: this module was called C(letsencrypt) before Ansible 2.6. The usage
did not change." did not change."
extends_documentation_fragment: extends_documentation_fragment:
@ -49,6 +53,10 @@ options:
description: description:
- "The email address associated with this account." - "The email address associated with this account."
- "It will be used for certificate expiration warnings." - "It will be used for certificate expiration warnings."
- "Note that when C(modify_account) is not set to C(no) and you also
used the M(acme_account) module to specify more than one contact
for your account, this module will update your account and restrict
it to the (at most one) contact email address specified here."
agreement: agreement:
description: description:
- "URI to a terms of service document you agree to when using the - "URI to a terms of service document you agree to when using the
@ -67,9 +75,9 @@ options:
description: description:
- "Boolean indicating whether the module should create the account if - "Boolean indicating whether the module should create the account if
necessary, and update its contact data." necessary, and update its contact data."
- "Set to C(no) if you want to use C(acme_account) to manage your - "Set to C(no) if you want to use the M(acme_account) module to manage
account instead, and to avoid accidental creation of a new account your account instead, and to avoid accidental creation of a new account
using an old key if you changed the account key with C(acme_account)." using an old key if you changed the account key with M(acme_account)."
- "If set to C(no), C(terms_agreed) and C(account_email) are ignored." - "If set to C(no), C(terms_agreed) and C(account_email) are ignored."
type: bool type: bool
default: 'yes' default: 'yes'
@ -465,11 +473,11 @@ class ACMEClient(object):
keyauthorization = self.account.get_keyauthorization(token) keyauthorization = self.account.get_keyauthorization(token)
if type == 'http-01': if type == 'http-01':
# https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-8.3 # https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8.3
resource = '.well-known/acme-challenge/' + token resource = '.well-known/acme-challenge/' + token
data[type] = {'resource': resource, 'resource_value': keyauthorization} data[type] = {'resource': resource, 'resource_value': keyauthorization}
elif type == 'dns-01': elif type == 'dns-01':
# https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-8.5 # https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8.4
resource = '_acme-challenge' resource = '_acme-challenge'
value = nopad_b64(hashlib.sha256(to_bytes(keyauthorization)).digest()) value = nopad_b64(hashlib.sha256(to_bytes(keyauthorization)).digest())
record = (resource + domain[1:]) if domain.startswith('*.') else (resource + '.' + domain) record = (resource + domain[1:]) if domain.startswith('*.') else (resource + '.' + domain)
@ -523,7 +531,7 @@ class ACMEClient(object):
result['uri'] = auth['uri'] result['uri'] = auth['uri']
if self._add_or_update_auth(domain, result): if self._add_or_update_auth(domain, result):
self.changed = True self.changed = True
# draft-ietf-acme-acme-02 # https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.1.2
# "status (required, string): ... # "status (required, string): ...
# If this field is missing, then the default value is "pending"." # If this field is missing, then the default value is "pending"."
if self.version == 1 and 'status' not in result: if self.version == 1 and 'status' not in result:
@ -541,7 +549,7 @@ class ACMEClient(object):
''' '''
Create a new certificate based on the csr. Create a new certificate based on the csr.
Return the certificate object as dict Return the certificate object as dict
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.4 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.4
''' '''
openssl_csr_cmd = [self._openssl_bin, "req", "-in", self.csr, "-outform", "DER"] openssl_csr_cmd = [self._openssl_bin, "req", "-in", self.csr, "-outform", "DER"]
dummy, out, dummy = self.module.run_command(openssl_csr_cmd, check_rc=True) dummy, out, dummy = self.module.run_command(openssl_csr_cmd, check_rc=True)
@ -577,7 +585,7 @@ class ACMEClient(object):
def _download_cert(self, url): def _download_cert(self, url):
''' '''
Download and parse the certificate chain. Download and parse the certificate chain.
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.4.2 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.4.2
''' '''
resp, info = fetch_url(self.module, url, headers={'Accept': 'application/pem-certificate-chain'}) resp, info = fetch_url(self.module, url, headers={'Accept': 'application/pem-certificate-chain'})
try: try:
@ -651,7 +659,7 @@ class ACMEClient(object):
def _new_order_v2(self): def _new_order_v2(self):
''' '''
Start a new certificate order (ACME v2 protocol). Start a new certificate order (ACME v2 protocol).
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.4 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.4
''' '''
identifiers = [] identifiers = []
for domain in self.domains: for domain in self.domains:
@ -813,7 +821,7 @@ class ACMEClient(object):
''' '''
Deactivates all valid authz's. Does not raise exceptions. Deactivates all valid authz's. Does not raise exceptions.
https://community.letsencrypt.org/t/authorization-deactivation/19860/2 https://community.letsencrypt.org/t/authorization-deactivation/19860/2
https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-7.5.2 https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.5.2
''' '''
authz_deactivate = { authz_deactivate = {
'status': 'deactivated' 'status': 'deactivated'

View file

@ -20,8 +20,10 @@ author: "Felix Fontein (@felixfontein)"
version_added: "2.7" version_added: "2.7"
short_description: Revoke certificates with the ACME protocol. short_description: Revoke certificates with the ACME protocol.
description: description:
- "Allows to revoke certificates with the ACME protocol. This protocol - "Allows to revoke certificates with the ACME protocol, for example
is, for example, used by Let's Encrypt." for certificates obtained by the M(acme_certificate) module. The
ACME protocol is used by some Certificate Authorities such as
L(Let's Encrypt,https://letsencrypt.org/)."
- "Note that exactly one of C(account_key_src), C(account_key_content), - "Note that exactly one of C(account_key_src), C(account_key_content),
C(private_key_src) or C(private_key_content) must be specified." C(private_key_src) or C(private_key_content) must be specified."
- "Also note that in general, trying to revoke an already revoked - "Also note that in general, trying to revoke an already revoked
@ -48,7 +50,7 @@ options:
- "Content of the certificate's private key." - "Content of the certificate's private key."
- "Note that exactly one of C(account_key_src), C(account_key_content), - "Note that exactly one of C(account_key_src), C(account_key_content),
C(private_key_src) or C(private_key_content) must be specified." C(private_key_src) or C(private_key_content) must be specified."
- "Warning: the content will be written into a temporary file, which will - "I(Warning): the content will be written into a temporary file, which will
be deleted by Ansible when the module completes. Since this is an be deleted by Ansible when the module completes. Since this is an
important private key it can be used to change the account key, important private key it can be used to change the account key,
or to revoke your certificates without knowing their private keys or to revoke your certificates without knowing their private keys

View file

@ -17,7 +17,8 @@ options:
- "Path to a file containing the ACME account RSA or Elliptic Curve - "Path to a file containing the ACME account RSA or Elliptic Curve
key." key."
- "RSA keys can be created with C(openssl rsa ...). Elliptic curve keys can - "RSA keys can be created with C(openssl rsa ...). Elliptic curve keys can
be created with C(openssl ecparam -genkey ...)." be created with C(openssl ecparam -genkey ...). Any other tool creating
private keys in PEM format can be used as well."
- "Mutually exclusive with C(account_key_content)." - "Mutually exclusive with C(account_key_content)."
- "Required if C(account_key_content) is not used." - "Required if C(account_key_content) is not used."
aliases: [ account_key ] aliases: [ account_key ]
@ -26,7 +27,7 @@ options:
- "Content of the ACME account RSA or Elliptic Curve key." - "Content of the ACME account RSA or Elliptic Curve key."
- "Mutually exclusive with C(account_key_src)." - "Mutually exclusive with C(account_key_src)."
- "Required if C(account_key_src) is not used." - "Required if C(account_key_src) is not used."
- "Warning: the content will be written into a temporary file, which will - "I(Warning): the content will be written into a temporary file, which will
be deleted by Ansible when the module completes. Since this is an be deleted by Ansible when the module completes. Since this is an
important private key it can be used to change the account key, important private key it can be used to change the account key,
or to revoke your certificates without knowing their private keys or to revoke your certificates without knowing their private keys
@ -59,8 +60,8 @@ options:
validate_certs: validate_certs:
description: description:
- Whether calls to the ACME directory will validate TLS certificates. - Whether calls to the ACME directory will validate TLS certificates.
- I(Warning:) Should I(only ever) be set to C(no) for testing purposes, - "I(Warning): Should I(only ever) be set to C(no) for testing purposes,
for example when testing against a local Pebble server. for example when testing against a local Pebble server."
type: bool type: bool
default: 'yes' default: 'yes'
version_added: 2.5 version_added: 2.5