Initial support for Synology DSM

This allows you to update a key on a Synology DSM using the existing API.
Handles restarting the necessary services the certificate is attached to and all other internal stuff (copying the certificate around, etc.)

This is way less error prone than most articles I've found on how to update a Synology DSM certificate.
This commit is contained in:
Brian Hartvigsen 2019-06-29 21:47:24 -06:00
parent 8e6c4e1aca
commit 555e0de9e4
No known key found for this signature in database
GPG Key ID: 46EEA32081255BEB
1 changed files with 145 additions and 0 deletions

145
deploy/synology_dsm.sh Normal file
View File

@ -0,0 +1,145 @@
#!/usr/bin/env sh
# Here is a script to deploy cert to Synology DSM vault
# (https://www.vaultproject.io/)
#
# it requires the jq and curl are in the $PATH and the following
# environment variables must be set:
#
# SYNO_Username - Synology Username to login (must be an administrator)
# SYNO_Password - Synology Password to login
# SYNO_Certificate - Certificate description to target for replacement
#
# The following environmental variables may be set if you don't like their
# default values:
#
# SYNO_Scheme - defaults to http
# SYNO_Hostname - defaults to localhost
# SYNO_Port - defaults to 5000
#
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
synology_dsm_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_debug _cdomain "$_cdomain"
# Get Username and Password, but don't save until we successfully authenticate
SYNO_Username="${SYNO_Username:-$(_readaccountconf_mutable SYNO_Username)}"
SYNO_Password="${SYNO_Password:-$(_readaccountconf_mutable SYNO_Password)}"
if [ -z "$SYNO_Username" ] || [ -z "$SYNO_Password" ]; then
SYNO_Username=""
SYNO_Password=""
_err "SYNO_Username & SYNO_Password must be set"
return 1
fi
_debug2 SYNO_Username "$SYNO_Username"
_secure_debug2 SYNO_Password "$SYNO_Password"
# Optional scheme, hostname, and port for Synology DSM
SYNO_Scheme="${SYNO_Scheme:-$(_readaccountconf_mutable SYNO_Scheme)}"
SYNO_Hostname="${SYNO_Hostname:-$(_readaccountconf_mutable SYNO_Hostname)}"
SYNO_Port="${SYNO_Port:-$(_readaccountconf_mutable SYNO_Port)}"
_saveaccountconf_mutable SYNO_Scheme "$SYNO_Scheme"
_saveaccountconf_mutable SYNO_Hostname "$SYNO_Hostname"
_saveaccountconf_mutable SYNO_Port "$SYNO_Port"
# default vaules for scheme, hostname, and port
# defaulting to localhost and http because it's localhost...
[ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
[ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
[ -n "${SYNO_Port}" ] || SYNO_Port="5000"
_debug2 SYNO_Scheme "$SYNO_Scheme"
_debug2 SYNO_Hostname "$SYNO_Hostname"
_debug2 SYNO_Port "$SYNO_Port"
# Get the certificate description, but don't save it until we verfiy it's real
_getdeployconf SYNO_Certificate
if [ -z "${SYNO_Certificate}" ]; then
_err "SYNO_Certificate needs to be defined (with the Certificate description name)"
return 1
fi
_debug SYNO_Certificate "$SYNO_Certificate"
# We can't use _get or _post because they lack support for cookies
# use jq because I'm too lazy to figure out what is required to parse json
# by hand. Also it seems to be in place for Synology DSM (6.2.1 at least)
for x in curl jq; do
if ! _exists "$x"; then
_err "Please install $x first."
_err "We need $x to work."
return 1
fi
done
_base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
_debug _base_url "$_base_url"
_cookie_jar="$(_mktemp)"
_debug _cookie_jar "$_cookie_jar"
# Login, get the token from JSON and session id from cookie
_debug "Logging into $SYNO_Hostname:$SYNO_Port"
token=$(curl -sk -c $_cookie_jar "$_base_url/webman/login.cgi?username=$SYNO_Username&passwd=$SYNO_Password&enable_syno_token=yes" | jq -r .SynoToken)
if [ $token = "null" ]; then
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
_err "Check your username and password."
rm "$_cookie_jar"
return 1
fi
# Now that we know the username and password are good, save them
_saveaccountconf_mutable SYNO_Username "$SYNO_Username"
_saveaccountconf_mutable SYNO_Password "$SYNO_Password"
_secure_debug2 token "$token"
# Use token and session id to get the list of certificates
response=$(curl -sk -b $_cookie_jar $_base_url/webapi/entry.cgi -H "X-SYNO-TOKEN: $token" -d api=SYNO.Core.Certificate.CRT -d method=list -d version=1)
_debug3 response "$response"
# select the first certificate matching our description
cert=$(echo "$response" | jq -r ".data.certificates | map(select(.desc == \"$SYNO_Certificate\"))[0]")
_debug3 cert "$cert"
if [ "$cert" = "null" ]; then
_err "Unable to find certificate: $SYNO_Certificate"
rm "$_cookie_jar"
return 1
fi
# we've verified this certificate description is a thing, so save it
_savedeployconf SYNO_Certificate "$SYNO_Certificate"
id=$(echo $cert | jq -r ".id")
default=$(echo "$cert" | jq -r ".is_default")
_debug2 id "$id"
_debug2 default "$default"
# This is the heavy lifting, make the API call to update a certificate in place
response=$(curl -sk -b $_cookie_jar "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token" -F key=@$_ckey -F cert=@$_ccert -F inter_cert=@$_cca -F id=$id -F desc=$SYNO_Certificate -F as_default=$default)
_debug3 response "$response"
success=$(echo "$response" | jq -r ".success")
_debug2 success "$success"
rm "$_cookie_jar"
if [ "$success" = "true" ]; then
restarted=$(echo "$response" | jq -r ".data.restart_httpd")
if [ "$restarted" = "true" ]; then
_info "http services were restarted"
else
_info "http services were NOT restarted"
fi
return 0;
else
code=$(echo "$response" | jq -r ".error.code")
_err "Unable to update certificate, error code $code"
return 1
fi
}