diff --git a/Dockerfile b/Dockerfile index 36b2adac..15439e5a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,12 +14,14 @@ RUN apk --no-cache add -f \ libidn \ jq \ yq-go \ - cronie + supercronic ENV LE_WORKING_DIR=/acmebin ENV LE_CONFIG_HOME=/acme.sh +ENV HOME=/acme.sh + ARG AUTO_UPGRADE=1 ENV AUTO_UPGRADE=$AUTO_UPGRADE @@ -30,10 +32,13 @@ COPY ./deploy /install_acme.sh/deploy COPY ./dnsapi /install_acme.sh/dnsapi COPY ./notify /install_acme.sh/notify +RUN addgroup -g 1000 acme && adduser -h $LE_CONFIG_HOME -s /bin/sh -G acme -D -H -u 1000 acme + RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ +RUN ln -s $LE_WORKING_DIR/acme.sh /usr/local/bin/acme.sh -RUN ln -s $LE_WORKING_DIR/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab - +RUN chown -R acme:acme $LE_CONFIG_HOME RUN for verb in help \ version \ @@ -72,7 +77,15 @@ RUN for verb in help \ RUN printf "%b" '#!'"/usr/bin/env sh\n \ if [ \"\$1\" = \"daemon\" ]; then \n \ - exec crond -n -s -m off \n \ + if [ ! -f \"\$LE_CONFIG_HOME/crontab\" ]; then \n \ + echo \"\$LE_CONFIG_HOME/crontab not found, generating one\" \n \ + time=\$(date -u \"+%s\") \n \ + random_minute=\$((\$time % 60)) \n \ + random_hour=\$((\$time / 60 % 24)) \n \ + echo \"\$random_minute \$random_hour * * * \\\"\$LE_WORKING_DIR\\\"/acme.sh --cron --home \\\"\$LE_WORKING_DIR\\\" --config-home \\\"\$LE_CONFIG_HOME\\\"\" > \"\$LE_CONFIG_HOME\"/crontab \n \ + fi \n \ + echo \"Running Supercronic using crontab at \$LE_CONFIG_HOME/crontab\" \n \ + exec -- /usr/bin/supercronic \"\$LE_CONFIG_HOME/crontab\" \n \ else \n \ exec -- \"\$@\"\n \ fi\n" >/entry.sh && chmod +x /entry.sh && chmod -R o+rwx $LE_WORKING_DIR && chmod -R o+rwx $LE_CONFIG_HOME diff --git a/deploy/panos.sh b/deploy/panos.sh index c54d21fe..019d8c62 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -207,13 +207,12 @@ panos_deploy() { fi # PANOS_KEY - _getdeployconf PANOS_KEY if [ "$PANOS_KEY" ]; then - _debug "Detected saved key." - _panos_key=$PANOS_KEY + _debug "Detected ENV variable PANOS_KEY. Saving to file." + _savedeployconf PANOS_KEY "$PANOS_KEY" 1 else - _debug "No key detected" - unset _panos_key + _debug "Attempting to load variable PANOS_KEY from file." + _getdeployconf PANOS_KEY fi # PANOS_TEMPLATE @@ -256,6 +255,7 @@ panos_deploy() { _panos_host=$PANOS_HOST _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS + _panos_key=$PANOS_KEY _panos_template=$PANOS_TEMPLATE _panos_template_stack=$PANOS_TEMPLATE_STACK _panos_vsys=$PANOS_VSYS @@ -271,12 +271,6 @@ panos_deploy() { if [ -z "$_panos_host" ]; then _err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs." return 1 - elif [ -z "$_panos_user" ]; then - _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs." - return 1 - elif [ -z "$_panos_pass" ]; then - _err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs." - return 1 else # Use certificate name based on the first domain on the certificate if no custom certificate name is set if [ -z "$_panos_certname" ]; then @@ -286,6 +280,13 @@ panos_deploy() { # Generate a new API key if no valid API key is found if [ -z "$_panos_key" ]; then + if [ -z "$_panos_user" ]; then + _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs." + return 1 + elif [ -z "$_panos_pass" ]; then + _err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs." + return 1 + fi _debug "**** Generating new PANOS API KEY ****" deployer keygen _savedeployconf PANOS_KEY "$_panos_key" 1 diff --git a/deploy/ssh.sh b/deploy/ssh.sh index c66e2e19..848380a5 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -238,6 +238,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d return $_err_code fi else + # If file doesn't exist, create it and change its permissions. + _cmdstr="$_cmdstr test ! -f $DEPLOY_SSH_KEYFILE && touch $DEPLOY_SSH_KEYFILE && chmod 600 $DEPLOY_SSH_KEYFILE;" # ssh echo to the file _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;" _info "will copy private key to remote file $DEPLOY_SSH_KEYFILE" diff --git a/dnsapi/dns_infomaniak.sh b/dnsapi/dns_infomaniak.sh index ea5ef461..0ae32b47 100755 --- a/dnsapi/dns_infomaniak.sh +++ b/dnsapi/dns_infomaniak.sh @@ -6,14 +6,16 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_infomaniak Options: INFOMANIAK_API_TOKEN API Token Issues: github.com/acmesh-official/acme.sh/issues/3188 + ' -# To use this API you need visit the API dashboard of your account -# once logged into https://manager.infomaniak.com add /api/dashboard to the URL -# +# To use this API you need visit the API dashboard of your account. # Note: the URL looks like this: -# https://manager.infomaniak.com/v3//api/dashboard -# Then generate a token with the scope Domain +# https://manager.infomaniak.com/v3//ng/profile/user/token/list +# Then generate a token with following scopes : +# - domain:read +# - dns:read +# - dns:write # this is given as an environment variable INFOMANIAK_API_TOKEN # base variables @@ -65,33 +67,32 @@ dns_infomaniak_add() { _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" - fqdn=${fulldomain#_acme-challenge.} - # guess which base domain to add record to - zone_and_id=$(_find_zone "$fqdn") - if [ -z "$zone_and_id" ]; then - _err "cannot find zone to modify" + zone=$(_get_zone "$fulldomain") + if [ -z "$zone" ]; then + _err "cannot find zone:<${zone}> to modify" return 1 fi - zone=${zone_and_id% *} - domain_id=${zone_and_id#* } # extract first part of domain key=${fulldomain%."$zone"} - _debug "zone:$zone id:$domain_id key:$key" + _debug "key:$key" + _debug "txtvalue: $txtvalue" # payload data="{\"type\": \"TXT\", \"source\": \"$key\", \"target\": \"$txtvalue\", \"ttl\": $INFOMANIAK_TTL}" # API call - response=$(_post "$data" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record") - if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then - _info "Record added" - _debug "Response: $response" - return 0 + response=$(_post "$data" "${INFOMANIAK_API_URL}/2/zones/${zone}/records") + if [ -n "$response" ]; then + if [ ! "$(echo "$response" | _contains '"result":"success"')" ]; then + _info "Record added" + _debug "response: $response" + return 0 + fi fi - _err "could not create record" + _err "Could not create record." _debug "Response: $response" return 1 } @@ -106,7 +107,7 @@ dns_infomaniak_rm() { if [ -z "$INFOMANIAK_API_TOKEN" ]; then INFOMANIAK_API_TOKEN="" - _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN" + _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN." return 1 fi @@ -138,63 +139,53 @@ dns_infomaniak_rm() { _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" - fqdn=${fulldomain#_acme-challenge.} - # guess which base domain to add record to - zone_and_id=$(_find_zone "$fqdn") - if [ -z "$zone_and_id" ]; then - _err "cannot find zone to modify" + zone=$(_get_zone "$fulldomain") + if [ -z "$zone" ]; then + _err "cannot find zone:<$zone> to modify" return 1 fi - zone=${zone_and_id% *} - domain_id=${zone_and_id#* } # extract first part of domain key=${fulldomain%."$zone"} + key=$(echo "$key" | _lower_case) - _debug "zone:$zone id:$domain_id key:$key" + _debug "zone:$zone" + _debug "key:$key" # find previous record - # shellcheck disable=SC1004 - record_id=$(_get "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}\ -{/g' | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source_idn":"'"$fulldomain"'".*"target_idn":"'"$txtvalue"'".*/\1/p') + # shellcheck disable=SC2086 + response=$(_get "${INFOMANIAK_API_URL}/2/zones/${zone}/records" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}{/g') + record_id=$(echo "$response" | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source":"'"$key"'".*"target":"\\"'"$txtvalue"'\\"".*/\1/p') + _debug "key: $key" + _debug "txtvalue: $txtvalue" + _debug "record_id: $record_id" + if [ -z "$record_id" ]; then _err "could not find record to delete" + _debug "response: $response" return 1 fi - _debug "record_id: $record_id" # API call - response=$(_post "" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record/$record_id" "" DELETE) - if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then - _info "Record deleted" - return 0 + response=$(_post "" "${INFOMANIAK_API_URL}/2/zones/${zone}/records/${record_id}" "" DELETE) + if [ -n "$response" ]; then + if [ ! "$(echo "$response" | _contains '"result":"success"')" ]; then + _info "Record deleted" + return 0 + fi fi - _err "could not delete record" + _err "Could not delete record." + _debug "Response: $response" return 1 } #################### Private functions below ################################## -_get_domain_id() { +_get_zone() { domain="$1" - + # Whatever the domain is, you can get the fqdn with the following. # shellcheck disable=SC1004 - _get "${INFOMANIAK_API_URL}/1/product?service_name=domain&customer_name=$domain" | sed 's/.*"data":\[{\(.*\)}\]}/\1/; s/,/\ -/g' | sed -n 's/^"id":\(.*\)/\1/p' -} - -_find_zone() { - zone="$1" - - # find domain in list, removing . parts sequentialy - while _contains "$zone" '\.'; do - _debug "testing $zone" - id=$(_get_domain_id "$zone") - if [ -n "$id" ]; then - echo "$zone $id" - return - fi - zone=${zone#*.} - done + response=$(_get "${INFOMANIAK_API_URL}/2/domains/${domain}/zones" | sed 's/.*\[{"fqdn"\:"\(.*\)/\1/') + echo "${response%%\"*}" } diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index d5dbbcbc..9b14553b 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -6,7 +6,7 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_nsupdate Options: NSUPDATE_SERVER Server hostname. Default: "localhost". NSUPDATE_SERVER_PORT Server port. Default: "53". - NSUPDATE_KEY File path to TSIG key. + NSUPDATE_KEY File path to TSIG key. Default: "" NSUPDATE_ZONE Domain zone to update. Optional. ' @@ -22,8 +22,6 @@ dns_nsupdate_add() { NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" NSUPDATE_OPT="${NSUPDATE_OPT:-$(_readaccountconf_mutable NSUPDATE_OPT)}" - _checkKeyFile || return 1 - # save the dns server and key to the account conf file. _saveaccountconf_mutable NSUPDATE_SERVER "${NSUPDATE_SERVER}" _saveaccountconf_mutable NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" @@ -33,6 +31,7 @@ dns_nsupdate_add() { [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 + [ -n "${NSUPDATE_KEY}" ] || NSUPDATE_KEY="" [ -n "${NSUPDATE_OPT}" ] || NSUPDATE_OPT="" _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" @@ -40,19 +39,36 @@ dns_nsupdate_add() { [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" if [ -z "${NSUPDATE_ZONE}" ]; then #shellcheck disable=SC2086 - nsupdate -k "${NSUPDATE_KEY}" $nsdebug $NSUPDATE_OPT <