Merge pull request #1332 from Neilpang/dev

sync
This commit is contained in:
neil 2018-03-07 09:38:54 +08:00 committed by GitHub
commit c3a289cebc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 252 additions and 64 deletions

View File

@ -327,6 +327,7 @@ You don't have to do anything manually!
1. selectel.com(selectel.ru) DNS API 1. selectel.com(selectel.ru) DNS API
1. zonomi.com DNS API 1. zonomi.com DNS API
1. DreamHost.com API 1. DreamHost.com API
1. DirectAdmin API
And: And:

View File

@ -4078,7 +4078,9 @@ $_authorizations_map"
_info "Your cert key is in $(__green " $CERT_KEY_PATH ")" _info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
fi fi
cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH" if [ "$ACME_VERSION" != "2" ]; then
cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
fi
if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then
USER_PATH="$PATH" USER_PATH="$PATH"

View File

@ -114,8 +114,8 @@ user
Any backups older than 180 days will be deleted when new certificates Any backups older than 180 days will be deleted when new certificates
are deployed. This defaults to "yes" set to "no" to disable backup. are deployed. This defaults to "yes" set to "no" to disable backup.
###Eamples using SSH deploy ###Examples using SSH deploy
The following example illustrates deploying certifcates to a QNAP NAS The following example illustrates deploying certificates to a QNAP NAS
(tested with QTS version 4.2.3) (tested with QTS version 4.2.3)
```sh ```sh
@ -132,8 +132,8 @@ the same file. This will result in the certificate being appended
to the same file as the private key... a common requirement of several to the same file as the private key... a common requirement of several
services. services.
The next example illustates deploying certificates to a Unifi The next example illustrates deploying certificates to a Unifi
Contolller (tested with version 5.4.11). Controller (tested with version 5.4.11).
```sh ```sh
export DEPLOY_SSH_USER="root" export DEPLOY_SSH_USER="root"
@ -153,9 +153,9 @@ export DEPLOY_SSH_REMOTE_CMD="openssl pkcs12 -export \
acme.sh --deploy -d unifi.example.com --deploy-hook ssh acme.sh --deploy -d unifi.example.com --deploy-hook ssh
``` ```
In this exmple we execute several commands on the remote host In this example we execute several commands on the remote host
after the certificate files have been copied... to generate a pkcs12 file after the certificate files have been copied... to generate a pkcs12 file
compatible with Unifi, to import it into the Unifi keystore and then finaly compatible with Unifi, to import it into the Unifi keystore and then finally
to restart the service. to restart the service.
Note also that once the certificate is imported Note also that once the certificate is imported
@ -233,7 +233,7 @@ DEPLOY_CPANEL_USER is required only if you run the script as root and it should
export DEPLOY_CPANEL_USER=username export DEPLOY_CPANEL_USER=username
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
``` ```
Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain. Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separate certificate for each domain.
## 8. Deploy the cert to your FRITZ!Box router ## 8. Deploy the cert to your FRITZ!Box router

View File

@ -354,7 +354,7 @@ acme.sh --issue --dns dns_gandi_livedns -d example.com -d www.example.com
First, generate a TSIG key for updating the zone. First, generate a TSIG key for updating the zone.
``` ```
keymgr tsig generate acme_key algorithm hmac-sha512 > /etc/knot/acme.key keymgr tsig generate -t acme_key hmac-sha512 > /etc/knot/acme.key
``` ```
Include this key in your knot configuration file. Include this key in your knot configuration file.
@ -757,6 +757,34 @@ acme.sh --issue --dns dns_dreamhost -d example.com -d www.example.com
The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will The 'DH_API_KEY' will be saved in `~/.acme.sh/account.conf` and will
be reused when needed. be reused when needed.
## 41. Use DirectAdmin API
The DirectAdmin interface has it's own Let's encrypt functionality, but this
script can be used to generate certificates for names which are not hosted on
DirectAdmin
User must provide login data and URL to the DirectAdmin incl. port.
You can create an user which only has access to
- CMD_API_DNS_CONTROL
- CMD_API_SHOW_DOMAINS
By using the Login Keys function.
See also https://www.directadmin.com/api.php and https://www.directadmin.com/features.php?id=1298
```
export DA_Api="https://remoteUser:remotePassword@da.domain.tld:8443"
export DA_Api_Insecure=1
```
Set `DA_Api_Insecure` to 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1)
Ok, let's issue a cert now:
```
acme.sh --issue --dns dns_da -d example.com -d www.example.com
```
The `DA_Api` and `DA_Api_Insecure` will be saved in `~/.acme.sh/account.conf` and will be reused when needed.
# Use custom API # Use custom API
If your API is not supported yet, you can write your own DNS API. If your API is not supported yet, you can write your own DNS API.

