Skip to content

Commit 0a2940d

Browse files
authored
Merge pull request #895 from kouba/master
add support for pdns-api
2 parents 94209bc + 5e0a886 commit 0a2940d

4 files changed

Lines changed: 278 additions & 0 deletions

File tree

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,21 @@ For a more comprehensive installation (e.g. install also helper scripts)
190190
use the provided Makefile with each release tarball. Use the `install`
191191
target.
192192

193+
If you install only the standalone `getssl` script to a location such as
194+
`/usr/local/bin/getssl`, the helper scripts under `dns_scripts/` and
195+
`other_scripts/` are not installed automatically. In that case, copy any
196+
helper scripts you need to a suitable location yourself, for example:
197+
198+
```sh
199+
/usr/local/share/getssl/dns_scripts/
200+
```
201+
202+
and reference that path in `DNS_ADD_COMMAND` / `DNS_DEL_COMMAND`.
203+
204+
If you install `getssl` from the provided RPM/DEB packages or via the
205+
`make install` target, the helper scripts are installed alongside it under
206+
`/usr/share/getssl/dns_scripts/` and `other_scripts/`.
207+
193208
You'll find the latest version in the git repository:
194209

195210
```sh
@@ -279,6 +294,26 @@ DNS_ADD_COMMAND=/home/root/getssl/dns_scripts/dns_add_cpanel
279294
DNS_DEL_COMMAND=/home/root/getssl/dns_scripts/dns_del_cpanel
280295
```
281296

297+
## PowerDNS
298+
299+
PowerDNS users can either use the existing MySQL helper scripts or the HTTP
300+
API helper scripts in `dns_scripts/PowerDNS-API-README.md`.
301+
302+
If you installed only `/usr/local/bin/getssl`, remember to copy the helper
303+
scripts to a local directory first, for example:
304+
305+
```sh
306+
install -d /usr/local/share/getssl/dns_scripts
307+
install -m 755 dns_scripts/dns_add_pdns-api /usr/local/share/getssl/dns_scripts/
308+
install -m 755 dns_scripts/dns_del_pdns-api /usr/local/share/getssl/dns_scripts/
309+
```
310+
311+
and then reference them in your `getssl.cfg`:
312+
313+
```sh
314+
DNS_ADD_COMMAND="/usr/local/share/getssl/dns_scripts/dns_add_pdns-api"
315+
DNS_DEL_COMMAND="/usr/local/share/getssl/dns_scripts/dns_del_pdns-api"
316+
```
282317

283318
## ISPConfig
284319

