ACME: add diff to acme_account, account_public_key to acme_account_facts, and general refactoring (#49410)
* Only one exit point. * Refactoring account handling. * Add diff support for acme_account. * Insert public_account_key into acme_account_facts result and into acme_account diff. * Add changelog.
This commit is contained in:
parent
62dd1fe29e
commit
b0c7efcc6b
9 changed files with 305 additions and 104 deletions
3
changelogs/fragments/49410-acme-diff.yml
Normal file
3
changelogs/fragments/49410-acme-diff.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
minor_changes:
|
||||||
|
- "acme_account: add support for diff mode."
|
||||||
|
- "acme_account_facts: also return ``public_account_key`` in JWK format."
|
|
@ -646,12 +646,14 @@ class ACMEAccount(object):
|
||||||
|
|
||||||
def _new_reg(self, contact=None, agreement=None, terms_agreed=False, allow_creation=True):
|
def _new_reg(self, contact=None, agreement=None, terms_agreed=False, allow_creation=True):
|
||||||
'''
|
'''
|
||||||
Registers a new ACME account. Returns True if the account was
|
Registers a new ACME account. Returns a pair ``(created, data)``.
|
||||||
created and False if it already existed (e.g. it was not newly
|
Here, ``created`` is ``True`` if the account was created and
|
||||||
created).
|
``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-14#section-7.3
|
||||||
'''
|
'''
|
||||||
contact = [] if contact is None else contact
|
contact = contact or []
|
||||||
|
|
||||||
if self.version == 1:
|
if self.version == 1:
|
||||||
new_reg = {
|
new_reg = {
|
||||||
|
@ -668,6 +670,7 @@ class ACMEAccount(object):
|
||||||
'contact': contact
|
'contact': contact
|
||||||
}
|
}
|
||||||
if not allow_creation:
|
if not allow_creation:
|
||||||
|
# https://tools.ietf.org/html/draft-ietf-acme-acme-14#section-7.3.1
|
||||||
new_reg['onlyReturnExisting'] = True
|
new_reg['onlyReturnExisting'] = True
|
||||||
if terms_agreed:
|
if terms_agreed:
|
||||||
new_reg['termsOfServiceAgreed'] = True
|
new_reg['termsOfServiceAgreed'] = True
|
||||||
|
@ -679,7 +682,7 @@ class ACMEAccount(object):
|
||||||
# Account did not exist
|
# Account did not exist
|
||||||
if 'location' in info:
|
if 'location' in info:
|
||||||
self.set_account_uri(info['location'])
|
self.set_account_uri(info['location'])
|
||||||
return True
|
return True, result
|
||||||
elif info['status'] == (409 if self.version == 1 else 200):
|
elif info['status'] == (409 if self.version == 1 else 200):
|
||||||
# Account did exist
|
# Account did exist
|
||||||
if result.get('status') == 'deactivated':
|
if result.get('status') == 'deactivated':
|
||||||
|
@ -689,22 +692,22 @@ class ACMEAccount(object):
|
||||||
# "Once an account is deactivated, the server MUST NOT accept further
|
# "Once an account is deactivated, the server MUST NOT accept further
|
||||||
# requests authorized by that account's key."
|
# requests authorized by that account's key."
|
||||||
if not allow_creation:
|
if not allow_creation:
|
||||||
return False
|
return False, None
|
||||||
else:
|
else:
|
||||||
raise ModuleFailException("Account is deactivated")
|
raise ModuleFailException("Account is deactivated")
|
||||||
if 'location' in info:
|
if 'location' in info:
|
||||||
self.set_account_uri(info['location'])
|
self.set_account_uri(info['location'])
|
||||||
return False
|
return False, result
|
||||||
elif info['status'] == 400 and result['type'] == 'urn:ietf:params:acme:error:accountDoesNotExist' and not allow_creation:
|
elif info['status'] == 400 and result['type'] == 'urn:ietf:params:acme:error:accountDoesNotExist' and not allow_creation:
|
||||||
# Account does not exist (and we didn't try to create it)
|
# Account does not exist (and we didn't try to create it)
|
||||||
return False
|
return False, None
|
||||||
else:
|
else:
|
||||||
raise ModuleFailException("Error registering: {0} {1}".format(info['status'], result))
|
raise ModuleFailException("Error registering: {0} {1}".format(info['status'], result))
|
||||||
|
|
||||||
def get_account_data(self):
|
def get_account_data(self):
|
||||||
'''
|
'''
|
||||||
Retrieve account information. Can only be called when the account
|
Retrieve account information. Can only be called when the account
|
||||||
URI is already known (such as after calling init_account).
|
URI is already known (such as after calling setup_account).
|
||||||
Return None if the account was deactivated, or a dict otherwise.
|
Return None if the account was deactivated, or a dict otherwise.
|
||||||
'''
|
'''
|
||||||
if self.uri is None:
|
if self.uri is None:
|
||||||
|
@ -732,66 +735,82 @@ class ACMEAccount(object):
|
||||||
raise ModuleFailException("Error getting account data from {2}: {0} {1}".format(info['status'], result, self.uri))
|
raise ModuleFailException("Error getting account data from {2}: {0} {1}".format(info['status'], result, self.uri))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def init_account(self, contact, agreement=None, terms_agreed=False, allow_creation=True, update_contact=True, remove_account_uri_if_not_exists=False):
|
def setup_account(self, contact=None, agreement=None, terms_agreed=False, allow_creation=True, remove_account_uri_if_not_exists=False):
|
||||||
'''
|
'''
|
||||||
Create or update an account on the ACME server. For ACME v1,
|
Detect or create an account on the ACME server. For ACME v1,
|
||||||
as the only way (without knowing an account URI) to test if an
|
as the only way (without knowing an account URI) to test if an
|
||||||
account exists is to try and create one with the provided account
|
account exists is to try and create one with the provided account
|
||||||
key, this method will always result in an account being present
|
key, this method will always result in an account being present
|
||||||
(except on error situations). For ACME v2, a new account will
|
(except on error situations). For ACME v2, a new account will
|
||||||
only be created if allow_creation is set to True.
|
only be created if ``allow_creation`` is set to True.
|
||||||
|
|
||||||
For ACME v2, check_mode is fully respected. For ACME v1, the account
|
For ACME v2, ``check_mode`` is fully respected. For ACME v1, the
|
||||||
might be created if it does not yet exist.
|
account might be created if it does not yet exist.
|
||||||
|
|
||||||
If the account already exists and if update_contact is set to
|
Return a pair ``(created, account_data)``. Here, ``created`` will
|
||||||
True, this method will update the contact information.
|
be ``True`` in case the account was created or would be created
|
||||||
|
(check mode). ``account_data`` will be the current account data,
|
||||||
|
or ``None`` if the account does not exist.
|
||||||
|
|
||||||
Return True in case something changed (account was created, contact
|
The account URI will be stored in ``self.uri``; if it is ``None``,
|
||||||
info updated) or would be changed (check_mode). The account URI
|
the account does not exist.
|
||||||
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-14#section-7.3
|
||||||
'''
|
'''
|
||||||
|
|
||||||
new_account = True
|
|
||||||
changed = False
|
|
||||||
if self.uri is not None:
|
if self.uri is not None:
|
||||||
new_account = False
|
created = False
|
||||||
if not update_contact:
|
# Verify that the account key belongs to the URI.
|
||||||
# Verify that the account key belongs to the URI.
|
# (If update_contact is True, this will be done below.)
|
||||||
# (If update_contact is True, this will be done below.)
|
account_data = self.get_account_data()
|
||||||
if self.get_account_data() is None:
|
if account_data is None:
|
||||||
if remove_account_uri_if_not_exists and not allow_creation:
|
if remove_account_uri_if_not_exists and not allow_creation:
|
||||||
self.uri = None
|
self.uri = None
|
||||||
return False
|
else:
|
||||||
raise ModuleFailException("Account is deactivated or does not exist!")
|
raise ModuleFailException("Account is deactivated or does not exist!")
|
||||||
else:
|
else:
|
||||||
new_account = self._new_reg(
|
created, account_data = self._new_reg(
|
||||||
contact,
|
contact,
|
||||||
agreement=agreement,
|
agreement=agreement,
|
||||||
terms_agreed=terms_agreed,
|
terms_agreed=terms_agreed,
|
||||||
allow_creation=allow_creation and not self.module.check_mode
|
allow_creation=allow_creation and not self.module.check_mode
|
||||||
)
|
)
|
||||||
if self.module.check_mode and self.uri is None and allow_creation:
|
if self.module.check_mode and self.uri is None and allow_creation:
|
||||||
return True
|
created = True
|
||||||
if not new_account and self.uri and update_contact:
|
account_data = {
|
||||||
result = self.get_account_data()
|
'contact': contact or []
|
||||||
if result is None:
|
}
|
||||||
if not allow_creation:
|
return created, account_data
|
||||||
self.uri = None
|
|
||||||
return False
|
|
||||||
raise ModuleFailException("Account is deactivated or does not exist!")
|
|
||||||
|
|
||||||
# ...and check if update is necessary
|
def update_account(self, account_data, contact=None):
|
||||||
if result.get('contact', []) != contact:
|
'''
|
||||||
if not self.module.check_mode:
|
Update an account on the ACME server. Check mode is fully respected.
|
||||||
upd_reg = result
|
|
||||||
upd_reg['contact'] = contact
|
The current account data must be provided as ``account_data``.
|
||||||
result, dummy = self.send_signed_request(self.uri, upd_reg)
|
|
||||||
changed = True
|
Return a pair ``(updated, account_data)``, where ``updated`` is
|
||||||
return new_account or changed
|
``True`` in case something changed (contact info updated) or
|
||||||
|
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
|
||||||
|
'''
|
||||||
|
# Create request
|
||||||
|
update_request = {}
|
||||||
|
if contact is not None and account_data.get('contact', []) != contact:
|
||||||
|
update_request['contact'] = list(contact)
|
||||||
|
|
||||||
|
# No change?
|
||||||
|
if not update_request:
|
||||||
|
return False, dict(account_data)
|
||||||
|
|
||||||
|
# Apply change
|
||||||
|
if self.module.check_mode:
|
||||||
|
account_data = dict(account_data)
|
||||||
|
account_data.update(update_request)
|
||||||
|
else:
|
||||||
|
account_data, dummy = self.send_signed_request(self.uri, update_request)
|
||||||
|
return True, account_data
|
||||||
|
|
||||||
|
|
||||||
def cryptography_get_csr_domains(module, csr_filename):
|
def cryptography_get_csr_domains(module, csr_filename):
|
||||||
|
|
|
@ -166,43 +166,51 @@ def main():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
account = ACMEAccount(module)
|
account = ACMEAccount(module)
|
||||||
|
changed = False
|
||||||
state = module.params.get('state')
|
state = module.params.get('state')
|
||||||
|
diff_before = {}
|
||||||
|
diff_after = {}
|
||||||
if state == 'absent':
|
if state == 'absent':
|
||||||
changed = account.init_account(
|
created, account_data = account.setup_account(allow_creation=False)
|
||||||
[],
|
if account_data:
|
||||||
allow_creation=False,
|
diff_before = dict(account_data)
|
||||||
update_contact=False,
|
diff_before['public_account_key'] = account.key_data['jwk']
|
||||||
)
|
if created:
|
||||||
if changed:
|
raise AssertionError('Unwanted account creation')
|
||||||
raise AssertionError('Unwanted account change')
|
if account_data is not None:
|
||||||
if account.uri is not None:
|
# Account is not yet deactivated
|
||||||
# Account does exist
|
if not module.check_mode:
|
||||||
account_data = account.get_account_data()
|
# Deactivate it
|
||||||
if account_data is not None:
|
payload = {
|
||||||
# Account is not yet deactivated
|
'status': 'deactivated'
|
||||||
if not module.check_mode:
|
}
|
||||||
# Deactivate it
|
result, info = account.send_signed_request(account.uri, payload)
|
||||||
payload = {
|
if info['status'] != 200:
|
||||||
'status': 'deactivated'
|
raise ModuleFailException('Error deactivating account: {0} {1}'.format(info['status'], result))
|
||||||
}
|
changed = True
|
||||||
result, info = account.send_signed_request(account.uri, payload)
|
|
||||||
if info['status'] != 200:
|
|
||||||
raise ModuleFailException('Error deactivating account: {0} {1}'.format(info['status'], result))
|
|
||||||
module.exit_json(changed=True, account_uri=account.uri)
|
|
||||||
module.exit_json(changed=False, account_uri=account.uri)
|
|
||||||
elif state == 'present':
|
elif state == 'present':
|
||||||
allow_creation = module.params.get('allow_creation')
|
allow_creation = module.params.get('allow_creation')
|
||||||
# Make sure contact is a list of strings (unfortunately, Ansible doesn't do that for us)
|
# Make sure contact is a list of strings (unfortunately, Ansible doesn't do that for us)
|
||||||
contact = [str(v) for v in module.params.get('contact')]
|
contact = [str(v) for v in module.params.get('contact')]
|
||||||
terms_agreed = module.params.get('terms_agreed')
|
terms_agreed = module.params.get('terms_agreed')
|
||||||
changed = account.init_account(
|
created, account_data = account.setup_account(
|
||||||
contact,
|
contact,
|
||||||
terms_agreed=terms_agreed,
|
terms_agreed=terms_agreed,
|
||||||
allow_creation=allow_creation,
|
allow_creation=allow_creation,
|
||||||
)
|
)
|
||||||
if account.uri is None:
|
if account_data is None:
|
||||||
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
||||||
module.exit_json(changed=changed, account_uri=account.uri)
|
if created:
|
||||||
|
diff_before = {}
|
||||||
|
else:
|
||||||
|
diff_before = dict(account_data)
|
||||||
|
diff_before['public_account_key'] = account.key_data['jwk']
|
||||||
|
updated = False
|
||||||
|
if not created:
|
||||||
|
updated, account_data = account.update_account(account_data, contact)
|
||||||
|
changed = created or updated
|
||||||
|
diff_after = dict(account_data)
|
||||||
|
diff_after['public_account_key'] = account.key_data['jwk']
|
||||||
elif state == 'changed_key':
|
elif state == 'changed_key':
|
||||||
# Parse new account key
|
# Parse new account key
|
||||||
error, new_key_data = account.parse_key(
|
error, new_key_data = account.parse_key(
|
||||||
|
@ -212,15 +220,13 @@ def main():
|
||||||
if error:
|
if error:
|
||||||
raise ModuleFailException("error while parsing account key: %s" % error)
|
raise ModuleFailException("error while parsing account key: %s" % error)
|
||||||
# Verify that the account exists and has not been deactivated
|
# Verify that the account exists and has not been deactivated
|
||||||
changed = account.init_account(
|
created, account_data = account.setup_account(allow_creation=False)
|
||||||
[],
|
if created:
|
||||||
allow_creation=False,
|
raise AssertionError('Unwanted account creation')
|
||||||
update_contact=False,
|
if account_data is None:
|
||||||
)
|
|
||||||
if changed:
|
|
||||||
raise AssertionError('Unwanted account change')
|
|
||||||
if account.uri is None or account.get_account_data() is None:
|
|
||||||
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
||||||
|
diff_before = dict(account_data)
|
||||||
|
diff_before['public_account_key'] = account.key_data['jwk']
|
||||||
# Now we can start the account key rollover
|
# Now we can start the account key rollover
|
||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
# Compose inner signed message
|
# Compose inner signed message
|
||||||
|
@ -241,7 +247,25 @@ def main():
|
||||||
result, info = account.send_signed_request(url, data)
|
result, info = account.send_signed_request(url, data)
|
||||||
if info['status'] != 200:
|
if info['status'] != 200:
|
||||||
raise ModuleFailException('Error account key rollover: {0} {1}'.format(info['status'], result))
|
raise ModuleFailException('Error account key rollover: {0} {1}'.format(info['status'], result))
|
||||||
module.exit_json(changed=True, account_uri=account.uri)
|
if module._diff:
|
||||||
|
account.key_data = new_key_data
|
||||||
|
account.jws_header['alg'] = new_key_data['alg']
|
||||||
|
diff_after = account.get_account_data()
|
||||||
|
elif module._diff:
|
||||||
|
# Kind of fake diff_after
|
||||||
|
diff_after = dict(diff_before)
|
||||||
|
diff_after['public_account_key'] = new_key_data['jwk']
|
||||||
|
changed = True
|
||||||
|
result = {
|
||||||
|
'changed': changed,
|
||||||
|
'account_uri': account.uri,
|
||||||
|
}
|
||||||
|
if module._diff:
|
||||||
|
result['diff'] = {
|
||||||
|
'before': diff_before,
|
||||||
|
'after': diff_after,
|
||||||
|
}
|
||||||
|
module.exit_json(**result)
|
||||||
except ModuleFailException as e:
|
except ModuleFailException as e:
|
||||||
e.do_fail(module)
|
e.do_fail(module)
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,11 @@ account:
|
||||||
returned: always
|
returned: always
|
||||||
type: str
|
type: str
|
||||||
sample: https://example.ca/account/1/orders
|
sample: https://example.ca/account/1/orders
|
||||||
|
public_account_key:
|
||||||
|
description: the public account key as a L(JSON Web Key,https://tools.ietf.org/html/rfc7517).
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: https://example.ca/account/1/orders
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from ansible.module_utils.acme import (
|
from ansible.module_utils.acme import (
|
||||||
|
@ -129,24 +134,25 @@ def main():
|
||||||
try:
|
try:
|
||||||
account = ACMEAccount(module)
|
account = ACMEAccount(module)
|
||||||
# Check whether account exists
|
# Check whether account exists
|
||||||
changed = account.init_account(
|
created, account_data = account.setup_account(
|
||||||
[],
|
[],
|
||||||
allow_creation=False,
|
allow_creation=False,
|
||||||
update_contact=False,
|
|
||||||
remove_account_uri_if_not_exists=True,
|
remove_account_uri_if_not_exists=True,
|
||||||
)
|
)
|
||||||
if changed:
|
if created:
|
||||||
raise AssertionError('Unwanted account change')
|
raise AssertionError('Unwanted account creation')
|
||||||
if account.uri is None:
|
result = {
|
||||||
# Account does exist
|
'changed': False,
|
||||||
module.exit_json(changed=False, exists=False, account_uri=None)
|
'exists': account.uri is not None,
|
||||||
else:
|
'account_uri': account.uri,
|
||||||
# Account exists: retrieve account information
|
}
|
||||||
data = account.get_account_data()
|
if account.uri is not None:
|
||||||
# Make sure promised data is there
|
# Make sure promised data is there
|
||||||
if 'contact' not in data:
|
if 'contact' not in account_data:
|
||||||
data['contact'] = []
|
account_data['contact'] = []
|
||||||
module.exit_json(changed=False, exists=True, account_uri=account.uri, account=data)
|
account_data['public_account_key'] = account.key_data['jwk']
|
||||||
|
result['account'] = account_data
|
||||||
|
module.exit_json(**result)
|
||||||
except ModuleFailException as e:
|
except ModuleFailException as e:
|
||||||
e.do_fail(module)
|
e.do_fail(module)
|
||||||
|
|
||||||
|
|
|
@ -406,16 +406,21 @@ class ACMEClient(object):
|
||||||
contact = []
|
contact = []
|
||||||
if module.params['account_email']:
|
if module.params['account_email']:
|
||||||
contact.append('mailto:' + module.params['account_email'])
|
contact.append('mailto:' + module.params['account_email'])
|
||||||
self.changed = self.account.init_account(
|
created, account_data = self.account.setup_account(
|
||||||
contact,
|
contact,
|
||||||
agreement=module.params.get('agreement'),
|
agreement=module.params.get('agreement'),
|
||||||
terms_agreed=module.params.get('terms_agreed'),
|
terms_agreed=module.params.get('terms_agreed'),
|
||||||
allow_creation=modify_account,
|
allow_creation=modify_account,
|
||||||
update_contact=modify_account
|
|
||||||
)
|
)
|
||||||
|
if account_data is None:
|
||||||
|
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
||||||
|
updated = False
|
||||||
|
if not created and account_data and modify_account:
|
||||||
|
updated, account_data = self.account.update_account(account_data, contact)
|
||||||
|
self.changed = created or updated
|
||||||
else:
|
else:
|
||||||
# This happens if modify_account is False and the ACME v1
|
# This happens if modify_account is False and the ACME v1
|
||||||
# protocol is used. In this case, we do not call init_account()
|
# protocol is used. In this case, we do not call setup_account()
|
||||||
# to avoid accidental creation of an account. This is OK
|
# to avoid accidental creation of an account. This is OK
|
||||||
# since for ACME v1, the account URI is not needed to send a
|
# since for ACME v1, the account URI is not needed to send a
|
||||||
# signed ACME request.
|
# signed ACME request.
|
||||||
|
|
|
@ -177,13 +177,11 @@ def main():
|
||||||
result, info = account.send_signed_request(endpoint, payload, key_data=private_key_data, jws_header=jws_header)
|
result, info = account.send_signed_request(endpoint, payload, key_data=private_key_data, jws_header=jws_header)
|
||||||
else:
|
else:
|
||||||
# Step 1: get hold of account URI
|
# Step 1: get hold of account URI
|
||||||
changed = account.init_account(
|
created, account_data = account.setup_account(allow_creation=False)
|
||||||
[],
|
if created:
|
||||||
allow_creation=False,
|
raise AssertionError('Unwanted account creation')
|
||||||
update_contact=False,
|
if account_data is None:
|
||||||
)
|
raise ModuleFailException(msg='Account does not exist or is deactivated.')
|
||||||
if changed:
|
|
||||||
raise AssertionError('Unwanted account change')
|
|
||||||
# Step 2: sign revokation request with account key
|
# Step 2: sign revokation request with account key
|
||||||
result, info = account.send_signed_request(endpoint, payload)
|
result, info = account.send_signed_request(endpoint, payload)
|
||||||
if info['status'] != 200:
|
if info['status'] != 200:
|
||||||
|
|
|
@ -16,6 +16,22 @@
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: account_not_created
|
register: account_not_created
|
||||||
|
|
||||||
|
- name: Create it now (check mode, diff)
|
||||||
|
acme_account:
|
||||||
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
account_key_src: "{{ output_dir }}/accountkey.pem"
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: https://{{ acme_host }}:14000/dir
|
||||||
|
validate_certs: no
|
||||||
|
state: present
|
||||||
|
allow_creation: yes
|
||||||
|
terms_agreed: yes
|
||||||
|
contact:
|
||||||
|
- mailto:example@example.org
|
||||||
|
check_mode: yes
|
||||||
|
diff: yes
|
||||||
|
register: account_created_check
|
||||||
|
|
||||||
- name: Create it now
|
- name: Create it now
|
||||||
acme_account:
|
acme_account:
|
||||||
select_crypto_backend: "{{ select_crypto_backend }}"
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
@ -30,6 +46,35 @@
|
||||||
- mailto:example@example.org
|
- mailto:example@example.org
|
||||||
register: account_created
|
register: account_created
|
||||||
|
|
||||||
|
- name: Create it now (idempotent)
|
||||||
|
acme_account:
|
||||||
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
account_key_src: "{{ output_dir }}/accountkey.pem"
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: https://{{ acme_host }}:14000/dir
|
||||||
|
validate_certs: no
|
||||||
|
state: present
|
||||||
|
allow_creation: yes
|
||||||
|
terms_agreed: yes
|
||||||
|
contact:
|
||||||
|
- mailto:example@example.org
|
||||||
|
register: account_created_idempotent
|
||||||
|
|
||||||
|
- name: Change email address (check mode, diff)
|
||||||
|
acme_account:
|
||||||
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
account_key_content: "{{ lookup('file', output_dir ~ '/accountkey.pem') }}"
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: https://{{ acme_host }}:14000/dir
|
||||||
|
validate_certs: no
|
||||||
|
state: present
|
||||||
|
# allow_creation: no
|
||||||
|
contact:
|
||||||
|
- mailto:example@example.com
|
||||||
|
check_mode: yes
|
||||||
|
diff: yes
|
||||||
|
register: account_modified_check
|
||||||
|
|
||||||
- name: Change email address
|
- name: Change email address
|
||||||
acme_account:
|
acme_account:
|
||||||
select_crypto_backend: "{{ select_crypto_backend }}"
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
@ -70,6 +115,20 @@
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
register: account_modified_wrong_uri
|
register: account_modified_wrong_uri
|
||||||
|
|
||||||
|
- name: Clear contact email addresses (check mode, diff)
|
||||||
|
acme_account:
|
||||||
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
account_key_src: "{{ output_dir }}/accountkey.pem"
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: https://{{ acme_host }}:14000/dir
|
||||||
|
validate_certs: no
|
||||||
|
state: present
|
||||||
|
# allow_creation: no
|
||||||
|
contact: []
|
||||||
|
check_mode: yes
|
||||||
|
diff: yes
|
||||||
|
register: account_modified_2_check
|
||||||
|
|
||||||
- name: Clear contact email addresses
|
- name: Clear contact email addresses
|
||||||
acme_account:
|
acme_account:
|
||||||
select_crypto_backend: "{{ select_crypto_backend }}"
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
@ -100,6 +159,21 @@
|
||||||
- name: Parse account key (to ease debugging some test failures)
|
- name: Parse account key (to ease debugging some test failures)
|
||||||
command: openssl ec -in {{ output_dir }}/accountkey2.pem -noout -text
|
command: openssl ec -in {{ output_dir }}/accountkey2.pem -noout -text
|
||||||
|
|
||||||
|
- name: Change account key (check mode, diff)
|
||||||
|
acme_account:
|
||||||
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
account_key_src: "{{ output_dir }}/accountkey.pem"
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: https://{{ acme_host }}:14000/dir
|
||||||
|
validate_certs: no
|
||||||
|
new_account_key_src: "{{ output_dir }}/accountkey2.pem"
|
||||||
|
state: changed_key
|
||||||
|
contact:
|
||||||
|
- mailto:example@example.com
|
||||||
|
check_mode: yes
|
||||||
|
diff: yes
|
||||||
|
register: account_change_key_check
|
||||||
|
|
||||||
- name: Change account key
|
- name: Change account key
|
||||||
acme_account:
|
acme_account:
|
||||||
select_crypto_backend: "{{ select_crypto_backend }}"
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
@ -113,6 +187,18 @@
|
||||||
- mailto:example@example.com
|
- mailto:example@example.com
|
||||||
register: account_change_key
|
register: account_change_key
|
||||||
|
|
||||||
|
- name: Deactivate account (check mode, diff)
|
||||||
|
acme_account:
|
||||||
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
account_key_src: "{{ output_dir }}/accountkey2.pem"
|
||||||
|
acme_version: 2
|
||||||
|
acme_directory: https://{{ acme_host }}:14000/dir
|
||||||
|
validate_certs: no
|
||||||
|
state: absent
|
||||||
|
check_mode: yes
|
||||||
|
diff: yes
|
||||||
|
register: account_deactivate_check
|
||||||
|
|
||||||
- name: Deactivate account
|
- name: Deactivate account
|
||||||
acme_account:
|
acme_account:
|
||||||
select_crypto_backend: "{{ select_crypto_backend }}"
|
select_crypto_backend: "{{ select_crypto_backend }}"
|
||||||
|
|
|
@ -3,6 +3,18 @@
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- account_not_created is failed
|
- account_not_created is failed
|
||||||
|
- account_not_created.msg == 'Account does not exist or is deactivated.'
|
||||||
|
|
||||||
|
- name: Validate that account was created in the second step (check mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- account_created_check is changed
|
||||||
|
- account_created_check.account_uri is none
|
||||||
|
- "'diff' in account_created_check"
|
||||||
|
- "account_created_check.diff.before == {}"
|
||||||
|
- "'after' in account_created_check.diff"
|
||||||
|
- account_created_check.diff.after.contact | length == 1
|
||||||
|
- account_created_check.diff.after.contact[0] == 'mailto:example@example.org'
|
||||||
|
|
||||||
- name: Validate that account was created in the second step
|
- name: Validate that account was created in the second step
|
||||||
assert:
|
assert:
|
||||||
|
@ -10,6 +22,23 @@
|
||||||
- account_created is changed
|
- account_created is changed
|
||||||
- account_created.account_uri is not none
|
- account_created.account_uri is not none
|
||||||
|
|
||||||
|
- name: Validate that account was created in the second step (idempotency)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- account_created_idempotent is not changed
|
||||||
|
- account_created_idempotent.account_uri is not none
|
||||||
|
|
||||||
|
- name: Validate that email address was changed (check mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- account_modified_check is changed
|
||||||
|
- account_modified_check.account_uri is not none
|
||||||
|
- "'diff' in account_modified_check"
|
||||||
|
- account_modified_check.diff.before.contact | length == 1
|
||||||
|
- account_modified_check.diff.before.contact[0] == 'mailto:example@example.org'
|
||||||
|
- account_modified_check.diff.after.contact | length == 1
|
||||||
|
- account_modified_check.diff.after.contact[0] == 'mailto:example@example.com'
|
||||||
|
|
||||||
- name: Validate that email address was changed
|
- name: Validate that email address was changed
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
|
@ -27,6 +56,16 @@
|
||||||
that:
|
that:
|
||||||
- account_modified_wrong_uri is failed
|
- account_modified_wrong_uri is failed
|
||||||
|
|
||||||
|
- name: Validate that email address was cleared (check mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- account_modified_2_check is changed
|
||||||
|
- account_modified_2_check.account_uri is not none
|
||||||
|
- "'diff' in account_modified_2_check"
|
||||||
|
- account_modified_2_check.diff.before.contact | length == 1
|
||||||
|
- account_modified_2_check.diff.before.contact[0] == 'mailto:example@example.com'
|
||||||
|
- account_modified_2_check.diff.after.contact | length == 0
|
||||||
|
|
||||||
- name: Validate that email address was cleared
|
- name: Validate that email address was cleared
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
|
@ -39,12 +78,29 @@
|
||||||
- account_modified_2_idempotent is not changed
|
- account_modified_2_idempotent is not changed
|
||||||
- account_modified_2_idempotent.account_uri is not none
|
- account_modified_2_idempotent.account_uri is not none
|
||||||
|
|
||||||
|
- name: Validate that the account key was changed (check mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- account_change_key_check is changed
|
||||||
|
- account_change_key_check.account_uri is not none
|
||||||
|
- "'diff' in account_change_key_check"
|
||||||
|
- account_change_key_check.diff.before.public_account_key != account_change_key_check.diff.after.public_account_key
|
||||||
|
|
||||||
- name: Validate that the account key was changed
|
- name: Validate that the account key was changed
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- account_change_key is changed
|
- account_change_key is changed
|
||||||
- account_change_key.account_uri is not none
|
- account_change_key.account_uri is not none
|
||||||
|
|
||||||
|
- name: Validate that the account was deactivated (check mode)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- account_deactivate_check is changed
|
||||||
|
- account_deactivate_check.account_uri is not none
|
||||||
|
- "'diff' in account_deactivate_check"
|
||||||
|
- "account_deactivate_check.diff.before != {}"
|
||||||
|
- "account_deactivate_check.diff.after == {}"
|
||||||
|
|
||||||
- name: Validate that the account was deactivated
|
- name: Validate that the account was deactivated
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
|
@ -61,8 +117,10 @@
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- account_not_created_2 is failed
|
- account_not_created_2 is failed
|
||||||
|
- account_not_created_2.msg == 'Account does not exist or is deactivated.'
|
||||||
|
|
||||||
- name: Validate that the account is gone (old account key)
|
- name: Validate that the account is gone (old account key)
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- account_not_created_3 is failed
|
- account_not_created_3 is failed
|
||||||
|
- account_not_created_3.msg == 'Account does not exist or is deactivated.'
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
- account_created.account_uri is not none
|
- account_created.account_uri is not none
|
||||||
- "'account' in account_created"
|
- "'account' in account_created"
|
||||||
- "'contact' in account_created.account"
|
- "'contact' in account_created.account"
|
||||||
|
- "'public_account_key' in account_created.account"
|
||||||
- account_created.account.contact | length == 1
|
- account_created.account.contact | length == 1
|
||||||
- "account_created.account.contact[0] == 'mailto:example@example.org'"
|
- "account_created.account.contact[0] == 'mailto:example@example.org'"
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
- account_modified.account_uri is not none
|
- account_modified.account_uri is not none
|
||||||
- "'account' in account_modified"
|
- "'account' in account_modified"
|
||||||
- "'contact' in account_modified.account"
|
- "'contact' in account_modified.account"
|
||||||
|
- "'public_account_key' in account_modified.account"
|
||||||
- account_modified.account.contact | length == 0
|
- account_modified.account.contact | length == 0
|
||||||
|
|
||||||
- name: Validate that account does not exist with wrong account URI
|
- name: Validate that account does not exist with wrong account URI
|
||||||
|
|
Loading…
Reference in a new issue