-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding nsupdate DNS challenge (#169)
* Adding nsupdate DNS challenge * Update after feedback * Update after feedback * Fix linting and some cosmetics Signed-off-by: Martin Schurz <[email protected]> * Fix linting and some cosmetics Signed-off-by: Martin Schurz <[email protected]> * Fix typo Signed-off-by: Martin Schurz <[email protected]> --------- Signed-off-by: Martin Schurz <[email protected]> Co-authored-by: Michael Kluge <[email protected]> Co-authored-by: Martin Schurz <[email protected]>
- Loading branch information
1 parent
0c6233a
commit ae971d0
Showing
5 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
--- | ||
exclude_paths: | ||
- .cache/ # implicit unless exclude_paths is defined in config | ||
- .ansible/ # somehow someone decided that the cache directory should be renamed | ||
- .github/ | ||
skip_list: | ||
- meta-runtime[unsupported-version] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# Variables for nsupdate dns-challenge | ||
|
||
| Variable | Required | Default | Description | | ||
|-----------------------------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------------------| | ||
| | | | | | ||
| acme_nsupdate_server | yes | | The IPv4/IPv6 address of the DNS server where nsupdate manages the _acme-challenge TXT records. (can also be a DNS name, see below) | | ||
| acme_nsupdate_dns_key: | yes | | The acme_nsupdate_dns_key dictionary mirrors the settings of a bind DNS keyfile. | | ||
| acme_nsupdate_dns_key: name: | no | nsupdate_key | Name of the | | ||
| acme_nsupdate_dns_key: algorithm: | no | hmac-sha512 | Hash algo of the key (i.e. hmac-sha512, hmac-sha256) | | ||
| acme_nsupdate_dns_key: secret: | yes | | The key | | ||
| acme_nsupdate_replication_delay | no | 2 | Wait time after the TXT record is issued, before the certificate is fetched via ACME | | ||
|
||
## Usage | ||
|
||
### wildcard certificate | ||
|
||
```yaml | ||
- name: create the certificate for *.example.org | ||
hosts: localhost | ||
collections: | ||
- telekom_mms.acme | ||
roles: | ||
- acme | ||
vars: | ||
acme_domain: | ||
certificate_name: "wildcard.example.org" | ||
zone: "example.org" | ||
email_address: "[email protected]" | ||
subject_alt_name: | ||
- "*.example.org" | ||
acme_challenge_provider: nsupdate | ||
acme_use_live_directory: false | ||
acme_account_email: "[email protected]" | ||
acme_nsupdate_server: "{{ lookup('community.general.dig', 'primary.nsforexample.org', qtype='A') }}" | ||
acme_nsupdate_dns_key: | ||
name: 'nsupdate_key' | ||
algorithm: hmac-sha512 | ||
secret: "" | ||
``` | ||
### SAN certificate | ||
```yaml | ||
- name: create the certificate for example.org | ||
hosts: localhost | ||
collections: | ||
- telekom_mms.acme | ||
roles: | ||
- acme | ||
vars: | ||
acme_domain: | ||
certificate_name: "test.example.org" | ||
zone: "example.org" | ||
email_address: "[email protected]" | ||
subject_alt_name: | ||
- "test.example.org" | ||
- "domain1.example.org" | ||
- "domain2.example.org" | ||
acme_challenge_provider: nsupdate | ||
acme_use_live_directory: false | ||
acme_account_email: "[email protected]" | ||
acme_nsupdate_server: "{{ lookup('community.general.dig', 'primary.nsforexample.org', qtype='A') }}" | ||
acme_nsupdate_dns_key: | ||
name: 'nsupdate_key' | ||
algorithm: hmac-sha512 | ||
secret: "" | ||
``` | ||
### acme_nsupdate_server | ||
The acme_nsupdate_server MUST be a IPv4/IPv6 address (limitation of the nsupdate ansible module). To work with a DNS | ||
name, you can use the dig lookup: | ||
``` | ||
acme_nsupdate_server: "{{ lookup('community.general.dig', 'primary.nsforexample.org', qtype='A') }}" | ||
``` | ||
### acme_domain.zone | ||
In some cases your DNS server may not be authoritative for a subdomain but the parent domain. In such cases you can | ||
override which zone is used when the nsupdate is issued. For example: | ||
* certificate zone (acme_domain.zone) = mysub.example.org | ||
* DNS is authoritative for example.org and the zonefile should contain the following entry | ||
``` | ||
_acme-challenge.mysub.example.org. 120 IN TXT "nsupdate-test123" | ||
``` | ||
In this scenario the following dictionary should be placed in acme_nsupdate_override_domain | ||
``` | ||
acme_domain: | ||
certificate_name: "mysub.example.org" | ||
zone: "example.org" | ||
subject_alt_name: | ||
- "test.example.org" | ||
- "domain1.example.org" | ||
- "domain2.example.org" | ||
``` | ||
|
||
The same is true for SAN certificates. Please note, that SAN certificates can have multiple subdomain names but | ||
are limited to one zone. | ||
``` | ||
acme_domain: | ||
certificate_name: "mysub.example.org" | ||
zone: "example.org" | ||
``` | ||
|
||
### acme_nsupdate_replication_delay | ||
If you are using a primary/secondary DNS server setup it might be a good idea to wait a second or two after the | ||
nsupdate on the primary was issued. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
--- | ||
# include/role 3 - validate challenge | ||
- name: Validate challenge only if it is created or changed # noqa no-handler | ||
when: acme_challenge is changed | ||
connection: local | ||
delegate_to: localhost | ||
block: | ||
- name: Add a new TXT record to the relevant domains | ||
vars: | ||
record_name: "_acme-challenge.{{ domain | replace('*.', '') }}." # replace '*.' in the case of a wildcard | ||
record_data: "{{ acme_challenge['challenge_data'][domain]['dns-01']['resource_value'] }}" | ||
community.general.nsupdate: | ||
key_name: "{{ acme_nsupdate_dns_key.name | default('nsupdate_key') }}" | ||
key_secret: "{{ acme_nsupdate_dns_key.secret }}" | ||
key_algorithm: "{{ acme_nsupdate_dns_key.algorithm | default('hmac-sha512') }}" | ||
server: "{{ acme_nsupdate_server }}" | ||
zone: "{{ acme_domain.zone | default(domain) }}" | ||
record: "{{ record_name }}" | ||
value: "{{ record_data }}" | ||
type: "TXT" | ||
ttl: "120" | ||
loop: "{{ acme_domain.subject_alt_name }}" | ||
loop_control: | ||
label: "zone={{ domain }} rr={{ record_name }} (TXT) {{ record_data }}" | ||
loop_var: "domain" | ||
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'][domain] is defined | ||
|
||
- name: Wait for DNS replication to catch up | ||
ansible.builtin.pause: | ||
seconds: "{{ acme_nsupdate_replication_delay }}" | ||
|
||
- 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 }}" | ||
when: | ||
- acme_certificate_enabled | default(true) | ||
|
||
always: | ||
- name: Remove the TXT record from the relevant domains | ||
vars: | ||
record_name: "_acme-challenge.{{ domain | replace('*.', '') }}." # replace '*.' in the case of a wildcard | ||
record_data: "{{ acme_challenge['challenge_data'][domain]['dns-01']['resource_value'] }}" | ||
community.general.nsupdate: | ||
key_name: "{{ acme_nsupdate_dns_key.name | default('nsupdate_key') }}" | ||
key_secret: "{{ acme_nsupdate_dns_key.secret }}" | ||
key_algorithm: "{{ acme_nsupdate_dns_key.algorithm | default('hmac-sha512') }}" | ||
server: "{{ acme_nsupdate_server }}" | ||
zone: "{{ acme_domain.zone | default(domain) }}" | ||
record: "{{ record_name }}" | ||
value: "{{ record_data }}" | ||
type: "TXT" | ||
ttl: "120" | ||
state: absent | ||
loop: "{{ acme_domain.subject_alt_name }}" | ||
loop_control: | ||
label: "zone={{ domain }} rr={{ record_name }} (TXT) {{ record_data }}" | ||
loop_var: "domain" | ||
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'][domain] is defined |