184
dnsapi/dns_da.sh Executable file
View File

@ -0,0 +1,184 @@
#!/usr/bin/env sh
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
# vim: et ts=2 sw=2
#
# DirectAdmin 1.41.0 API
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
# script can be used to generate certificates for names which are not hosted on
# DirectAdmin
#
# User must provide login data and URL to DirectAdmin incl. port.
# You can create login key, by using the Login Keys function
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
# - CMD_API_DNS_CONTROL
# - CMD_API_SHOW_DOMAINS
#
# See also https://www.directadmin.com/api.php and
# https://www.directadmin.com/features.php?id=1298
#
# Report bugs to https://github.com/TigerP/acme.sh/issues
#
# Values to export:
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
# export DA_Api_Insecure=1
#
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
# whether ssl cert is checked for validity (0) or whether it is just accepted
# (1)
#
######## Public functions #####################
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to add txt record
dns_da_add() {
fulldomain="${1}"
txtvalue="${2}"
_debug "Calling: dns_da_add() '${fulldomain}' '${txtvalue}'"
_DA_credentials && _DA_getDomainInfo && _DA_addTxt
}
# Usage: dns_da_rm _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
# Used to remove the txt record after validation
dns_da_rm() {
fulldomain="${1}"
txtvalue="${2}"
_debug "Calling: dns_da_rm() '${fulldomain}' '${txtvalue}'"
_DA_credentials && _DA_getDomainInfo && _DA_rmTxt
}
#################### Private functions below ##################################
# Usage: _DA_credentials
# It will check if the needed settings are available
_DA_credentials() {
DA_Api="${DA_Api:-$(_readaccountconf_mutable DA_Api)}"
DA_Api_Insecure="${DA_Api_Insecure:-$(_readaccountconf_mutable DA_Api_Insecure)}"
if [ -z "${DA_Api}" ] || [ -z "${DA_Api_Insecure}" ]; then
DA_Api=""
DA_Api_Insecure=""
_err "You haven't specified the DirectAdmin Login data, URL and whether you want check the DirectAdmin SSL cert. Please try again."
return 1
else
_saveaccountconf_mutable DA_Api "${DA_Api}"
_saveaccountconf_mutable DA_Api_Insecure "${DA_Api_Insecure}"
# Set whether curl should use secure or insecure mode
export HTTPS_INSECURE="${DA_Api_Insecure}"
fi
}
# Usage: _get_root _acme-challenge.www.example.com
# Split the full domain to a domain and subdomain
#returns
# _sub_domain=_acme-challenge.www
# _domain=example.com
_get_root() {
domain=$1
i=2
p=1
# Get a list of all the domains
# response will contain "list[]=example.com&list[]=example.org"
_da_api CMD_API_SHOW_DOMAINS "" "${domain}"
while true; do
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
_debug h "$h"
if [ -z "$h" ]; then
# not valid
_debug "The given domain $h is not valid"
return 1
fi
if _contains "$response" "$h" >/dev/null; then
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
_domain=$h
return 0
fi
p=$i
i=$(_math "$i" + 1)
done
_debug "Stop on 100"
return 1
}
# Usage: _da_api CMD_API_* data example.com
# Use the DirectAdmin API and check the result
# returns
# response="error=0&text=Result text&details="
_da_api() {
cmd=$1
data=$2
domain=$3
_debug "$domain; $data"
response="$(_post "$data" "$DA_Api/$cmd" "" "POST")"
if [ "$?" != "0" ]; then
_err "error $cmd"
return 1
fi
_debug response "$response"
case "${cmd}" in
CMD_API_DNS_CONTROL)
# Parse the result in general
# error=0&text=Records Deleted&details=
# error=1&text=Cannot View Dns Record&details=No domain provided
err_field="$(_getfield "$response" 1 '&')"
txt_field="$(_getfield "$response" 2 '&')"
details_field="$(_getfield "$response" 3 '&')"
error="$(_getfield "$err_field" 2 '=')"
text="$(_getfield "$txt_field" 2 '=')"
details="$(_getfield "$details_field" 2 '=')"
_debug "error: ${error}, text: ${text}, details: ${details}"
if [ "$error" != "0" ]; then
_err "error $response"
return 1
fi
;;
CMD_API_SHOW_DOMAINS) ;;
esac
return 0
}
# Usage: _DA_getDomainInfo
# Get the root zone if possible
_DA_getDomainInfo() {
_debug "First detect the root zone"
if ! _get_root "$fulldomain"; then
_err "invalid domain"
return 1
else
_debug "The root domain: $_domain"
_debug "The sub domain: $_sub_domain"
fi
return 0
}
# Usage: _DA_addTxt
# Use the API to add a record
_DA_addTxt() {
curData="domain=${_domain}&action=add&type=TXT&name=${_sub_domain}&value=\"${txtvalue}\""
_debug "Calling _DA_addTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'"
_da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}"
_debug "Result of _DA_addTxt: '$response'"
if _contains "${response}" 'error=0'; then
_debug "Add TXT succeeded"
return 0
fi
_debug "Add TXT failed"
return 1
}
# Usage: _DA_rmTxt
# Use the API to remove a record
_DA_rmTxt() {
curData="domain=${_domain}&action=select&txtrecs0=name=${_sub_domain}&value=\"${txtvalue}\""
_debug "Calling _DA_rmTxt: '${curData}' '${DA_Api}/CMD_API_DNS_CONTROL'"
if _da_api CMD_API_DNS_CONTROL "${curData}" "${_domain}"; then
_debug "Result of _DA_rmTxt: '$response'"
else
_err "Result of _DA_rmTxt: '$response'"
fi
if _contains "${response}" 'error=0'; then
_debug "RM TXT succeeded"
return 0
fi
_debug "RM TXT failed"
return 1
}

