acme_certificate: allow 'no challenge' (#615)

* Allow 'no challenge'.

* Fix undefined variable.
pull/617/head
Felix Fontein 2023-06-05 20:54:07 +02:00 committed by GitHub
parent 9305bfe190
commit 17702d1a76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 5 deletions

View File

@ -0,0 +1,4 @@
minor_changes:
- "acme_certificate - allow to use no challenge by providing ``no challenge`` for the ``challenge`` option.
This is needed for ACME servers where validation is done without challenges
(https://github.com/ansible-collections/community.crypto/issues/613, https://github.com/ansible-collections/community.crypto/pull/615)."

View File

@ -124,10 +124,19 @@ options:
type: bool
default: true
challenge:
description: The challenge to be performed.
description:
- The challenge to be performed.
- If set to C(no challenge), no challenge will be used. This is necessary for some private
CAs which use External Account Binding and other means of validating certificate assurance.
For example, an account could be allowed to issue certificates for C(foo.example.com)
without any further validation for a certain period of time.
type: str
default: 'http-01'
choices: [ 'http-01', 'dns-01', 'tls-alpn-01' ]
choices:
- 'http-01'
- 'dns-01'
- 'tls-alpn-01'
- 'no challenge'
csr:
description:
- "File containing the CSR for the new certificate."
@ -578,6 +587,9 @@ from ansible_collections.community.crypto.plugins.module_utils.acme.utils import
)
NO_CHALLENGE = 'no challenge'
class ACMECertificateClient(object):
'''
ACME client class. Uses an ACME account object and a CSR to
@ -589,6 +601,9 @@ class ACMECertificateClient(object):
self.module = module
self.version = module.params['acme_version']
self.challenge = module.params['challenge']
# We use None instead of a magic string for 'no challenge'
if self.challenge == NO_CHALLENGE:
self.challenge = None
self.csr = module.params['csr']
self.csr_content = module.params['csr_content']
self.dest = module.params.get('dest')
@ -696,7 +711,7 @@ class ACMECertificateClient(object):
continue
# We drop the type from the key to preserve backwards compatibility
data[identifier] = authz.get_challenge_data(self.client)
if first_step and self.challenge not in data[identifier]:
if first_step and self.challenge is not None and self.challenge not in data[identifier]:
raise ModuleFailException("Found no challenge of type '{0}' for identifier {1}!".format(
self.challenge, type_identifier))
# Get DNS challenge data
@ -735,7 +750,14 @@ class ACMECertificateClient(object):
for type_identifier, authz in self.authorizations.items():
if authz.status == 'pending':
identifier_type, identifier = split_identifier(type_identifier)
if self.challenge is not None:
authz.call_validate(self.client, self.challenge)
# If there is no challenge, we must check whether the authz is valid
elif authz.status != 'valid':
authz.raise_error(
'Status is not "valid", even though no challenge should be necessary',
module=self.client.module,
)
self.changed = True
def download_alternate_chains(self, cert):
@ -832,7 +854,7 @@ def main():
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']),
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'),