Skip to content

Yandex DNS manage script #861

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions dns_scripts/Yandex-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Yandex DNS management via Yandex API

## Requrements

- [JQ](https://jqlang.github.io/jq/) command-line JSON processor needed

## Useful links

- [Yandex API Access](https://yandex.ru/dev/api360/doc/concepts/access.html)
- [Yandex DNS API](https://yandex.ru/dev/api360/doc/ref/DomainDNSService.html)

## Yandex Auth parameters in domain config file

0. Authorize in Your Yandex Account in web browser. You must have Administartor rights
1. Get `OrgId` from Your Comapny Profile - <https://admin.yandex.ru/company-profile> (You have Your first important variable `YANDEX_ORGID` now!)
2. Create Your new application for DNS management - <https://oauth.yandex.ru/client/new/id>
3. Get `ClientID` for this application on application page
4. Get `OAuthToken` for this application from URL <https://oauth.yandex.ru/authorize?response_type=token&client_id=ClientID> in authtorised browser where `ClientID` code from previous step. This is Your second secret variable `YANDEX_OAUTH`!
5. Define this variables in domain config file

```bash
# Use the following 3 variables if you want to validate via DNS
VALIDATE_VIA_DNS="true"
DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_yandex add"
DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_yandex del"
DNS_WAIT="600" # Waiting 10 minutes. Very-very-very slow distrbution

# Yandex base DNS
AUTH_DNS_SERVER="77.88.8.8"

# Yandex Authentication credintals
export YANDEX_ORGID="<OrgId>"
export YANDEX_OAUTH="<OAuthToken>"
```

## Manual run

- `/usr/share/getssl/dns_scripts/dns_yandex add domain.tld <token>` - add `<token> TXT _acme-challenge.domain.tld` record
- `/usr/share/getssl/dns_scripts/dns_yandex add subdomain.domain.tld <token>` - add `<token> TXT _acme-challenge.subdomain.domain.tld` record
- `/usr/share/getssl/dns_scripts/dns_yandex del domain.tld <token>` - delete `<token> TXT _acme-challenge.domain.tld` record
- `/usr/share/getssl/dns_scripts/dns_yandex del subdomain.domain.tld <token>` - delete `<token> TXT _acme-challenge.subdomain.domain.tld` record

- `/usr/share/getssl/dns_scripts/dns_yandex cleanup domain.tld` - cleanup all dangling `_acme-challenge` records from DNS for <domain.tld>
- `/usr/share/getssl/dns_scripts/dns_yandex cleanup subdomain.domain.tld` - cleanup all dangling `_acme-challenge.subdomain` records from DNS for <subdomain.domain.tld>
- `/usr/share/getssl/dns_scripts/dns_yandex cleanup [subdomain.]domain.tld <token>` - cleanup all dangling `_acme-challenge` domain or subdomain records with `<token>`
144 changes: 144 additions & 0 deletions dns_scripts/dns_yandex
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/bin/bash

### Functions
check() { # Verify that required parameters are set
IFS=$'\n'
for var in ${check_vars[@]}; do
var_name=$(echo $var | awk -F, '{ print $1 }')
err_msg=$( echo $var | awk -F, '{ print $2 }')
[ -z "${!var_name}" ] && error_exit "variable '${var_name}' empty. Error:$err_msg"
done
}

add() { # Add challenge domain to DNS
debug "create domain '$acme_domain'"
response=`curl --silent \
-X POST https://api360.yandex.net/directory/v1/org/${orgId}/domains/${domain}/dns \
-H "Authorization: OAuth ${OAuth}" \
-H "Content-Type: application/json" \
-d '{"name":"'"$acme_domain"'","type":"TXT","ttl":"3600","text":"'"$token"'"}'`
debug "Asked record: {\"name\":\"$acme_domain\",\"type\":\"TXT\",\"ttl\":\"3600\",\"text\":\"$token\"}"
debug "Recieved response: \"$response\""
recordId=$(echo $response | jq .recordId)
if [ "$recordId" != "null" ]; then
# Save recordId for cleanup later
mkdir -p -m 0700 $(dirname $recordIdFile)
echo $response >> $recordIdFile
debug "File '$recordIdFile' created/updated:\n$(sed -E '/^#/d;/^\s*$/d' $recordIdFile)"
else
err_code=$(echo $response | jq .code)
err_message=$(echo $response | jq .message)
error_exit "error code: $err_code -- $err_message"
fi
}

del() { # Delete all or specific challenge domains from DNS
if [[ "$1" == "cleanup" ]]; then # Cleanup records for specific domain
if [ -z "$subdomain" ]; then # Delete all records for domain if 'domain.tld' specimied
# Get ALL recordIDs from file
debug "all '$domain' domain records will be removed"
recordIds=`sed -E '/^#/d;/^\s*$/d' $recordIdFile | jq .recordId`
else # Delete all records for specific subdomain only if 'subdomain.domain.tld' specified
# Get ALL recordIDs from file for specific domain
debug "all '$acme_domain' domain records will be removed"
recordIds=`sed -E '/^#/d;/^\s*$/d' $recordIdFile | jq "select(.name == \"$acme_domain\") | .recordId"`
fi
else # Delete specific records for specific domain or subdomain specified challenge token
# Get specific combinations of domain and token
debug "'$acme_domain' domain records with token '$token' will be removed"
recordIds=`sed -E '/^#/d;/^\s*$/d' $recordIdFile | jq "select(.name == \"$acme_domain\" and .text == \"$token\") | .recordId"`
fi
# Check selected exist records
[ -z "$recordIds" ] && error_exit "can't parse '$recordIdFile' file or matched recordIds not found"
# Delete selected records if exist
unset not_removed
for recordId in $recordIds; do
debug "removeing record '$recordId'"
del_result=`curl -H "Authorization: OAuth ${OAuth}" --silent \
-X DELETE https://api360.yandex.net/directory/v1/org/${orgId}/domains/${domain}/dns/${recordId}`
if [ "$del_result" == "{}" ]; then
sed -i "/$recordId/d" $recordIdFile # Remove record from file if it was removed from DNS
unset del_msg
else
not_removed=${not_removed:+$not_removed, }$recordId
del_msg=' NOT'
fi
debug "'$recordId' was$rm_msg removed from DNS and file '$recordIdFile'"
done
[ -n "$not_removed" ] && error_exit "Something went wrong. Server says: '$del_result' This records was NOT removed: '$not_removed'"
}

### Requires
requires jq

### Presets
# Yandex Authentication credintals
orgId=${YANDEX_ORGID:-''}
OAuth=${YANDEX_OAUTH:-''}

# Let's Encrypt DNS validtaion token
token=$3

# Split FQDN to domain and subdomain. Specific for Yandex API
fqdn=`echo $2 | grep -Po '^(?:(?!-)[a-z0-9-]{0,62}[a-z0-9]\.)+[a-z]{2,}$'`
domain=`echo $fqdn | grep -Po '(?!-)[a-z0-9-]{0,62}[a-z0-9]\.[a-z]{2,}$'`
subdomain=`echo $fqdn | sed -E 's/(\.?[^.]+){2}$//'`

acme_domain="_acme-challenge${subdomain:+.$subdomain}"
recordIdFile=${WORKING_DIR:-/tmp}/getssl_yandex_dns_records

debug "FQDN: '$fqdn'
Validation token: '$token'
Asked domain: '$domain'
Asked subdomain: '$subdomain'
Record ID file: '$recordIdFile'"

# Yandex API returns JSON with recordId as successful result
# It's required for remove this record later. Yandex API cant't remove records by names, by recordId only
[ -f "$recordIdFile" ] || echo -n "
# DON'T EDIT! DON'T DELETE!
# This is active Yandex DNS challenge records
# Don't remove manually
# Just run \`$(cd "$(dirname "$0")" || exit; pwd -P;) cleanup [subdomain.]domain.tld\`

" > "$recordIdFile"

### Main process
case "$1" in
"add" )
check_vars=(
"fqdn, No or invalid FQDN"
"domain, No or invalid DOMAIN"
"token, No challenge token"
"orgId, No Yandex OrgID"
"OAuth, No Yandex OAuth"
)
check
add
;;

"del" )
check_vars=(
"domain, No or invalid DOMAIN"
"token, No challenge token"
"orgId, No Yandex OrgID"
"OAuth, No Yandex OAuth"
)
check
del
;;

"cleanup" )
check_vars=(
"domain, No or invalid DOMAIN"
"orgId, No Yandex OrgID"
"OAuth, No Yandex OAuth"
)
check
del cleanup
;;

