Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

acme_certificate: allow 'no challenge' #615

Merged
merged 2 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelogs/fragments/615-no-challenge.yml
Original file line number Diff line number Diff line change
@@ -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)."
32 changes: 27 additions & 5 deletions plugins/modules/acme_certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,19 @@
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."
Expand Down Expand Up @@ -578,6 +587,9 @@
)


NO_CHALLENGE = 'no challenge'


class ACMECertificateClient(object):
'''
ACME client class. Uses an ACME account object and a CSR to
Expand All @@ -589,6 +601,9 @@ def __init__(self, module, backend):
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')
Expand Down Expand Up @@ -696,7 +711,7 @@ def get_challenges_data(self, first_step):
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
Expand Down Expand Up @@ -735,7 +750,14 @@ def finish_challenges(self):
for type_identifier, authz in self.authorizations.items():
if authz.status == 'pending':
identifier_type, identifier = split_identifier(type_identifier)
authz.call_validate(self.client, self.challenge)
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):
Expand Down Expand Up @@ -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'),
Expand Down