View File

@ -1,11 +1,12 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#Author: RaidneII #Author: RaidenII
#Created 06/28/2017 #Created 06/28/2017
#Updated 03/01/2018, rewrote to support name.com API v4
#Utilize name.com API to finish dns-01 verifications. #Utilize name.com API to finish dns-01 verifications.
######## Public functions ##################### ######## Public functions #####################
Namecom_API="https://api.name.com/api" Namecom_API="https://api.name.com/v4"
#Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" #Usage: dns_namecom_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_namecom_add() { dns_namecom_add() {
@ -39,21 +40,18 @@ dns_namecom_add() {
# Find domain in domain list. # Find domain in domain list.
if ! _namecom_get_root "$fulldomain"; then if ! _namecom_get_root "$fulldomain"; then
_err "Unable to find domain specified." _err "Unable to find domain specified."
_namecom_logout
return 1 return 1
fi fi
# Add TXT record. # Add TXT record.
_namecom_addtxt_json="{\"hostname\":\"$_sub_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":\"300\",\"priority\":\"10\"}" _namecom_addtxt_json="{\"host\":\"$_sub_domain\",\"type\":\"TXT\",\"answer\":\"$txtvalue\",\"ttl\":\"300\"}"
if _namecom_rest POST "dns/create/$_domain" "$_namecom_addtxt_json"; then if _namecom_rest POST "domains/$_domain/records" "$_namecom_addtxt_json"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") _retvalue=$(printf "%s\n" "$response" | _egrep_o "\"$_sub_domain\"")
if [ "$retcode" ]; then if [ "$_retvalue" ]; then
_info "Successfully added TXT record, ready for validation." _info "Successfully added TXT record, ready for validation."
_namecom_logout
return 0 return 0
else else
_err "Unable to add the DNS record." _err "Unable to add the DNS record."
_namecom_logout
return 1 return 1
fi fi
fi fi
@ -72,37 +70,28 @@ dns_namecom_rm() {
# Find domain in domain list. # Find domain in domain list.
if ! _namecom_get_root "$fulldomain"; then if ! _namecom_get_root "$fulldomain"; then
_err "Unable to find domain specified." _err "Unable to find domain specified."
_namecom_logout
return 1 return 1
fi fi
# Get the record id. # Get the record id.
if _namecom_rest GET "dns/list/$_domain"; then if _namecom_rest GET "domains/$_domain/records"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") _record_id=$(printf "%s\n" "$response" | _egrep_o "\"id\":[0-9]+,\"domainName\":\"$_domain\",\"host\":\"$_sub_domain\",\"fqdn\":\"$fulldomain.\",\"type\":\"TXT\",\"answer\":\"$txtvalue\"" | cut -d \" -f 3 | _egrep_o [0-9]+)
if [ "$retcode" ]; then _debug record_id "$_record_id"
_record_id=$(printf "%s\n" "$response" | _egrep_o "\"record_id\":\"[0-9]+\",\"name\":\"$fulldomain\",\"type\":\"TXT\"" | cut -d \" -f 4) if [ "$_record_id" ]; then
_debug record_id "$_record_id"
_info "Successfully retrieved the record id for ACME challenge." _info "Successfully retrieved the record id for ACME challenge."
else else
_err "Unable to retrieve the record id." _err "Unable to retrieve the record id."
_namecom_logout
return 1 return 1
fi fi
fi fi
# Remove the DNS record using record id. # Remove the DNS record using record id.
_namecom_rmtxt_json="{\"record_id\":\"$_record_id\"}" if _namecom_rest DELETE "domains/$_domain/records/$_record_id"; then
if _namecom_rest POST "dns/delete/$_domain" "$_namecom_rmtxt_json"; then _info "Successfully removed the TXT record."
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") return 0
if [ "$retcode" ]; then else
_info "Successfully removed the TXT record." _err "Unable to delete record id."
_namecom_logout return 1
return 0
else
_err "Unable to remove the DNS record."
_namecom_logout
return 1
fi
fi fi
} }
@ -112,8 +101,9 @@ _namecom_rest() {
param=$2 param=$2
data=$3 data=$3
export _H1="Content-Type: application/json" export _H1="Authorization: Basic $_namecom_auth"
export _H2="Api-Session-Token: $sessionkey" export _H2="Content-Type: application/json"
if [ "$method" != "GET" ]; then if [ "$method" != "GET" ]; then
response="$(_post "$data" "$Namecom_API/$param" "" "$method")" response="$(_post "$data" "$Namecom_API/$param" "" "$method")"
else else
@ -130,20 +120,15 @@ _namecom_rest() {
} }
_namecom_login() { _namecom_login() {
namecom_login_json="{\"username\":\"$Namecom_Username\",\"api_token\":\"$Namecom_Token\"}" # Auth string
# Name.com API v4 uses http basic auth to authenticate
# need to convert the token for http auth
_namecom_auth=$(printf "%s:%s" "$Namecom_Username" "$Namecom_Token" | base64)
if _namecom_rest POST "login" "$namecom_login_json"; then if _namecom_rest GET "hello"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100") retcode=$(printf "%s\n" "$response" | _egrep_o "\"username\"\:\"$Namecom_Username\"")
if [ "$retcode" ]; then if [ "$retcode" ]; then
_info "Successfully logged in. Fetching session token..." _info "Successfully logged in."
sessionkey=$(printf "%s\n" "$response" | _egrep_o "\"session_token\":\".+" | cut -d \" -f 4)
if [ ! -z "$sessionkey" ]; then
_debug sessionkey "$sessionkey"
_info "Session key obtained."
else
_err "Unable to get session key."
return 1
fi
else else
_err "Logging in failed." _err "Logging in failed."
return 1 return 1
@ -151,24 +136,12 @@ _namecom_login() {
fi fi
} }
_namecom_logout() {
if _namecom_rest GET "logout"; then
retcode=$(printf "%s\n" "$response" | _egrep_o "\"code\":100")
if [ "$retcode" ]; then
_info "Successfully logged out."
else
_err "Error logging out."
return 1
fi
fi
}
_namecom_get_root() { _namecom_get_root() {
domain=$1 domain=$1
i=2 i=2
p=1 p=1
if ! _namecom_rest GET "domain/list"; then if ! _namecom_rest GET "domains"; then
return 1 return 1
fi fi