My own script for TLSA records

Panormitis

Verified User
Joined
Sep 13, 2014
Messages
37
I was trying to add TLSA records for two of my domains, the script set_tlsa.sh in https://docs.directadmin.com/other-...y-add-tlsa-records-with-let-s-encrypt-updates didn't work in my case, so I decided to make my own version.
Feel free to use it if you like. Create a file (in my case set_tlsa_records_30x.sh) in /usr/local/directadmin/scripts/custom and set 700 permissions.
Bash:
#!/bin/bash

DOMAIN="${1//[^[:alnum:]._-]/}" # Just in case, let's removes all spaces and special characters from $1.
SHA_TYPE="sha256"               # Valid values: sha256 or sha512.
TMPDIR=/tmp
TQ=/usr/local/directadmin/data/task.queue
DTQ=/usr/local/directadmin/dataskq

if [ ${DOMAIN} = "" ] || [ ! -d /etc/virtual/${DOMAIN} ]; then
    echo "${DOMAIN} is not a valid domain, aborting...";
    exit 1
fi

if [ ${SHA_TYPE} = "sha256" ]; then
    RECORD_DATA_1="3 0 1"
    RECORD_DATA_2="3 0 1"
elif [ ${SHA_TYPE} = "sha512" ]; then
    RECORD_DATA_1="3 0 2"
    RECORD_DATA_2="3 0 2"
else
    echo "Wrong SHA_TYPE value, it can only be sha256 or sha512, aborting...";
    exit 1
fi

# Get the data for domain.com.
echo | openssl s_client -connect ${DOMAIN}:443 -no_ticket -servername ${DOMAIN} 2>/dev/null | openssl x509 > ${TMPDIR}/${DOMAIN}.pem
if [ -e ${TMPDIR}/${DOMAIN}.pem ] && [ -s ${TMPDIR}/${DOMAIN}.pem ]; then # If we got the certificate successfully proceed, otherwise abort.
    RECORD_DATA_1="${RECORD_DATA_1} $(openssl x509 -in ${TMPDIR}/${DOMAIN}.pem -outform DER | openssl dgst -${SHA_TYPE} | awk '{ print $2 }')"
    rm -f ${TMPDIR}/${DOMAIN}.pem
else
    echo "Couldn't get certificate information for ${DOMAIN}! TLSA procedure aborted!"
    exit 1
fi

# Get the data for mail.domain.com.
echo | openssl s_client -starttls smtp -connect mail.${DOMAIN}:25 -no_ticket -servername mail.${DOMAIN} 2>/dev/null | openssl x509 > ${TMPDIR}/mail.${DOMAIN}.pem
if [ -e ${TMPDIR}/mail.${DOMAIN}.pem ] && [ -s ${TMPDIR}/mail.${DOMAIN}.pem ]; then # If we got the certificate successfully proceed, otherwise abort.
    RECORD_DATA_2="${RECORD_DATA_2} $(openssl x509 -in ${TMPDIR}/mail.${DOMAIN}.pem -outform DER | openssl dgst -${SHA_TYPE} | awk '{ print $2 }')"
    rm -f ${TMPDIR}/mail.${DOMAIN}.pem
else
    echo "Couldn't get certificate information for mail.${DOMAIN}! TLSA procedure aborted!"
    exit 1
fi

# Delete the old TLSA records if they exist.
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=_443._tcp&value=*" >> ${TQ}.cb;
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=_25._tcp.mail&value=*" >> ${TQ}.cb;
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=_587._tcp.mail&value=*" >> ${TQ}.cb; ${DTQ} --custombuild

# Add the new TLSA records.
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=_443._tcp&value=${RECORD_DATA_1}" >> ${TQ}.cb;
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=_25._tcp.mail&value=${RECORD_DATA_2}" >> ${TQ}.cb;
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=_587._tcp.mail&value=${RECORD_DATA_2}" >> ${TQ}.cb; ${DTQ} --custombuild

# Set named to reload.
echo 'action=named&value=reload' >> ${TQ}

echo "TLSA procedure completed successfully!"

exit 0

