Certbot and DNS with BIND and Windows: Difference between revisions

wiki.TerraBase.info
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
What a blessed hassle it is.  Here's what needs to be done.
What a blessed hassle it is.  Here's what needs to be done.


=== Script to Run (work in progress) ===
===Script to Run (work in progress)===
The below script, when run with ./NC.sh, will use DNS to retrieve certificates. That infrastructure has to be set up before hand, and includes the following;
The below script, when run with <code>./NC.sh</code> (assuming that's the name of the script), will use DNS to retrieve certificates (and also update other 'Slave Servers').


* _acme_challenge 'sub zone'
That infrastructure of course has to be set up before hand, and includes the following items (generally speaking);
* "RNDC Setup"
 
* If using external / internal DNS Servers, then that configuration too.
*Configure the following;
<syntaxhighlight lang="text">
**Delegate the _acme_challenge 'sub zone' in Windows (assumes Windows DNS is used as the backend "Master / Primary" DNS Server
**"Slave / Secondary" configuration in BIND (assuming BIND / NAMED is being used as a frontend server;<syntaxhighlight lang="text">
zone "_acme-challenge.WhatEverDomainName.WhatEverSuffix" {
 
check-names ignore;
 
type master;
 
allow-update { W.X.Y.Z/24; };
 
file "/var/named/masters/_acme-challenge.WhatEverDomainName.WhatEverSuffix.hosts";
};
</syntaxhighlight>
 
./NC.sh Script;<syntaxhighlight lang="text">
#!/bin/sh
#!/bin/sh


DomainName="$1"
DomainName="$1"
ScriptsPath="/etc/letsencrypt/renewal-hooks/CUSTOM"


TotalSlaveServers=1
SlaveServer1=W1.X1.Y1.Z1
SlaveServerKey1=WhatEverKey1
SlaveServer2=W2.X2.Y2.Z2
SlaveServerKey2=WhatEverKey2




Line 34: Line 43:




i=1
while [ "$i" -le "$TotalSlaveServers" ]; do
eval SlaveIP="\$SlaveServer${i}"
# Create fresh RNDC temp file for this slave
rm -f /etc/letsencrypt/SCRIPTS/RNDC.TempFile
(
echo 'key "rndc-key" {'
echo ' algorithm hmac-sha256;'
echo " secret \"${SlaveServerKey1}\";"
echo '};'
echo
echo 'options {'
echo " default-key \"rndc-key\";"
echo " default-server ${SlaveIP};"
echo ' default-port 953;'
echo '};'
) > /etc/letsencrypt/SCRIPTS/RNDC.TempFile
# Test the zone on this slave
if /usr/sbin/rndc -c /etc/letsencrypt/SCRIPTS/RNDC.TempFile zonestatus "_acme-challenge.${DomainName}" > /dev/null 2>&1; then
echo
echo "_acme-challenge.${DomainName} Zone Exists on ${SlaveIP}"
echo
else
echo
echo "_acme-challenge.${DomainName} Zone Does NOT exist on ${SlaveIP}"
echo
rm -f /etc/letsencrypt/SCRIPTS/RNDC.TempFile
exit 1
fi
rm -f /etc/letsencrypt/SCRIPTS/RNDC.TempFile
i=$((i + 1))
done
### Remove --staging for a 'Real / Live Certificate';


certbot certonly \
certbot certonly \
--manual \
--manual \
--preferred-challenges dns \
--preferred-challenges dns \
--manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
--manual-auth-hook "${ScriptsPath}/ManualAuth.sh" \
--manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
--manual-cleanup-hook "${ScriptsPath}/ManualCleanUp.sh" \
--non-interactive \
--non-interactive \
--cert-name "${DomainName}" \
--cert-name "${DomainName}" \
Line 89: Line 56:
--manual \
--manual \
--preferred-challenges dns \
--preferred-challenges dns \
--manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
--manual-auth-hook "${ScriptsPath}/ManualAuth.sh" \
--manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
--manual-cleanup-hook "${ScriptsPath}/ManualCleanUp.sh" \
--non-interactive \
--non-interactive \
--cert-name "${DomainName}-WILDCARD" \
--cert-name "${DomainName}-WILDCARD" \
-d "*.${DomainName}"
-d "*.${DomainName}"
</syntaxhighlight>--manual-auth-hook (ManualAuth.sh)<syntaxhighlight lang="text">
#!/bin/sh


ZoneName="_acme-challenge.${CERTBOT_DOMAIN}"
MasterServer=W.X.Y.Z
TTL="0"


### Staging versions of above (REMEMBER: Don't comment individual items out out, it won't work below cuz those \ ( backslashes ) indicate 'one continuous line', not separate lines. )
### Zone Name: the 'sub-zone', which will always be "_acme-challenge", prefixed to the Domain Name
### certbot certonly \
### TTL: Time To Live
### --manual \
 
### --preferred-challenges dns \
### {CERTBOT_DOMAIN}: Variable from CertBot that contains the Domain Name (Example: TerraBase.info
### --manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
### {CERTBOT_VALIDATION} (see below): Variable from CertBot that contains the Validation Text String to be put into a TXT Record (Example: ZtvSKa-0ifZ3lov_zvXj0Adso1Y94Jh8c0xrtjwsTEQ)
### --manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
 
### --staging \
 
### --non-interactive \
 
### --cert-name "${DomainName}" \
### The Following Section enters the record into the BIND / NAMED Zone for Certbot Validation;
### -d "${DomainName}"
 
(
echo "server ${MasterServer}"
echo "zone ${ZoneName}"
echo "update delete ${ZoneName} TXT"
echo "update add ${ZoneName}. ${TTL} TXT \"${CERTBOT_VALIDATION}\""
echo "send"
) | /usr/bin/nsupdate -v
 
 
 
### The following item will sync the BIND / NAMED .hosts and JNL Files
 
/usr/sbin/rndc -s "${MasterServer}" sync "${ZoneName}"
 
 
 
sleep 3
 
 
### For Testing, set the following variables as they're normally provided by Certbot;
 
### CERTBOT_DOMAIN=WhatEverDomainName.WhatEverSuffix
### CERTBOT_VALIDATION="ThisIsTest1"


### certbot certonly \
### --manual \
### --preferred-challenges dns \
### --manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh \
### --manual-cleanup-hook /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh \
### --staging \
### --non-interactive \
### --cert-name "${DomainName}-WILDCARD" \
### -d "*.${DomainName}"
</syntaxhighlight>
</syntaxhighlight>


Line 145: Line 131:
Yup, that's right.  Everything in the /etc/letsencrypt/renewal-hooks/pre/ will be run.  Then anything listed in the Renewal Config File will be run.  Woof!
Yup, that's right.  Everything in the /etc/letsencrypt/renewal-hooks/pre/ will be run.  Then anything listed in the Renewal Config File will be run.  Woof!


'''LESSON LEARNED''': Put hooks in a CUSTOM Directory Structure, NOT in the one provided by Let's Encrypt!<br />
'''LESSON LEARNED''': Put hooks in a CUSTOM Directory Structure, NOT in the one provided by Let's Encrypt!
 
<br />
 
===Troubleshooting Commands===
 
*Regarding the NAMED / BIND .jnl Files;
**rndc zonestatus _acme-challenge.WhatEverDomainName
***...if issues, then;
***rndc freeze _acme-challenge.WhatEverDomainName
***rndc sync -clean _acme-challenge.WhatEverDomainName
***rndc thaw _acme-challenge.WhatEverDomainName
*dig +trace _acme-challenge.grassvalleyflorist.com TXT
 
<br />

Latest revision as of 22:20, 25 August 2025

What a blessed hassle it is. Here's what needs to be done.

Script to Run (work in progress)

The below script, when run with ./NC.sh (assuming that's the name of the script), will use DNS to retrieve certificates (and also update other 'Slave Servers').

That infrastructure of course has to be set up before hand, and includes the following items (generally speaking);

  • Configure the following;
    • Delegate the _acme_challenge 'sub zone' in Windows (assumes Windows DNS is used as the backend "Master / Primary" DNS Server
    • "Slave / Secondary" configuration in BIND (assuming BIND / NAMED is being used as a frontend server;
      zone "_acme-challenge.WhatEverDomainName.WhatEverSuffix" {
      
      	check-names ignore;
      
      	type master;
      
      	allow-update { W.X.Y.Z/24; };
      
      	file "/var/named/masters/_acme-challenge.WhatEverDomainName.WhatEverSuffix.hosts";
      	};

./NC.sh Script;

#!/bin/sh


DomainName="$1"
ScriptsPath="/etc/letsencrypt/renewal-hooks/CUSTOM"



if [ -z "${DomainName}" ]; then
	echo
	echo "Don't forget to add the Domain Name to the end of the command."
	echo "Example: ./NewCertificate.via.DNS.sh terrawide.com"
	echo
	exit 1
else
	echo
	echo "Command Line contains Domain Name: ${DomainName}"
	echo
fi



certbot certonly \
	--manual \
	--preferred-challenges dns \
	--manual-auth-hook "${ScriptsPath}/ManualAuth.sh" \
	--manual-cleanup-hook "${ScriptsPath}/ManualCleanUp.sh" \
	--non-interactive \
	--cert-name "${DomainName}" \
	-d "${DomainName}"

certbot certonly \
	--manual \
	--preferred-challenges dns \
	--manual-auth-hook "${ScriptsPath}/ManualAuth.sh" \
	--manual-cleanup-hook "${ScriptsPath}/ManualCleanUp.sh" \
	--non-interactive \
	--cert-name "${DomainName}-WILDCARD" \
	-d "*.${DomainName}"

--manual-auth-hook (ManualAuth.sh)

#!/bin/sh

ZoneName="_acme-challenge.${CERTBOT_DOMAIN}"
MasterServer=W.X.Y.Z
TTL="0"

### Zone Name: the 'sub-zone', which will always be "_acme-challenge", prefixed to the Domain Name
### TTL: Time To Live

### {CERTBOT_DOMAIN}: Variable from CertBot that contains the Domain Name (Example: TerraBase.info
### {CERTBOT_VALIDATION} (see below): Variable from CertBot that contains the Validation Text String to be put into a TXT Record (Example: ZtvSKa-0ifZ3lov_zvXj0Adso1Y94Jh8c0xrtjwsTEQ)



### The Following Section enters the record into the BIND / NAMED Zone for Certbot Validation;

(
	echo "server ${MasterServer}"
	echo "zone ${ZoneName}"
	echo "update delete ${ZoneName} TXT"
	echo "update add ${ZoneName}. ${TTL} TXT \"${CERTBOT_VALIDATION}\""
	echo "send"
) | /usr/bin/nsupdate -v



### The following item will sync the BIND / NAMED .hosts and JNL Files

/usr/sbin/rndc -s "${MasterServer}" sync "${ZoneName}"



sleep 3


### For Testing, set the following variables as they're normally provided by Certbot;

### CERTBOT_DOMAIN=WhatEverDomainName.WhatEverSuffix
### CERTBOT_VALIDATION="ThisIsTest1"

Big ASH Gotcha!

If you use the preconfigured Directory Structure Let's Encrypt / Certbot provides in /etc/letsencrypt/renewal-hooks, watch out!

When renewing a Certificate it automatically runs everything it finds in the above mentioned Directory, like for instance: /etc/letsencrypt/renewal-hooks/pre/WhatEver.sh

In the instance of the /etc/letsencrypt/renewal/WhatEverRenewalFile below (WHICH CERTBOT AUTOMATICALLY CREATES ITSELF WHEN GETTING A NEW CERTIFICATE!!!);

# renew_before_expiry = 30 days
version = 2.9.0
archive_dir = /etc/letsencrypt/archive/WhatEverDomain.com
cert = /etc/letsencrypt/live/WhatEverDomain.com/cert.pem
privkey = /etc/letsencrypt/live/WhatEverDomain.com/privkey.pem
chain = /etc/letsencrypt/live/WhatEverDomain.com/chain.pem
fullchain = /etc/letsencrypt/live/WhatEverDomain.com/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = WhatEverAccountNumber
pref_challs = dns-01,
authenticator = manual
manual_auth_hook = /etc/letsencrypt/renewal-hooks/pre/ManualAuth.sh
manual_cleanup_hook = /etc/letsencrypt/renewal-hooks/post/ManualCleanUp.sh
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa

Guess how many times the WhatEver.sh Script in the /etc/letsencrypt/renewal-hooks/pre/ runs? Once, as one might think from the above Renewal Config File? Nope, TWICE!

Yup, that's right. Everything in the /etc/letsencrypt/renewal-hooks/pre/ will be run. Then anything listed in the Renewal Config File will be run. Woof!

LESSON LEARNED: Put hooks in a CUSTOM Directory Structure, NOT in the one provided by Let's Encrypt!


Troubleshooting Commands

  • Regarding the NAMED / BIND .jnl Files;
    • rndc zonestatus _acme-challenge.WhatEverDomainName
      • ...if issues, then;
      • rndc freeze _acme-challenge.WhatEverDomainName
      • rndc sync -clean _acme-challenge.WhatEverDomainName
      • rndc thaw _acme-challenge.WhatEverDomainName
  • dig +trace _acme-challenge.grassvalleyflorist.com TXT