From 0eac6ad705096e14136badb164888042bb9b1e86 Mon Sep 17 00:00:00 2001 From: Sven Liebert Date: Wed, 20 Mar 2024 15:34:39 +0100 Subject: [PATCH] Add domain-offensive as dns-01 challenge (#122) * add domain-offensive as dns-01 challenge * Fix ansible lint for dns01: domain-offensive * Update docs/dns-challenge/domain-offensive.md --------- Co-authored-by: Sebastian Gumprich --- README.md | 6 ++ docs/dns-challenge/domain-offensive.md | 57 +++++++++++++++++++ docs/role-acme.md | 1 + .../challenge/dns-01/domain-offensive.yml | 53 +++++++++++++++++ .../dns-challenge-domain-offensive.yml | 32 +++++++++++ 5 files changed, 149 insertions(+) create mode 100644 docs/dns-challenge/domain-offensive.md create mode 100644 roles/acme/tasks/challenge/dns-01/domain-offensive.yml create mode 100644 tests/integration/targets/acme_letsencrypt/dns-challenge-domain-offensive.yml diff --git a/README.md b/README.md index c929469..d0888e9 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,12 @@ Here we list ways to manually test the dns-providers if you have access: ansible-playbook tests/integration/targets/acme_letsencrypt/dns-challenge-hetzner.yml -e acme_hetzner_auth_token=YOUR_AUTH_TOKEN -e hetzner_domain_name="example.com" -e hetzner_zone="example.com" ``` +* Domain-Offensive + +``` +ansible-playbook tests/integration/targets/acme_letsencrypt/dns-challenge-domain-offensive.yml -e acme_dns_password=YOUR_DO_AUTH_TOKEN -e domain_offensive_zone="example.com" -e domain_offensive_domain_name="example.com" +``` + ## License GPLv3 diff --git a/docs/dns-challenge/domain-offensive.md b/docs/dns-challenge/domain-offensive.md new file mode 100644 index 0000000..56edb53 --- /dev/null +++ b/docs/dns-challenge/domain-offensive.md @@ -0,0 +1,57 @@ +# Variables for Domain Offensive dns-challenge + +| Variable | Required | Default | Description +|-------------------------|----------|---------|------------ +| acme_dns_password | yes | | Let's Encrypt API-Token, you can get here: [do.de](https://my.do.de/settings/domains/general) + +## Usage + +### wildcard certificate + +```yaml +- name: create the certificate for *.example.com + hosts: localhost + collections: + - telekom_mms.acme + roles: + - acme + vars: + acme_domain: + certificate_name: "wildcard.example.com" + zone: "example.com" + email_address: "ssl-admin@example.com" + subject_alt_name: + - "*.example.com" + acme_challenge_provider: domain-offensive + acme_use_live_directory: false + acme_account_email: "ssl-admin@example.com" + acme_dns_password: !vault | + $ANSIBLE_VAULT;1.1;AES256 + ... +``` + +### SAN certificate + +```yaml +- name: create the certificate for example.com + hosts: localhost + collections: + - telekom_mms.acme + roles: + - acme + vars: + acme_domain: + certificate_name: "wildcard.example.com" + zone: "example.com" + email_address: "ssl-admin@example.com" + subject_alt_name: + - "example.com" + - "domain1.example.com" + - "domain2.example.com" + acme_challenge_provider: domain-offensive + acme_use_live_directory: false + acme_account_email: "ssl-admin@example.com" + acme_dns_password: !vault | + $ANSIBLE_VAULT;1.1;AES256 + ... +``` diff --git a/docs/role-acme.md b/docs/role-acme.md index 18977d2..f8ac0db 100644 --- a/docs/role-acme.md +++ b/docs/role-acme.md @@ -14,6 +14,7 @@ Feel free to contribute more DNS or HTTP APIs :) * DNS-01 * [AutoDNS](/docs/dns-challenge/autodns.md) * [Azure](/docs/dns-challenge/azure.md) + * [Domain Offensive](/docs/dns-challenge/domain-offensive.md) * [hetzner](/docs/dns-challenge/hetzner.md) * [openstack](/docs/dns-challenge/openstack.md) * [pebble](/docs/dns-challenge/pebble.md) diff --git a/roles/acme/tasks/challenge/dns-01/domain-offensive.yml b/roles/acme/tasks/challenge/dns-01/domain-offensive.yml new file mode 100644 index 0000000..7362ccb --- /dev/null +++ b/roles/acme/tasks/challenge/dns-01/domain-offensive.yml @@ -0,0 +1,53 @@ +--- +### include/role 3 - validate challenge +- name: Validate challenge only if it is created or changed # noqa no-handler + when: acme_challenge is changed + block: + - name: Add a new TXT record to the SAN domains + ansible.builtin.uri: + url: "https://my.do.de/api/letsencrypt" + body_format: form-multipart + body: + token: "{{ acme_dns_password }}" + domain: "_acme-challenge.{{ item | replace('*.', '') }}" + value: "{{ acme_challenge['challenge_data'][item]['dns-01']['resource_value'] }}" + ttl: "120" + method: POST + loop: "{{ acme_domain.subject_alt_name }}" + when: + - acme_domain.subject_alt_name is defined + # only runs if the challenge is run the first time, because then there is challenge_data + - acme_challenge['challenge_data'][item] is defined + + - name: Let the challenge be validated and retrieve the cert and intermediate certificate + community.crypto.acme_certificate: + account_key_src: "{{ acme_account_key_path }}" + account_email: "{{ acme_account_email }}" + csr: "{{ acme_csr_path }}" + cert: "{{ acme_cert_path }}" + fullchain: "{{ acme_fullchain_path }}" + chain: "{{ acme_intermediate_path }}" + challenge: dns-01 + force: "{{ acme_force_renewal | default(false) }}" + acme_directory: "{{ acme_directory }}" + acme_version: 2 + terms_agreed: true + remaining_days: "{{ acme_remaining_days }}" + data: "{{ acme_challenge }}" + + always: + - name: Remove created SAN TXT records to keep DNS zone clean + ansible.builtin.uri: + url: "https://my.do.de/api/letsencrypt" + body_format: form-multipart + body: + token: "{{ acme_dns_password }}" + domain: "_acme-challenge.{{ item | replace('*.', '') }}" + value: "{{ acme_challenge['challenge_data'][item]['dns-01']['resource_value'] }}" + action: delete + method: POST + loop: "{{ acme_domain.subject_alt_name }}" + when: + - acme_domain.subject_alt_name is defined + # only runs if the challenge is run the first time, because then there is challenge_data + - acme_challenge['challenge_data'][item] is defined diff --git a/tests/integration/targets/acme_letsencrypt/dns-challenge-domain-offensive.yml b/tests/integration/targets/acme_letsencrypt/dns-challenge-domain-offensive.yml new file mode 100644 index 0000000..510446c --- /dev/null +++ b/tests/integration/targets/acme_letsencrypt/dns-challenge-domain-offensive.yml @@ -0,0 +1,32 @@ +--- +- name: Create a test certificate for domain-offensive + hosts: localhost + roles: + - telekom_mms.acme.acme + vars: + acme_challenge_provider: domain-offensive + acme_use_live_directory: false + acme_account_email: ssl-admin@example.de + acme_force_renewal: true + acme_domain: + email_address: ssl-admin@example.de + certificate_name: "{{ domain_offensive_zone }}" + zone: "{{ domain_offensive_zone }}" + subject_alt_name: + - "{{ domain_offensive_domain_name }}" + post_tasks: + - name: Validate certs + community.crypto.x509_certificate_info: + path: "{{ acme_cert_path }}" + register: result + + - name: Print the certificate + ansible.builtin.debug: + msg: "{{ result }}" + + - name: Check if the certificate has correct data + ansible.builtin.assert: + that: + - result.subject.commonName == "{{ acme_domain.certificate_name }}" + - "'DNS:{{ acme_domain.certificate_name }}' in result.subject_alt_name" + - "'(STAGING) Artificial Apricot R3' in result.issuer.commonName"