Go to /usr/local/directadmin/scripts/custom
If you want the script to be triggered on Let's Encrypt queries, create a file named letsencrypt_post.sh and set 700 permissions.
If you want the script to be triggered every time any SSL is saved (including Let's Encrypt), create a file named ssl_save_post.sh and set 700 permissions.
In my case I want the TLSA records to be updated automatically but only on some domains, not all domains on the server are using DNSSEC.
Bash:
#!/bin/bash

# These are our domain names that use TSLA records.
DOMAIN_NAMES=("domain1.com" "domain2.com" "domain3.com")

# Check if the domain name that got a new SSL certificate, is included in the array and update its TSLA records.
for DOMAIN_NAME in ${DOMAIN_NAMES[@]}; do
    if [ ${DOMAIN_NAME} = ${domain} ]; then
        /usr/local/directadmin/scripts/custom/set_tlsa_records_30x.sh ${domain}
    fi
done

exit 0

EDIT: Updated the scripts a bit: Added port 587. SHA-512 hash functionality is available.

The scripts worked and I got all green on https://ssl-tools.net/mailservers/
Screenshot From 2025-03-03 10-53-12.png
 
Last edited:
The scripts above work, but because I'm using DANE-EE, every time a Let's Encrypt certificate is renewed, the TLSA records need updating.
Because of DNS propagation & caching this could cause mail deliverability issues. So let's make new scripts that use DANE-TA.
Feel free to use them if you like. Create a file (in my case set_tlsa_records_20x.sh) in /usr/local/directadmin/scripts/custom and set 700 permissions.
Bash:
#!/bin/bash

USERNAME="${1//[^[:alnum:]._-]/}" # Just in case, let's removes all spaces and special characters from $1.
DOMAIN="${2//[^[:alnum:]._-]/}"   # Just in case, let's removes all spaces and special characters from $2.
SHA_TYPE="sha256"                 # Valid values: sha256 or sha512.
TQ=/usr/local/directadmin/data/task.queue
DTQ=/usr/local/directadmin/dataskq

if [ ${USERNAME} = "" ] || [ ${DOMAIN} = "" ]; then
    echo "Both USERNAME and DOMAIN are required, aborting...";
    exit 1
elif [ ! -d /etc/virtual/${DOMAIN} ]; then
    echo "${DOMAIN} is not a valid domain, aborting...";
    exit 1
fi

if [ ${SHA_TYPE} = "sha256" ]; then
    RECORD_DATA_1="2 0 1"
    RECORD_DATA_2="2 0 1"
elif [ ${SHA_TYPE} = "sha512" ]; then
    RECORD_DATA_1="2 0 2"
    RECORD_DATA_2="2 0 2"
else
    echo "Wrong SHA_TYPE value, it can only be sha256 or sha512, aborting...";
    exit 1
fi

DOMAIN_CA="/usr/local/directadmin/data/users/${USERNAME}/domains/${DOMAIN}.cacert"
MAIL_CA="/usr/local/directadmin/data/users/${USERNAME}/domains/mail.${DOMAIN}.cacert"

if [ ! -e ${MAIL_CA} ] || [ ! -s ${MAIL_CA} ]; then
    MAIL_CA=${DOMAIN_CA}
fi

if [ ! -e ${DOMAIN_CA} ] || [ ! -s ${DOMAIN_CA} ]; then
    echo "Required CA files not found! TLSA procedure aborted!"
    exit 1
fi

# Generate the data of the records.
RECORD_DATA_1="${RECORD_DATA_1} $(openssl x509 -in ${DOMAIN_CA} -outform DER | openssl dgst -${SHA_TYPE} -binary | hexdump -ve '/1 "%02x"')"
RECORD_DATA_2="${RECORD_DATA_2} $(openssl x509 -in ${MAIL_CA} -outform DER | openssl dgst -${SHA_TYPE} -binary | hexdump -ve '/1 "%02x"')"

# Delete the old TLSA records if they exist.
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=_443._tcp&value=*" >> ${TQ}.cb;
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=_25._tcp.mail&value=*" >> ${TQ}.cb;
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=_587._tcp.mail&value=*" >> ${TQ}.cb; ${DTQ} --custombuild

# Add the new TLSA records.
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=_443._tcp&value=${RECORD_DATA_1}" >> ${TQ}.cb;
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=_25._tcp.mail&value=${RECORD_DATA_2}" >> ${TQ}.cb;
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=_587._tcp.mail&value=${RECORD_DATA_2}" >> ${TQ}.cb; ${DTQ} --custombuild

# Set named to reload.
echo 'action=named&value=reload' >> ${TQ}

echo "TLSA procedure completed successfully!"

exit 0
DANE-TA will remain the same even after Let's Encrypt certificates are renewed, so TLSA records don't need updating that often, but eventually the CA will change (after 2 years or so) therefore its better to automatically trigger the script somehow, in case the CA changes. If CA remains the same, the TLSA records will be recreated using the same values, no big deal, nothing breaks.
So, let's go to /usr/local/directadmin/scripts/custom
If you want the script to be triggered on Let's Encrypt queries, create a file named letsencrypt_post.sh and set 700 permissions.
If you want the script to be triggered every time any SSL is saved (including Let's Encrypt), create a file named ssl_save_post.sh and set 700 permissions.
In my case I want the TLSA records to be updated automatically but only on some domains, not all domains on the server are using DNSSEC.
Bash:
#!/bin/bash

# These are our domain names that use TSLA records.
DOMAIN_NAMES=("domain1.com" "domain2.com" "domain3.com")

# Check if the domain name that got a new SSL certificate, is included in the array and update its TSLA records.
for DOMAIN_NAME in ${DOMAIN_NAMES[@]}; do
    if [ ${DOMAIN_NAME} = ${domain} ]; then
        /usr/local/directadmin/scripts/custom/set_tlsa_records_20x.sh ${username} ${domain}
    fi
done

exit 0
That's it! Potentially less secure, but mail deliverability issues won't happen on Let's Encrypt renewals.
 
Last edited:
Back
Top