@@ -717,6 +752,7 @@ for dir in *_scripts; do install -dv /root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_
717752
'dns_scripts/DNS_IONOS.md' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/DNS_IONOS.md'
718753
'dns_scripts/DNS_ROUTE53.md' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/DNS_ROUTE53.md'
719754
'dns_scripts/GoDaddy-README.txt' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/GoDaddy-README.txt'
755+
'dns_scripts/PowerDNS-API-README.md' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/PowerDNS-API-README.md'
720756
'dns_scripts/dns_add_acmedns' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_acmedns'
721757
'dns_scripts/dns_add_azure' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_azure'
722758
'dns_scripts/dns_add_challtestsrv' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_challtestsrv'
@@ -737,6 +773,7 @@ for dir in *_scripts; do install -dv /root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_
737773
'dns_scripts/dns_add_manual' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_manual'
738774
'dns_scripts/dns_add_nsupdate' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_nsupdate'
739775
'dns_scripts/dns_add_ovh' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_ovh'
776+
'dns_scripts/dns_add_pdns-api' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_pdns-api'
740777
'dns_scripts/dns_add_pdns-mysql' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_pdns-mysql'
741778
'dns_scripts/dns_add_vultr' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_vultr'
742779
'dns_scripts/dns_add_windows_dns_server' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_add_windows_dns_server'
@@ -759,6 +796,7 @@ for dir in *_scripts; do install -dv /root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_
759796
'dns_scripts/dns_del_manual' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_manual'
760797
'dns_scripts/dns_del_nsupdate' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_nsupdate'
761798
'dns_scripts/dns_del_ovh' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_ovh'
799+
'dns_scripts/dns_del_pdns-api' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_pdns-api'
762800
'dns_scripts/dns_del_pdns-mysql' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_pdns-mysql'
763801
'dns_scripts/dns_del_vultr' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_vultr'
764802
'dns_scripts/dns_del_windows_dns_server' -> '/root/rpmbuild/BUILDROOT/getssl-2.49-1.x86_64/usr/share/getssl/dns_scripts/dns_del_windows_dns_server'
@@ -864,6 +902,7 @@ for dir in *_scripts; do install -dv /root/debbuild/BUILDROOT/getssl-2.49-1.amd6
864902
'dns_scripts/DNS_IONOS.md' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/DNS_IONOS.md'
865903
'dns_scripts/DNS_ROUTE53.md' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/DNS_ROUTE53.md'
866904
'dns_scripts/GoDaddy-README.txt' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/GoDaddy-README.txt'
905+
'dns_scripts/PowerDNS-API-README.md' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/PowerDNS-API-README.md'
867906
'dns_scripts/dns_add_acmedns' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_acmedns'
868907
'dns_scripts/dns_add_azure' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_azure'
869908
'dns_scripts/dns_add_challtestsrv' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_challtestsrv'
@@ -884,6 +923,7 @@ for dir in *_scripts; do install -dv /root/debbuild/BUILDROOT/getssl-2.49-1.amd6
884923
'dns_scripts/dns_add_manual' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_manual'
885924
'dns_scripts/dns_add_nsupdate' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_nsupdate'
886925
'dns_scripts/dns_add_ovh' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_ovh'
926+
'dns_scripts/dns_add_pdns-api' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_pdns-api'
887927
'dns_scripts/dns_add_pdns-mysql' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_pdns-mysql'
888928
'dns_scripts/dns_add_vultr' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_vultr'
889929
'dns_scripts/dns_add_windows_dns_server' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_add_windows_dns_server'
@@ -906,6 +946,7 @@ for dir in *_scripts; do install -dv /root/debbuild/BUILDROOT/getssl-2.49-1.amd6
906946
'dns_scripts/dns_del_manual' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_manual'
907947
'dns_scripts/dns_del_nsupdate' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_nsupdate'
908948
'dns_scripts/dns_del_ovh' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_ovh'
949+
'dns_scripts/dns_del_pdns-api' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_pdns-api'
909950
'dns_scripts/dns_del_pdns-mysql' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_pdns-mysql'
910951
'dns_scripts/dns_del_vultr' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_vultr'
911952
'dns_scripts/dns_del_windows_dns_server' -> '/root/debbuild/BUILDROOT/getssl-2.49-1.amd64/usr/share/getssl/dns_scripts/dns_del_windows_dns_server'

dns_scripts/PowerDNS-API-README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# PowerDNS API
2+
3+
These helper scripts use the PowerDNS HTTP API for DNS-01 validation.
4+
5+
## Requirements
6+
7+
- PowerDNS authoritative server with the HTTP API enabled
8+
- `curl`
9+
- `jq`
10+
11+
## Environment
12+
13+
Set these environment variables before running `getssl`:
14+
15+
- `PDNS_API_URL`
16+
Example: `https://ns1.example.com/pdns`
17+
- `PDNS_API_KEY`
18+
API token for the PowerDNS server
19+
20+
Optional:
21+
22+
- `PDNS_SERVER_ID`
23+
Default: `localhost`
24+
- `PDNS_TTL`
25+
Default: `120`
26+
27+
## Example `getssl.cfg`
28+
29+
```sh
30+
VALIDATE_VIA_DNS="true"
31+
DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_add_pdns-api"
32+
DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_del_pdns-api"
33+
34+
export PDNS_API_URL="https://ns1.example.com/pdns"
35+
export PDNS_API_KEY="your-api-token"
36+
# export PDNS_SERVER_ID="localhost"
37+
# export PDNS_TTL="120"
38+
```

