Skip to content
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

security/pfSense-pkg-acme: support deploy hooks. Implement #11827 #1298

Closed
wants to merge 1 commit into from
Closed
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
5 changes: 4 additions & 1 deletion security/pfSense-pkg-acme/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# $FreeBSD$

PORTNAME= pfSense-pkg-acme
PORTVERSION= 0.7.5
PORTVERSION= 0.8.5
CATEGORIES= security
MASTER_SITES= # empty
DISTFILES= # empty
Expand Down Expand Up @@ -29,6 +29,7 @@ do-extract:
${MKDIR} ${WRKSRC}

do-install:
${MKDIR} ${STAGEDIR}${PREFIX}/pkg/acme/deploy
${MKDIR} ${STAGEDIR}${PREFIX}/pkg/acme/dnsapi
${MKDIR} ${STAGEDIR}${PREFIX}/www/acme
${MKDIR} ${STAGEDIR}/etc/inc/priv
Expand All @@ -53,6 +54,8 @@ do-install:
${STAGEDIR}${PREFIX}/pkg/acme
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/acme/pkg_acme_tabs.inc \
${STAGEDIR}${PREFIX}/pkg/acme
${INSTALL_SCRIPT} ${FILESDIR}${PREFIX}/pkg/acme/deploy/*.sh \
${STAGEDIR}${PREFIX}/pkg/acme/deploy
${INSTALL_SCRIPT} ${FILESDIR}${PREFIX}/pkg/acme/dnsapi/dns_*.sh \
${STAGEDIR}${PREFIX}/pkg/acme/dnsapi
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/acme/acme_accountkeys.php \
Expand Down
27 changes: 27 additions & 0 deletions security/pfSense-pkg-acme/files/usr/local/pkg/acme/acme.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1497,11 +1497,32 @@ $acme_domain_validation_method['http-post'] = array('name' => "http-post",
*/

//TODO add more 'actions'
$deployhooks = array_map(function($path){
return pathinfo($path)['filename'];
}, glob('../../pkg/acme/deploy/*.sh'));
$acme_newcertificateactions = array(
'shellcommand' => array('name' => "Shell Command"),
'php_command' => array('name' => "PHP Command Script"),
'servicerestart' => array('name' => "Restart Local Service"),
'xmlrpcservicerestart' => array('name' => "Restart Remote Service (XMLRPC)"),
'deployhook' => array('name' => "acme.sh deploy hook",
'fields' => array(
'script' => array(
'name' => 'script',
'columnheader' => 'Script',
'type' => 'select',
'items' => array_combine($deployhooks, array_map(function($hook) {
return array('name' => $hook);
}, $deployhooks))
),
'environment' => array(
'name' => 'environment',
'columnheader' => 'Environment <a href="https://github.com/acmesh-official/acme.sh/wiki/deployhooks"><i class="fa fa-book"></i></a>',
'description' => 'Each line may contain one variable assignment of the form <tt>KEY=VALUE</tt>.<br>Lines starting with <tt>#</tt> will be ignored.',
'type' => 'textarea',
),
),
),
);

// </editor-fold>
Expand Down Expand Up @@ -1962,4 +1983,10 @@ function & get_certificate($name) {
}
}
}

function deploy_certificate($domain, $hook, $envvariables) {
$account = get_accountkey($certificate['acmeaccount']);
$acmesh = new acme_sh($domain, $$a_acmeserver[$account['acmeserver']]['url'], $account['email']);
return $acmesh->deployCertificate($domain, $hook, $envvariables);
}
}
13 changes: 13 additions & 0 deletions security/pfSense-pkg-acme/files/usr/local/pkg/acme/acme_command.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ if ($command == "importcert") {
acme_xmlrpc_restart_service($servicename, $extras);
}
}
if ($action['method'] == "deployhook") {
syslog(LOG_NOTICE, "Acme, Running deploy hook {$action['deployhookscript']}");
$envvariables = array();
foreach (preg_split("/\R/", base64_decode($action['deployhookenvironment'])) as $line) {
$array = explode("=", $line);
if (count($array) > 1) {
$key = $array[0];
if (!str_starts_with($key, "#"))
$envvariables[$key] = implode("=", array_slice($array, 1));
}
}
deploy_certificate($certificatename, $action['deployhookscript'], $envvariables);
}
}
}
return;
Expand Down
10 changes: 10 additions & 0 deletions security/pfSense-pkg-acme/files/usr/local/pkg/acme/acme_sh.inc
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,14 @@ EOD;
}
return false;
}