* )
echo "Unknown command '$1'. Valid commands: (add|del|cleanup)"
;;
esac
12 changes: 8 additions & 4 deletions getssl
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ clean_up() { # Perform pre-exit housekeeping
fi
fi
}
export -f clean_up # for use in DNS scripts

copy_file_to_location() { # copies a file, using scp, sftp or ftp if required.
cert=$1 # descriptive name, just used for display
Expand Down Expand Up @@ -1293,11 +1294,11 @@ debug() { # write out debug info if the debug flag has been set
if [[ -n ${BATS_RUN_TMPDIR} ]]; then
echo "$(date "+%b %d %T") ${FUNCNAME[1]}:${BASH_LINENO[1]}" "$@"
else
echo " "
echo "$@"
echo -e "\n$@"
fi
fi
}
export -f debug # for use in DNS scripts

error_exit() { # give error message on error exit
echo -e "${PROGNAME}: ${1:-"Unknown Error"}" >&2
Expand All @@ -1307,6 +1308,7 @@ error_exit() { # give error message on error exit
clean_up
exit 1
}
export -f error_exit # for use in DNS scripts

find_dns_utils() {
HAS_NSLOOKUP=false
Expand Down Expand Up @@ -1366,7 +1368,7 @@ add_dns_rr() {
# shellcheck disable=SC2018,SC2019
lower_d=$(printf '%s' "${d#\*.}" | tr 'A-Z' 'a-z')
debug "adding DNS RR via command: ${DNS_ADD_COMMAND} ${lower_d} ${auth_key}"
eval "${DNS_ADD_COMMAND}" "${lower_d}" "${auth_key}"
eval "PROGNAME=$PROGNAME _USE_DEBUG=$_USE_DEBUG WORKING_DIR=$WORKING_DIR ${DNS_ADD_COMMAND}" "${lower_d}" "${auth_key}"
}

del_dns_rr() {
Expand All @@ -1376,7 +1378,7 @@ del_dns_rr() {
# shellcheck disable=SC2018,SC2019
lower_d=$(printf '%s' "${d#\*.}" | tr 'A-Z' 'a-z')
debug "removing DNS RR via command: ${DNS_DEL_COMMAND} ${lower_d} ${auth_key}"
eval "${DNS_DEL_COMMAND}" "${lower_d}" "${auth_key}"
eval "PROGNAME=$PROGNAME _USE_DEBUG=$_USE_DEBUG WORKING_DIR=$WORKING_DIR ${DNS_DEL_COMMAND}" "${lower_d}" "${auth_key}"
}

fulfill_challenges() {
Expand Down Expand Up @@ -2438,6 +2440,7 @@ requires() { # check if required function is available
fi
fi
}
export -f requires # for use in DNS scripts

set_server_type() { # uses SERVER_TYPE to set REMOTE_PORT and REMOTE_EXTRA
if [[ ${SERVER_TYPE} == "https" ]] || [[ ${SERVER_TYPE} == "webserver" ]]; then
Expand Down Expand Up @@ -2680,6 +2683,7 @@ traceback() { # Print function traceback
done
return 0
}
export -f traceback # for use in DNS scripts

urlbase64() { # urlbase64: base64 encoded string with '+' replaced with '-' and '/' replaced with '_'
openssl base64 -e | tr -d '\n\r' | os_esed -e 's:=*$::g' -e 'y:+/:-_:'
Expand Down