dns_scripts/dns_add_pdns-api

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env bash
2+
3+
fulldomain="${1}"
4+
token="${2}"
5+
api_url="${PDNS_API_URL:-}"
6+
api_key="${PDNS_API_KEY:-}"
7+
server_id="${PDNS_SERVER_ID:-localhost}"
8+
ttl="${PDNS_TTL:-120}"
9+
10+
if [[ -z "$fulldomain" ]]; then
11+
echo "DNS script requires full domain name as first parameter"
12+
exit 1
13+
fi
14+
if [[ -z "$token" ]]; then
15+
echo "DNS script requires challenge token as second parameter"
16+
exit 1
17+
fi
18+
if [[ -z "$api_url" ]]; then
19+
echo "PDNS_API_URL variable not set"
20+
exit 1
21+
fi
22+
if [[ -z "$api_key" ]]; then
23+
echo "PDNS_API_KEY variable not set"
24+
exit 1
25+
fi
26+
if ! command -v jq >/dev/null 2>&1; then
27+
echo "jq command not found"
28+
exit 1
29+
fi
30+
31+
api_get() {
32+
curl --silent -X GET "${1}" \
33+
-H "X-API-Key: ${api_key}"
34+
}
35+
36+
find_zone() {
37+
local domain="${1}"
38+
local candidate="${domain}"
39+
while [[ "${candidate}" == *"."* ]]; do
40+
response=$(curl --silent "${api_url%/}/api/v1/servers/${server_id}/zones/${candidate}." \
41+
-H "X-API-Key: ${api_key}" \
42+
-o /dev/null \
43+
-w '%{http_code}')
44+
if [[ "$response" == "200" ]]; then
45+
printf '%s.\n' "${candidate}"
46+
return 0
47+
fi
48+
candidate="$(echo "${candidate}" | cut -d. -f1 --complement)"
49+
done
50+
return 1
51+
}
52+
53+
zone_name=$(find_zone "$fulldomain")
54+
if [[ -z "$zone_name" ]]; then
55+
echo "Cannot find matching PowerDNS zone"
56+
exit 1
57+
fi
58+
59+
txtname="_acme-challenge.${fulldomain}."
60+
61+
zone_data=$(api_get "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}")
62+
63+
records=$(echo "$zone_data" | jq -c --arg txtname "$txtname" --arg token "$token" '
64+
[
65+
.rrsets[]?
66+
| select(.name == $txtname and .type == "TXT")
67+
| .records[]?.content
68+
] as $existing
69+
| ($existing + [$token | @json] | unique)
70+
| map({content: ., disabled: false})
71+
')
72+
73+
payload=$(jq -cn \
74+
--arg txtname "$txtname" \
75+
--argjson ttl "${ttl}" \
76+
--argjson records "$records" \
77+
'{rrsets:[{changetype:"REPLACE",name:$txtname,type:"TXT",ttl:$ttl,records:$records}]}')
78+
79+
response=$(curl --silent -X PATCH "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}" \
80+
-H 'Content-Type: application/json' \
81+
-H "X-API-Key: ${api_key}" \
82+
-d "$payload" \
83+
-o /dev/null -w '%{http_code}')
84+
85+
if [[ "$response" != "204" ]]; then
86+
echo "Record not created"
87+
echo "Response code: $response"
88+
exit 1
89+
fi
90+
91+
curl --silent -X PUT "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}/notify" \
92+
-H "X-API-Key: ${api_key}" \
93+
-o /dev/null

dns_scripts/dns_del_pdns-api

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env bash
2+
3+
fulldomain="${1}"
4+
token="${2}"
5+
api_url="${PDNS_API_URL:-}"
6+
api_key="${PDNS_API_KEY:-}"
7+
server_id="${PDNS_SERVER_ID:-localhost}"
8+
ttl="${PDNS_TTL:-120}"
9+
10+
if [[ -z "$fulldomain" ]]; then
11+
echo "DNS script requires full domain name as first parameter"
12+
exit 1
13+
fi
14+
if [[ -z "$token" ]]; then
15+
echo "DNS script requires challenge token as second parameter"
16+
exit 1
17+
fi
18+
if [[ -z "$api_url" ]]; then
19+
echo "PDNS_API_URL variable not set"
20+
exit 1
21+
fi
22+
if [[ -z "$api_key" ]]; then
23+
echo "PDNS_API_KEY variable not set"
24+
exit 1
25+
fi
26+
if ! command -v jq >/dev/null 2>&1; then
27+
echo "jq command not found"
28+
exit 1
29+
fi
30+
31+
api_get() {
32+
curl --silent -X GET "${1}" \
33+
-H "X-API-Key: ${api_key}"
34+
}
35+
36+
find_zone() {
37+
local domain="${1}"
38+
local candidate="${domain}"
39+
while [[ "${candidate}" == *"."* ]]; do
40+
response=$(curl --silent "${api_url%/}/api/v1/servers/${server_id}/zones/${candidate}." \
41+
-H "X-API-Key: ${api_key}" \
42+
-o /dev/null \
43+
-w '%{http_code}')
44+
if [[ "$response" == "200" ]]; then
45+
printf '%s.\n' "${candidate}"
46+
return 0
47+
fi
48+
candidate="$(echo "${candidate}" | cut -d. -f1 --complement)"
49+
done
50+
return 1
51+
}
52+
53+
zone_name=$(find_zone "$fulldomain") || exit 0
54+
txtname="_acme-challenge.${fulldomain}."
55+
56+
zone_data=$(api_get "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}")
57+
58+
record_count=$(echo "$zone_data" | jq -r --arg txtname "$txtname" '
59+
[
60+
.rrsets[]?
61+
| select(.name == $txtname and .type == "TXT")
62+
| .records[]?.content
63+
] | length
64+
')
65+
66+
if [[ "$record_count" == "0" ]]; then
67+
exit 0
68+
fi
69+
70+
remaining=$(echo "$zone_data" | jq -c --arg txtname "$txtname" --arg token "$token" '
71+
[
72+
.rrsets[]?
73+
| select(.name == $txtname and .type == "TXT")
74+
| .records[]?
75+
| select(.content != ($token | @json))
76+
| {content: .content, disabled: false}
77+
]
78+
')
79+
80+
if [[ "$remaining" == "[]" ]]; then
81+
payload=$(jq -cn \
82+
--arg txtname "$txtname" \
83+
'{rrsets:[{changetype:"DELETE",name:$txtname,type:"TXT"}]}')
84+
else
85+
payload=$(jq -cn \
86+
--arg txtname "$txtname" \
87+
--argjson ttl "${ttl}" \
88+
--argjson records "$remaining" \
89+
'{rrsets:[{changetype:"REPLACE",name:$txtname,type:"TXT",ttl:$ttl,records:$records}]}')
90+
fi
91+
92+
response=$(curl --silent -X PATCH "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}" \
93+
-H 'Content-Type: application/json' \
94+
-H "X-API-Key: ${api_key}" \
95+
-d "$payload" \
96+
-o /dev/null -w '%{http_code}')
97+
98+
if [[ "$response" != "204" ]]; then
99+
echo "Record not deleted"
100+
echo "Response code: $response"
101+
exit 1
102+
fi
103+
104+
curl --silent -X PUT "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}/notify" \
105+
-H "X-API-Key: ${api_key}" \
106+
-o /dev/null

0 commit comments

Comments
 (0)