diff --git a/lib/ansible/module_utils/acme.py b/lib/ansible/module_utils/acme.py index 6860195fac..153bbf5982 100644 --- a/lib/ansible/module_utils/acme.py +++ b/lib/ansible/module_utils/acme.py @@ -514,7 +514,9 @@ class ACMEAccount(object): self.key_content = module.params['account_key_content'] self.directory = ACMEDirectory(module) - self.uri = None + # Grab account URI from module parameters. + # Make sure empty string is treated as None. + self.uri = module.params.get('account_uri') or None self._openssl_bin = module.get_bin_path('openssl', True) @@ -527,6 +529,9 @@ class ACMEAccount(object): "alg": self.key_data['alg'], "jwk": self.jwk, } + if self.uri: + # Make sure self.jws_header is updated + self.set_account_uri(self.uri) def get_keyauthorization(self, token): ''' @@ -709,6 +714,10 @@ class ACMEAccount(object): changed = False if self.uri is not None: new_account = False + if not update_contact: + # Verify that the account key belongs to the URI. + # (If update_contact is True, this will be done below.) + self.get_account_data() else: new_account = self._new_reg( contact, diff --git a/lib/ansible/modules/crypto/acme/acme_account.py b/lib/ansible/modules/crypto/acme/acme_account.py index f6c1b9a3db..5d779ee59f 100644 --- a/lib/ansible/modules/crypto/acme/acme_account.py +++ b/lib/ansible/modules/crypto/acme/acme_account.py @@ -127,6 +127,7 @@ def main(): argument_spec=dict( account_key_src=dict(type='path', aliases=['account_key']), account_key_content=dict(type='str', no_log=True), + account_uri=dict(required=False, type='str'), acme_directory=dict(required=False, default='https://acme-staging.api.letsencrypt.org/directory', type='str'), acme_version=dict(required=False, default=1, choices=[1, 2], type='int'), validate_certs=dict(required=False, default=True, type='bool'), diff --git a/lib/ansible/modules/crypto/acme/acme_certificate.py b/lib/ansible/modules/crypto/acme/acme_certificate.py index 668d8f9505..271acc610f 100644 --- a/lib/ansible/modules/crypto/acme/acme_certificate.py +++ b/lib/ansible/modules/crypto/acme/acme_certificate.py @@ -869,6 +869,7 @@ def main(): argument_spec=dict( account_key_src=dict(type='path', aliases=['account_key']), account_key_content=dict(type='str', no_log=True), + account_uri=dict(required=False, type='str'), modify_account=dict(required=False, type='bool', default=True), acme_directory=dict(required=False, default='https://acme-staging.api.letsencrypt.org/directory', type='str'), acme_version=dict(required=False, default=1, choices=[1, 2], type='int'), diff --git a/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py b/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py index 3ebee6c8e3..524034f0d0 100644 --- a/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py +++ b/lib/ansible/modules/crypto/acme/acme_certificate_revoke.py @@ -95,6 +95,7 @@ def main(): argument_spec=dict( account_key_src=dict(type='path', aliases=['account_key']), account_key_content=dict(type='str', no_log=True), + account_uri=dict(required=False, type='str'), acme_directory=dict(required=False, default='https://acme-staging.api.letsencrypt.org/directory', type='str'), acme_version=dict(required=False, default=1, choices=[1, 2], type='int'), validate_certs=dict(required=False, default=True, type='bool'), diff --git a/lib/ansible/utils/module_docs_fragments/acme.py b/lib/ansible/utils/module_docs_fragments/acme.py index b8dd595c8f..f0e67213b8 100644 --- a/lib/ansible/utils/module_docs_fragments/acme.py +++ b/lib/ansible/utils/module_docs_fragments/acme.py @@ -46,6 +46,12 @@ options: Ansible in the process of moving the module with its argument to the node where it is executed." version_added: "2.5" + account_uri: + description: + - "If specified, assumes that the account URI is as given. If the + account key does not match this account, or an account with this + URI does not exist, the module fails." + version_added: "2.7" acme_version: description: - "The ACME version of the endpoint." diff --git a/test/integration/targets/acme_account/tasks/impl.yml b/test/integration/targets/acme_account/tasks/impl.yml index 04bdca7cc8..50d5a8a5aa 100644 --- a/test/integration/targets/acme_account/tasks/impl.yml +++ b/test/integration/targets/acme_account/tasks/impl.yml @@ -47,6 +47,7 @@ acme_account: select_crypto_backend: "{{ select_crypto_backend }}" account_key_src: "{{ output_dir }}/accountkey.pem" + account_uri: "{{ account_created.account_uri }}" acme_version: 2 acme_directory: https://{{ acme_host }}:14000/dir validate_certs: no @@ -56,6 +57,19 @@ - mailto:example@example.com register: account_modified_idempotent +- name: Cannot access account with wrong URI + acme_account: + select_crypto_backend: "{{ select_crypto_backend }}" + account_key_src: "{{ output_dir }}/accountkey.pem" + account_uri: "{{ account_created.account_uri ~ '12345thisdoesnotexist' }}" + acme_version: 2 + acme_directory: https://{{ acme_host }}:14000/dir + validate_certs: no + state: present + contact: [] + ignore_errors: yes + register: account_modified_wrong_uri + - name: Clear contact email addresses acme_account: select_crypto_backend: "{{ select_crypto_backend }}" diff --git a/test/integration/targets/acme_account/tests/validate.yml b/test/integration/targets/acme_account/tests/validate.yml index d8ee9950a1..e01c496130 100644 --- a/test/integration/targets/acme_account/tests/validate.yml +++ b/test/integration/targets/acme_account/tests/validate.yml @@ -22,6 +22,11 @@ - account_modified_idempotent is not changed - account_modified_idempotent.account_uri is not none +- name: Make sure that with the wrong account URI, the account cannot be changed + assert: + that: + - account_modified_wrong_uri is failed + - name: Validate that email address was cleared assert: that: diff --git a/test/integration/targets/setup_acme/tasks/obtain-cert.yml b/test/integration/targets/setup_acme/tasks/obtain-cert.yml index 3df3ce5c03..268285fd9d 100644 --- a/test/integration/targets/setup_acme/tasks/obtain-cert.yml +++ b/test/integration/targets/setup_acme/tasks/obtain-cert.yml @@ -103,6 +103,7 @@ acme_directory: https://{{ acme_host }}:14000/dir validate_certs: no account_key: "{{ output_dir }}/{{ account_key }}.pem" + account_uri: "{{ challenge_data.account_uri }}" modify_account: "{{ modify_account }}" csr: "{{ output_dir }}/{{ certificate_name }}.csr" dest: "{{ output_dir }}/{{ certificate_name }}.pem" @@ -123,6 +124,7 @@ acme_directory: https://{{ acme_host }}:14000/dir validate_certs: no account_key_content: "{{ account_key_content }}" + account_uri: "{{ challenge_data.account_uri }}" modify_account: "{{ modify_account }}" csr: "{{ output_dir }}/{{ certificate_name }}.csr" dest: "{{ output_dir }}/{{ certificate_name }}.pem"