function deployCertificate($domain, $hook, $envvariables) {
$this->execacmesh(""
. " --deploy"
. " --domain " . escapeshellarg($domain)
. " --deploy-hook " . escapeshellarg($hook)
. " --accountconf " . escapeshellarg($this->accountconfig)
. " --home " . escapeshellarg($this->acmeconf)
, $envvariables);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env sh

#Here is a script to deploy cert to apache server.

#returns 0 means success, otherwise error.

######## Public functions #####################

#domain keyfile certfile cafile fullchain
apache_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"

_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"

_err "Deploy cert to apache server, Not implemented yet"
return 1

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env sh
# Here is the script to deploy the cert to your CleverReach Account using the CleverReach REST API.
# Your OAuth needs the right scope, please contact CleverReach support for that.
#
# Written by Jan-Philipp Benecke <[email protected]>
# Public domain, 2020
#
# Following environment variables must be set:
#
#export DEPLOY_CLEVERREACH_CLIENT_ID=myid
#export DEPLOY_CLEVERREACH_CLIENT_SECRET=mysecret

cleverreach_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"

_rest_endpoint="https://rest.cleverreach.com"

_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"

_getdeployconf DEPLOY_CLEVERREACH_CLIENT_ID
_getdeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET
_getdeployconf DEPLOY_CLEVERREACH_SUBCLIENT_ID

if [ -z "${DEPLOY_CLEVERREACH_CLIENT_ID}" ]; then
_err "CleverReach Client ID is not found, please define DEPLOY_CLEVERREACH_CLIENT_ID."
return 1
fi
if [ -z "${DEPLOY_CLEVERREACH_CLIENT_SECRET}" ]; then
_err "CleverReach client secret is not found, please define DEPLOY_CLEVERREACH_CLIENT_SECRET."
return 1
fi

_savedeployconf DEPLOY_CLEVERREACH_CLIENT_ID "${DEPLOY_CLEVERREACH_CLIENT_ID}"
_savedeployconf DEPLOY_CLEVERREACH_CLIENT_SECRET "${DEPLOY_CLEVERREACH_CLIENT_SECRET}"
_savedeployconf DEPLOY_CLEVERREACH_SUBCLIENT_ID "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}"

_info "Obtaining a CleverReach access token"

_data="{\"grant_type\": \"client_credentials\", \"client_id\": \"${DEPLOY_CLEVERREACH_CLIENT_ID}\", \"client_secret\": \"${DEPLOY_CLEVERREACH_CLIENT_SECRET}\"}"
_auth_result="$(_post "$_data" "$_rest_endpoint/oauth/token.php" "" "POST" "application/json")"

_debug _data "$_data"
_debug _auth_result "$_auth_result"

_regex=".*\"access_token\":\"\([-._0-9A-Za-z]*\)\".*$"
_debug _regex "$_regex"
_access_token=$(echo "$_auth_result" | _json_decode | sed -n "s/$_regex/\1/p")

_debug _subclient "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}"

if [ -n "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}" ]; then
_info "Obtaining token for sub-client ${DEPLOY_CLEVERREACH_SUBCLIENT_ID}"
export _H1="Authorization: Bearer ${_access_token}"
_subclient_token_result="$(_get "$_rest_endpoint/v3/clients/$DEPLOY_CLEVERREACH_SUBCLIENT_ID/token")"
_access_token=$(echo "$_subclient_token_result" | sed -n "s/\"//p")

_debug _subclient_token_result "$_access_token"

_info "Destroying parent token at CleverReach, as it not needed anymore"
_destroy_result="$(_post "" "$_rest_endpoint/v3/oauth/token.json" "" "DELETE" "application/json")"
_debug _destroy_result "$_destroy_result"
fi

_info "Uploading certificate and key to CleverReach"

_certData="{\"cert\":\"$(_json_encode <"$_cfullchain")\", \"key\":\"$(_json_encode <"$_ckey")\"}"
export _H1="Authorization: Bearer ${_access_token}"
_add_cert_result="$(_post "$_certData" "$_rest_endpoint/v3/ssl" "" "POST" "application/json")"

if [ -z "${DEPLOY_CLEVERREACH_SUBCLIENT_ID}" ]; then
_info "Destroying token at CleverReach, as it not needed anymore"
_destroy_result="$(_post "" "$_rest_endpoint/v3/oauth/token.json" "" "DELETE" "application/json")"
_debug _destroy_result "$_destroy_result"
fi

if ! echo "$_add_cert_result" | grep '"error":' >/dev/null; then
_info "Uploaded certificate successfully"
return 0
else
_debug _add_cert_result "$_add_cert_result"
_err "Unable to update certificate"
return 1
fi
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env sh

# Here is a script to deploy cert to hashicorp consul using curl
# (https://www.consul.io/)
#
# it requires following environment variables:
#
# CONSUL_PREFIX - this contains the prefix path in consul
# CONSUL_HTTP_ADDR - consul requires this to find your consul server
#
# additionally, you need to ensure that CONSUL_HTTP_TOKEN is available
# to access the consul server

#returns 0 means success, otherwise error.

######## Public functions #####################

#domain keyfile certfile cafile fullchain
consul_deploy() {

_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"

_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"

# validate required env vars
_getdeployconf CONSUL_PREFIX
if [ -z "$CONSUL_PREFIX" ]; then
_err "CONSUL_PREFIX needs to be defined (contains prefix path in vault)"
return 1
fi
_savedeployconf CONSUL_PREFIX "$CONSUL_PREFIX"

_getdeployconf CONSUL_HTTP_ADDR
if [ -z "$CONSUL_HTTP_ADDR" ]; then
_err "CONSUL_HTTP_ADDR needs to be defined (contains consul connection address)"
return 1
fi
_savedeployconf CONSUL_HTTP_ADDR "$CONSUL_HTTP_ADDR"

CONSUL_CMD=$(command -v consul)

# force CLI, but the binary does not exist => error
if [ -n "$USE_CLI" ] && [ -z "$CONSUL_CMD" ]; then
_err "Cannot find the consul binary!"
return 1
fi

# use the CLI first
if [ -n "$USE_CLI" ] || [ -n "$CONSUL_CMD" ]; then
_info "Found consul binary, deploying with CLI"
consul_deploy_cli "$CONSUL_CMD" "$CONSUL_PREFIX"
else
_info "Did not find consul binary, deploying with API"
consul_deploy_api "$CONSUL_HTTP_ADDR" "$CONSUL_PREFIX" "$CONSUL_HTTP_TOKEN"
fi
}

consul_deploy_api() {
CONSUL_HTTP_ADDR="$1"
CONSUL_PREFIX="$2"
CONSUL_HTTP_TOKEN="$3"

URL="$CONSUL_HTTP_ADDR/v1/kv/$CONSUL_PREFIX"
export _H1="X-Consul-Token: $CONSUL_HTTP_TOKEN"

if [ -n "$FABIO" ]; then
_post "$(cat "$_cfullchain")" "$URL/${_cdomain}-cert.pem" '' "PUT" || return 1
_post "$(cat "$_ckey")" "$URL/${_cdomain}-key.pem" '' "PUT" || return 1
else
_post "$(cat "$_ccert")" "$URL/${_cdomain}/cert.pem" '' "PUT" || return 1
_post "$(cat "$_ckey")" "$URL/${_cdomain}/cert.key" '' "PUT" || return 1
_post "$(cat "$_cca")" "$URL/${_cdomain}/chain.pem" '' "PUT" || return 1
_post "$(cat "$_cfullchain")" "$URL/${_cdomain}/fullchain.pem" '' "PUT" || return 1
fi
}

consul_deploy_cli() {
CONSUL_CMD="$1"
CONSUL_PREFIX="$2"

if [ -n "$FABIO" ]; then
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}-cert.pem" @"$_cfullchain" || return 1
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}-key.pem" @"$_ckey" || return 1
else
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
fi
}
Loading