acme_certificate and acme_certificate_create_order: add order_creation_error_strategy and order_creation_max_retries options (#842)

* Provide error information.

* Add helper function for order creation retrying.

* Improve existing documentation.

* Document 'replaces' return value.

* Add order_creation_error_strategy and order_creation_max_retries options.

* Add changelog fragment.

* Fix authz deactivation for finalizing step.

* Fix profile handling on order creation.

* Improve existing tests.

* Add ARI and profile tests.

* Warn when 'replaces' is removed when retrying to create an order.
This commit is contained in:
Felix Fontein
2025-01-18 10:51:10 +01:00
committed by GitHub
parent b9fa5b5193
commit 214794d056
17 changed files with 632 additions and 56 deletions

View File

@@ -3,23 +3,23 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Generate random domain name
- name: "({{ select_crypto_backend }}) Generate random domain name"
set_fact:
domain_name: "host{{ '%0x' % ((2**32) | random) }}.example.com"
- name: Generate account key
- name: "({{ select_crypto_backend }}) Generate account key"
openssl_privatekey:
path: "{{ remote_tmp_dir }}/accountkey.pem"
type: ECC
curve: secp256r1
force: true
- name: Parse account keys (to ease debugging some test failures)
- name: "({{ select_crypto_backend }}) Parse account keys (to ease debugging some test failures)"
openssl_privatekey_info:
path: "{{ remote_tmp_dir }}/accountkey.pem"
return_private_key_data: true
- name: Create ACME account
- name: "({{ select_crypto_backend }}) Create ACME account"
acme_account:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -30,14 +30,14 @@
state: present
register: account
- name: Generate certificate key
- name: "({{ select_crypto_backend }}) Generate certificate key"
openssl_privatekey:
path: "{{ remote_tmp_dir }}/cert.key"
type: ECC
curve: secp256r1
force: true
- name: Generate certificate CSR
- name: "({{ select_crypto_backend }}) Generate certificate CSR"
openssl_csr:
path: "{{ remote_tmp_dir }}/cert.csr"
privatekey_path: "{{ remote_tmp_dir }}/cert.key"
@@ -46,7 +46,7 @@
return_content: true
register: csr
- name: Create certificate order
- name: "({{ select_crypto_backend }}) Create certificate order"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -56,11 +56,11 @@
csr: "{{ remote_tmp_dir }}/cert.csr"
register: order
- name: Show order information
- name: "({{ select_crypto_backend }}) Show order information"
debug:
var: order
- name: Check order
- name: "({{ select_crypto_backend }}) Check order"
assert:
that:
- order is changed
@@ -80,7 +80,7 @@
- order.challenge_data_dns['_acme-challenge.' ~ domain_name] | length == 1
- order.account_uri == account.account_uri
- name: Get order information
- name: "({{ select_crypto_backend }}) Get order information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -90,11 +90,11 @@
order_uri: "{{ order.order_uri }}"
register: order_info_1
- name: Show order information
- name: "({{ select_crypto_backend }}) Show order information"
debug:
var: order_info_1
- name: Check order information
- name: "({{ select_crypto_backend }}) Check order information"
assert:
that:
- order_info_1 is not changed
@@ -115,10 +115,11 @@
- order_info_1.order.authorizations[0] == order_info_1.authorizations_by_identifier['dns:' ~ domain_name].uri
- "'certificate' not in order_info_1.order"
- order_info_1.order.status == 'pending'
- order_info_1.order.replaces is not defined
- order_info_1.order_uri == order.order_uri
- order_info_1.account_uri == account.account_uri
- name: Create HTTP challenges
- name: "({{ select_crypto_backend }}) Create HTTP challenges"
uri:
url: "http://{{ acme_host }}:5000/http/{{ item.identifier }}/{{ item.challenges['http-01'].resource[('.well-known/acme-challenge/'|length):] }}"
method: PUT
@@ -129,7 +130,7 @@
loop: "{{ order.challenge_data }}"
when: "'http-01' in item.challenges"
- name: Let the challenge be validated
- name: "({{ select_crypto_backend }}) Let the challenge be validated"
community.crypto.acme_certificate_order_validate:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -140,18 +141,18 @@
challenge: http-01
register: validate_1
- name: Check validation result
- name: "({{ select_crypto_backend }}) Check validation result"
assert:
that:
- validate_1 is changed
- validate_1.account_uri == account.account_uri
- name: Wait until we know that the challenges have been validated for ansible-core <= 2.11
- name: "({{ select_crypto_backend }}) Wait until we know that the challenges have been validated for ansible-core <= 2.11"
pause:
seconds: 5
when: ansible_version.full is version('2.12', '<')
- name: Get order information
- name: "({{ select_crypto_backend }}) Get order information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -161,11 +162,11 @@
order_uri: "{{ order.order_uri }}"
register: order_info_2
- name: Show order information
- name: "({{ select_crypto_backend }}) Show order information"
debug:
var: order_info_2
- name: Check order information
- name: "({{ select_crypto_backend }}) Check order information"
assert:
that:
- order_info_2 is not changed
@@ -186,10 +187,11 @@
- order_info_2.order.authorizations[0] == order_info_2.authorizations_by_identifier['dns:' ~ domain_name].uri
- "'certificate' not in order_info_2.order"
- order_info_2.order.status in ['pending', 'ready']
- order_info_2.order.replaces is not defined
- order_info_2.order_uri == order.order_uri
- order_info_2.account_uri == account.account_uri
- name: Let the challenge be validated (idempotent)
- name: "({{ select_crypto_backend }}) Let the challenge be validated (idempotent)"
community.crypto.acme_certificate_order_validate:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -200,13 +202,13 @@
challenge: http-01
register: validate_2
- name: Check validation result
- name: "({{ select_crypto_backend }}) Check validation result"
assert:
that:
- validate_2 is not changed
- validate_2.account_uri == account.account_uri
- name: Retrieve the cert and intermediate certificate
- name: "({{ select_crypto_backend }}) Retrieve the cert and intermediate certificate"
community.crypto.acme_certificate_order_finalize:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -214,6 +216,7 @@
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ order.order_uri }}"
deactivate_authzs: never
retrieve_all_alternates: true
csr: "{{ remote_tmp_dir }}/cert.csr"
cert_dest: "{{ remote_tmp_dir }}/cert.pem"
@@ -221,7 +224,7 @@
fullchain_dest: "{{ remote_tmp_dir }}/cert-fullchain.pem"
register: finalize_1
- name: Check finalization result
- name: "({{ select_crypto_backend }}) Check finalization result"
assert:
that:
- finalize_1 is changed
@@ -232,7 +235,7 @@
- finalize_1.selected_chain.chain.startswith('-----BEGIN CERTIFICATE-----\nMII')
- finalize_1.selected_chain.full_chain == finalize_1.selected_chain.cert + finalize_1.selected_chain.chain
- name: Read files from disk
- name: "({{ select_crypto_backend }}) Read files from disk"
slurp:
src: "{{ remote_tmp_dir }}/{{ item }}.pem"
loop:
@@ -241,14 +244,14 @@
- cert-fullchain
register: slurp
- name: Compare finalization result with files on disk
- name: "({{ select_crypto_backend }}) Compare finalization result with files on disk"
assert:
that:
- finalize_1.selected_chain.cert == slurp.results[0].content | b64decode
- finalize_1.selected_chain.chain == slurp.results[1].content | b64decode
- finalize_1.selected_chain.full_chain == slurp.results[2].content | b64decode
- name: Get order information
- name: "({{ select_crypto_backend }}) Get order information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -258,11 +261,11 @@
order_uri: "{{ order.order_uri }}"
register: order_info_3
- name: Show order information
- name: "({{ select_crypto_backend }}) Show order information"
debug:
var: order_info_3
- name: Check order information
- name: "({{ select_crypto_backend }}) Check order information"
assert:
that:
- order_info_3 is not changed
@@ -284,7 +287,7 @@
- order_info_3.order_uri == order.order_uri
- order_info_3.account_uri == account.account_uri
- name: Retrieve the cert and intermediate certificate (idempotent)
- name: "({{ select_crypto_backend }}) Retrieve the cert and intermediate certificate (idempotent, but deactivate authzs)"
community.crypto.acme_certificate_order_finalize:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -300,7 +303,7 @@
fullchain_dest: "{{ remote_tmp_dir }}/cert-fullchain.pem"
register: finalize_2
- name: Check finalization result
- name: "({{ select_crypto_backend }}) Check finalization result"
assert:
that:
- finalize_2 is not changed
@@ -312,7 +315,7 @@
- finalize_2.selected_chain.full_chain == finalize_2.selected_chain.cert + finalize_2.selected_chain.chain
- finalize_2.selected_chain == finalize_1.selected_chain
- name: Get order information
- name: "({{ select_crypto_backend }}) Get order information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
@@ -322,11 +325,11 @@
order_uri: "{{ order.order_uri }}"
register: order_info_4
- name: Show order information
- name: "({{ select_crypto_backend }}) Show order information"
debug:
var: order_info_4
- name: Check order information
- name: "({{ select_crypto_backend }}) Check order information"
assert:
that:
- order_info_4 is not changed
@@ -347,3 +350,385 @@
- order_info_4.order.status == 'deactivated'
- order_info_4.order_uri == order.order_uri
- order_info_4.account_uri == account.account_uri
# Test ARI support
- when: acme_supports_ari
block:
- name: "({{ select_crypto_backend }}) Get certificate renewal information"
acme_certificate_renewal_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
# account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
certificate_path: "{{ remote_tmp_dir }}/cert.pem"
register: cert_info
- name: "({{ select_crypto_backend }}) Verify information"
assert:
that:
- cert_info.supports_ari == true
- cert_info.should_renew == false
- cert_info.cert_id is string
- name: "({{ select_crypto_backend }}) Create replacement order 1"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
replaces_cert_id: "{{ cert_info.cert_id }}"
order_creation_error_strategy: fail
register: replacement_order_1
- name: "({{ select_crypto_backend }}) Get replacement order 1 information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_1.order_uri }}"
register: order_info_5
- name: "({{ select_crypto_backend }}) Check replacement order 1"
assert:
that:
- replacement_order_1 is changed
- replacement_order_1.order_uri.startswith('https://' ~ acme_host ~ ':14000/')
- replacement_order_1.challenge_data | length == 1
- replacement_order_1.challenge_data[0].identifier_type == 'dns'
- replacement_order_1.challenge_data[0].identifier == domain_name
- replacement_order_1.challenge_data[0].challenges | length >= 2
- "'http-01' in replacement_order_1.challenge_data[0].challenges"
- "'dns-01' in replacement_order_1.challenge_data[0].challenges"
- replacement_order_1.challenge_data[0].challenges['http-01'].resource.startswith('.well-known/acme-challenge/')
- replacement_order_1.challenge_data[0].challenges['http-01'].resource_value is string
- replacement_order_1.challenge_data[0].challenges['dns-01'].record == '_acme-challenge.' ~ domain_name
- replacement_order_1.challenge_data[0].challenges['dns-01'].resource == '_acme-challenge'
- replacement_order_1.challenge_data[0].challenges['dns-01'].resource_value is string
- replacement_order_1.challenge_data_dns | length == 1
- replacement_order_1.challenge_data_dns['_acme-challenge.' ~ domain_name] | length == 1
- replacement_order_1.account_uri == account.account_uri
- replacement_order_1.order_uri not in [order.order_uri]
- name: "({{ select_crypto_backend }}) Check replacement order 1 information"
assert:
that:
- order_info_5 is not changed
- order_info_5.authorizations_by_identifier | length == 1
- order_info_5.authorizations_by_identifier['dns:' ~ domain_name].identifier.type == 'dns'
- order_info_5.authorizations_by_identifier['dns:' ~ domain_name].identifier.value == domain_name
- order_info_5.authorizations_by_identifier['dns:' ~ domain_name].status == 'pending'
- (order_info_5.authorizations_by_identifier['dns:' ~ domain_name].challenges | selectattr('type', 'equalto', 'http-01') | first).status == 'pending'
- (order_info_5.authorizations_by_identifier['dns:' ~ domain_name].challenges | selectattr('type', 'equalto', 'dns-01') | first).status == 'pending'
- order_info_5.authorizations_by_status['deactivated'] | length == 0
- order_info_5.authorizations_by_status['expired'] | length == 0
- order_info_5.authorizations_by_status['invalid'] | length == 0
- order_info_5.authorizations_by_status['pending'] | length == 1
- order_info_5.authorizations_by_status['pending'][0] == 'dns:' ~ domain_name
- order_info_5.authorizations_by_status['revoked'] | length == 0
- order_info_5.authorizations_by_status['valid'] | length == 0
- order_info_5.order.authorizations | length == 1
- order_info_5.order.authorizations[0] == order_info_5.authorizations_by_identifier['dns:' ~ domain_name].uri
- "'certificate' not in order_info_5.order"
- order_info_5.order.status == 'pending'
- order_info_5.order.replaces == cert_info.cert_id
- order_info_5.order_uri == replacement_order_1.order_uri
- order_info_5.account_uri == account.account_uri
# Right now Pebble does not reject duplicate replacement orders...
- when: false # TODO get Pebble improved
block:
- name: "({{ select_crypto_backend }}) Create replacement order 2 (should fail)"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
replaces_cert_id: "{{ cert_info.cert_id }}"
order_creation_error_strategy: fail
register: replacement_order_2
ignore_errors: true
- name: "({{ select_crypto_backend }}) Check replacement order 2"
assert:
that:
- replacement_order_2 is failed
- >-
replacement_order_2.msg.startswith(
'Failed to start new order for '
~ acme_directory_url
~ '/order-plz with status 409 Conflict. Error urn:ietf:params:acme:error:malformed:'
)
- name: "({{ select_crypto_backend }}) Create replacement order 3 with error handling"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
replaces_cert_id: "{{ cert_info.cert_id }}"
order_creation_error_strategy: retry_without_replaces_cert_id
register: replacement_order_3
- name: "({{ select_crypto_backend }}) Get replacement order 3 information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_3.order_uri }}"
register: order_info_6
- name: "({{ select_crypto_backend }}) Check replacement order 3"
assert:
that:
- replacement_order_3 is changed
- replacement_order_3.order_uri.startswith('https://' ~ acme_host ~ ':14000/')
- replacement_order_3.challenge_data | length == 1
- replacement_order_3.challenge_data[0].identifier_type == 'dns'
- replacement_order_3.challenge_data[0].identifier == domain_name
- replacement_order_3.challenge_data[0].challenges | length >= 2
- "'http-01' in replacement_order_3.challenge_data[0].challenges"
- "'dns-01' in replacement_order_3.challenge_data[0].challenges"
- replacement_order_3.challenge_data[0].challenges['http-01'].resource.startswith('.well-known/acme-challenge/')
- replacement_order_3.challenge_data[0].challenges['http-01'].resource_value is string
- replacement_order_3.challenge_data[0].challenges['dns-01'].record == '_acme-challenge.' ~ domain_name
- replacement_order_3.challenge_data[0].challenges['dns-01'].resource == '_acme-challenge'
- replacement_order_3.challenge_data[0].challenges['dns-01'].resource_value is string
- replacement_order_3.challenge_data_dns | length == 1
- replacement_order_3.challenge_data_dns['_acme-challenge.' ~ domain_name] | length == 1
- replacement_order_3.account_uri == account.account_uri
- replacement_order_3.order_uri not in [order.order_uri, replacement_order_1.order_uri]
- >-
'Stop passing `replaces` due to error 409 urn:ietf:params:acme:error:malformed when creating ACME order' in replacement_order_3.warnings
- name: "({{ select_crypto_backend }}) Check replacement order 3 information"
assert:
that:
- order_info_6 is not changed
- order_info_6.authorizations_by_identifier | length == 1
- order_info_6.authorizations_by_identifier['dns:' ~ domain_name].identifier.type == 'dns'
- order_info_6.authorizations_by_identifier['dns:' ~ domain_name].identifier.value == domain_name
- order_info_6.authorizations_by_identifier['dns:' ~ domain_name].status == 'pending'
- (order_info_6.authorizations_by_identifier['dns:' ~ domain_name].challenges | selectattr('type', 'equalto', 'http-01') | first).status == 'pending'
- (order_info_6.authorizations_by_identifier['dns:' ~ domain_name].challenges | selectattr('type', 'equalto', 'dns-01') | first).status == 'pending'
- order_info_6.authorizations_by_status['deactivated'] | length == 0
- order_info_6.authorizations_by_status['expired'] | length == 0
- order_info_6.authorizations_by_status['invalid'] | length == 0
- order_info_6.authorizations_by_status['pending'] | length == 1
- order_info_6.authorizations_by_status['pending'][0] == 'dns:' ~ domain_name
- order_info_6.authorizations_by_status['revoked'] | length == 0
- order_info_6.authorizations_by_status['valid'] | length == 0
- order_info_6.order.authorizations | length == 1
- order_info_6.order.authorizations[0] == order_info_6.authorizations_by_identifier['dns:' ~ domain_name].uri
- "'certificate' not in order_info_6.order"
- order_info_6.order.status == 'pending'
- order_info_6.order.replaces is not defined
- order_info_6.order_uri == replacement_order_3.order_uri
- order_info_6.account_uri == account.account_uri
- name: "({{ select_crypto_backend }}) Deactivate authzs for replacement order 3"
acme_certificate_deactivate_authz:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_3.order_uri }}"
# Complete replacement order 1
- name: "({{ select_crypto_backend }}) Create HTTP challenges (replacement order 1)"
uri:
url: "http://{{ acme_host }}:5000/http/{{ item.identifier }}/{{ item.challenges['http-01'].resource[('.well-known/acme-challenge/'|length):] }}"
method: PUT
body_format: raw
body: "{{ item.challenges['http-01'].resource_value }}"
headers:
content-type: "application/octet-stream"
loop: "{{ replacement_order_1.challenge_data }}"
when: "'http-01' in item.challenges"
- name: "({{ select_crypto_backend }}) Let the challenge be validated (replacement order 1)"
community.crypto.acme_certificate_order_validate:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_1.order_uri }}"
challenge: http-01
- name: "({{ select_crypto_backend }}) Retrieve the cert and intermediate certificate (replacement order 1)"
community.crypto.acme_certificate_order_finalize:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_1.order_uri }}"
deactivate_authzs: on_success
retrieve_all_alternates: true
csr: "{{ remote_tmp_dir }}/cert.csr"
cert_dest: "{{ remote_tmp_dir }}/cert-repl.pem"
chain_dest: "{{ remote_tmp_dir }}/cert-repl-chain.pem"
fullchain_dest: "{{ remote_tmp_dir }}/cert-repl-fullchain.pem"
# Pebble *does* check against *completed* replacement orders
- when: true
block:
- name: "({{ select_crypto_backend }}) Create replacement order 4 (should fail)"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
replaces_cert_id: "{{ cert_info.cert_id }}"
order_creation_error_strategy: fail
register: replacement_order_4
ignore_errors: true
- name: "({{ select_crypto_backend }}) Check replacement order 4"
assert:
that:
- replacement_order_4 is failed
- replacement_order_4.msg.startswith('Failed to start new order for https://' ~ acme_host)
- >-
' with status 409 Conflict. Error urn:ietf:params:acme:error:malformed: ' in replacement_order_4.msg
- name: "({{ select_crypto_backend }}) Create replacement order 5 with error handling"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
replaces_cert_id: "{{ cert_info.cert_id }}"
order_creation_error_strategy: retry_without_replaces_cert_id
register: replacement_order_5
- name: "({{ select_crypto_backend }}) Get replacement order 5 information"
acme_certificate_order_info:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_5.order_uri }}"
register: order_info_7
- name: "({{ select_crypto_backend }}) Check replacement order 5"
assert:
that:
- replacement_order_5 is changed
- replacement_order_5.order_uri.startswith('https://' ~ acme_host ~ ':14000/')
- replacement_order_5.challenge_data | length == 1
- replacement_order_5.challenge_data[0].identifier_type == 'dns'
- replacement_order_5.challenge_data[0].identifier == domain_name
- replacement_order_5.challenge_data[0].challenges | length >= 2
- "'http-01' in replacement_order_5.challenge_data[0].challenges"
- "'dns-01' in replacement_order_5.challenge_data[0].challenges"
- replacement_order_5.challenge_data[0].challenges['http-01'].resource.startswith('.well-known/acme-challenge/')
- replacement_order_5.challenge_data[0].challenges['http-01'].resource_value is string
- replacement_order_5.challenge_data[0].challenges['dns-01'].record == '_acme-challenge.' ~ domain_name
- replacement_order_5.challenge_data[0].challenges['dns-01'].resource == '_acme-challenge'
- replacement_order_5.challenge_data[0].challenges['dns-01'].resource_value is string
- replacement_order_5.challenge_data_dns | length == 1
- replacement_order_5.challenge_data_dns['_acme-challenge.' ~ domain_name] | length == 1
- replacement_order_5.account_uri == account.account_uri
- replacement_order_5.order_uri not in [order.order_uri, replacement_order_1.order_uri]
- >-
'Stop passing `replaces` due to error 409 urn:ietf:params:acme:error:malformed when creating ACME order' in replacement_order_5.warnings
- name: "({{ select_crypto_backend }}) Check replacement order 5 information"
assert:
that:
- order_info_7 is not changed
- order_info_7.authorizations_by_identifier | length == 1
- order_info_7.authorizations_by_identifier['dns:' ~ domain_name].identifier.type == 'dns'
- order_info_7.authorizations_by_identifier['dns:' ~ domain_name].identifier.value == domain_name
- order_info_7.authorizations_by_identifier['dns:' ~ domain_name].status == 'pending'
- (order_info_7.authorizations_by_identifier['dns:' ~ domain_name].challenges | selectattr('type', 'equalto', 'http-01') | first).status == 'pending'
- (order_info_7.authorizations_by_identifier['dns:' ~ domain_name].challenges | selectattr('type', 'equalto', 'dns-01') | first).status == 'pending'
- order_info_7.authorizations_by_status['deactivated'] | length == 0
- order_info_7.authorizations_by_status['expired'] | length == 0
- order_info_7.authorizations_by_status['invalid'] | length == 0
- order_info_7.authorizations_by_status['pending'] | length == 1
- order_info_7.authorizations_by_status['pending'][0] == 'dns:' ~ domain_name
- order_info_7.authorizations_by_status['revoked'] | length == 0
- order_info_7.authorizations_by_status['valid'] | length == 0
- order_info_7.order.authorizations | length == 1
- order_info_7.order.authorizations[0] == order_info_7.authorizations_by_identifier['dns:' ~ domain_name].uri
- "'certificate' not in order_info_7.order"
- order_info_7.order.status == 'pending'
- order_info_7.order.replaces is not defined
- order_info_7.order_uri == replacement_order_5.order_uri
- order_info_7.account_uri == account.account_uri
- name: "({{ select_crypto_backend }}) Deactivate authzs for replacement order 5"
acme_certificate_deactivate_authz:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
order_uri: "{{ replacement_order_5.order_uri }}"
# Test invalid profile
- when: acme_supports_profiles
block:
- name: "({{ select_crypto_backend }}) Create order with invalid profile (should fail)"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
profile: does-not-exist
order_creation_error_strategy: fail
register: invalid_profile_order
ignore_errors: true
- name: "({{ select_crypto_backend }}) Check invalid profile order"
assert:
that:
- invalid_profile_order is failed
- invalid_profile_order.msg == "The ACME CA does not support selected profile 'does-not-exist'."
# Test profile when server does not support it
- when: not acme_supports_profiles
block:
- name: "({{ select_crypto_backend }}) Create order with profile when server does not support it (should fail)"
acme_certificate_order_create:
acme_directory: "{{ acme_directory_url }}"
acme_version: 2
validate_certs: false
account_key_src: "{{ remote_tmp_dir }}/accountkey.pem"
select_crypto_backend: "{{ select_crypto_backend }}"
csr: "{{ remote_tmp_dir }}/cert.csr"
profile: default
register: profile_without_server_support
ignore_errors: true
- name: "({{ select_crypto_backend }}) Check profile without server support order"
assert:
that:
- profile_without_server_support is failed
- profile_without_server_support.msg == 'The ACME CA does not support profiles. Please omit the "profile" option.'