@@ -0,0 +1,159 @@
#! /usr/bin/env bash
# Read https://www.linode.com/docs/email/postfix/configure-spf-and-dkim-in-postfix-on-debian-8 first!
# Run this script at the beginning of each month
cf_prefix=" https://api.cloudflare.com/client/v4"
cf_email=" [email protected] "
cf_api_key=" my-cloudflare-api-key"
config_dir=" /etc/opendkim"
declare -a cf_headers=(
" -H" " X-Auth-Email: $cf_email "
" -H" " X-Auth-Key: $cf_api_key "
" -H" " Content-Type: application/json"
)
declare -a domains=(
" example.com"
" instance.com"
)
declare -A zone_list=()
declare -A record_list=()
function get_zones() {
# $1: print results or not
for domain in ${domains[@]} ; do
response=$( curl " ${cf_headers[@]} " -sL " $cf_prefix /zones?name=$domain &status=active&match=all" )
zone_id=$( jq -r ' .result[0].id' <<< " $response" )
zone_list[" $domain " ]=" $zone_id "
if [[ " $1 " -eq 1 ]]; then
printf ' Domain %s ID:\t%s\n' " $domain " " $zone_id "
fi
done
}
function get_txt_records() {
# $1: domain
record_list=()
zone_id=" ${zone_list[$1]} "
response=$( curl " ${cf_headers[@]} " -sL " $cf_prefix /zones/$zone_id /dns_records?type=TXT&match=all" )
while read line; do
name=$( sed " s/^\([^\t]*\)\t\(.*\)$/\1/" <<< " $line" )
record_id=$( sed " s/^\([^\t]*\)\t\(.*\)$/\2/" <<< " $line" )
record_list[" $name " ]=" $record_id "
done < <( jq -r ' .result[] | .name + "\t" + .id' <<< " $response" )
}
function delete_record() {
# $1: domain, $2: record name
response=$( curl -X DELETE " ${cf_headers[@]} " -sL " $cf_prefix /zones/${zone_list[$1]} /dns_records/${record_list[$2]} " )
if [[ $? -ne 0 ]]; then
return 1
fi
if [[ $( jq -r ' .success' <<< " $response" ) != " true" ]]; then
return 1
fi
return 0
}
function create_record() {
# $1: domain, $2: selector
content=$( (tr -d $' \n ' | sed ' s/^.*"\(v=DKIM.*\)".*$/\1/' | tr -d ' "' | tr -d $' \t ' | tr -d ' ' | sed ' s/;/; /g' | sed ' s/rsa-sha256/sha256/' ) < " $config_dir /keys/$1 -$2 .txt" )
data=$( jq -r " .name = \" $2 ._domainkey.$1 \" | .content = \" $content \" | .type = \" TXT\" " <<< ' {}' )
curl -X POST " ${cf_headers[@]} " -d " $data " -sL " $cf_prefix /zones/${zone_list[$1]} /dns_records" > /dev/null
if [[ $? -ne 0 ]]; then
return 1
fi
for i in $( seq 1 10) ; do
sleep 60
opendkim-testkey -d " $1 " -s " $2 " -k " $config_dir /keys/$1 -$2 .private" > /dev/null
if [[ $? -eq 0 ]]; then
return 0
fi
done
return 1
}
function generate_dkim_keys() {
# $1: domain, $2: selector
if [[ -f " $config_dir /keys/$1 -$2 .private" ]]; then
return 2
fi
opendkim-genkey -b 2048 -h rsa-sha256 -r -s " $2 " -d " $1 " -D " $config_dir /keys" 2>&1 > /dev/null
if [[ $? -ne 0 ]]; then
return 1
else
mv " $config_dir /keys/$2 .private" " $config_dir /keys/$1 -$2 .private"
chown opendkim:opendkim " $_ "
mv " $config_dir /keys/$2 .txt" " $config_dir /keys/$1 -$2 .txt"
chown opendkim:opendkim " $_ "
return 0
fi
}
function update_key_table() {
# $1: domain, $2: selector
sed " /$domain /d" -i " $config_dir /key.table"
printf ' %s\t%s:%s:%s/keys/%s.private\n' " $domain " " $domain " " $selector " " $config_dir " " $domain " >> " $config_dir /key.table"
}
function diff_months() {
months1=$(( ${1: 0: 4} * 12 + ${1: -2} ))
months2=$(( ${2: 0: 4} * 12 + ${2: -2} ))
result=$(( $months1 - $months2 ))
if [[ $result -le 0 ]]; then
result=$(( - $result ))
fi
printf " $result "
}
function main() {
selector=$( date +%Y%m)
get_zones
for domain in ${domains[@]} ; do
get_txt_records " $domain "
declare -a to_delete=()
for name in " ${! record_list[@]} " ; do
if [[ " $name " == * " ._domainkey.$domain " ]] && [[ " $name " != " _adsp._domainkey.$domain " ]] && [[ $( diff_months " ${name: 0: 6} " " $selector " ) -gt 3 ]]; then
to_delete+=(" $name " )
fi
done
if [[ ${# to_delete[@]} -gt 0 ]]; then
printf ' Records to delete for %s:\n' " $domain "
for name in ${to_delete[@]} ; do
printf ' \t%s\t...\t' " $name "
delete_record " $domain " " $name "
[[ $? -eq 0 ]] && printf ' deleted\n' || printf ' failed to delete\n'
done
fi
generate_dkim_keys " $domain " " $selector "
case $? in
2)
printf ' DKIM key %s for %s already exists\n' " $selector " " $domain "
;;
1)
printf ' Failed to generate DKIM key %s for %s\n' " $selector " " $domain "
;;
0)
create_record " $domain " " $selector "
if [[ $? -ne 0 ]]; then
printf ' Failed to create DKIM record %s for %s\n' " $selector " " $domain "
else
sleep 60
ln -sf " $config_dir /keys/$domain -$selector .private" " $config_dir /keys/$domain .private"
chown -h opendkim:opendkim " $_ "
update_key_table " $domain " " $selector "
systemctl reload opendkim.service
printf ' DKIM record %s for %s created\n' " $selector " " $domain "
fi
;;
esac
done
}
if [[ " $USER " != " root" ]]; then
printf ' Must run as root\n'
exit 1
else
main
fi