diff --git a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/SettingsController.php b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/SettingsController.php index edc5de0c4..f78611844 100644 --- a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/SettingsController.php +++ b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/Api/SettingsController.php @@ -372,4 +372,22 @@ class SettingsController extends ApiMutableModelControllerBase return $result; } + + /** + * Check wether the Google Cloud plugin is installed. + * @return array status action + */ + public function getGcloudPluginStatusAction() + { + $result = array("result" => "0"); + + $mdlAcme = $this->getModel(); + + // Check if the required plugin is installed + if ((string)$mdlAcme->isPluginInstalled('google-cloud-sdk') == "1") { + $result['result'] = "1"; + } + + return $result; + } } diff --git a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml index 77078e9e9..7da76ac8d 100644 --- a/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml +++ b/security/acme-client/src/opnsense/mvc/app/controllers/OPNsense/AcmeClient/forms/dialogValidation.xml @@ -401,6 +401,30 @@ text + + + header + + + + + info + + + validation.dns_gcloud_key + + textbox + Provide a service account key in JSON format for your Google Cloud account. + + + + header + + + + + info + header diff --git a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml index 91046d2d4..e8cdb2877 100644 --- a/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml +++ b/security/acme-client/src/opnsense/mvc/app/models/OPNsense/AcmeClient/AcmeClient.xml @@ -363,6 +363,7 @@ FreeDNS API Gandi LiveDNS API GoDaddy.com API + Google Cloud DNS API GratisDNS.dk hosting.de API Hurricane Electric @@ -518,6 +519,9 @@ N + + N + N diff --git a/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/validations.volt b/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/validations.volt index 7c5d762d8..fe51b231e 100644 --- a/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/validations.volt +++ b/security/acme-client/src/opnsense/mvc/app/views/OPNsense/AcmeClient/validations.volt @@ -56,6 +56,12 @@ POSSIBILITY OF SUCH DAMAGE. if ($("#validation\\.method").val() == 'dns01') { $("."+service_id).show(); } + // Show a warning if the Google Cloud SDK plugin is missing. + ajaxCall(url="/api/acmeclient/settings/getGcloudPluginStatus", sendData={}, callback=function(data,status) { + if (data['result'] != 0) { + $(".gcloud_plugin_warning").hide(); + } + }); }); $("#validation\\.http_service").change(function(){ var service_id = 'table_http_' + $(this).val(); @@ -72,6 +78,7 @@ POSSIBILITY OF SUCH DAMAGE. $("#validation\\.http_service").change(); }); $("#validation\\.method").change(); + }) }); diff --git a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php index d1a1bd6ee..328900d0a 100755 --- a/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php +++ b/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient/certhelper.php @@ -417,6 +417,7 @@ function run_acme_validation($certObj, $valObj, $acctObj) // Required to run pre-defined commands. $backend = new Backend(); + $modelObj = new OPNsense\AcmeClient\AcmeClient; // Collect account information $account_conf_dir = "/var/etc/acme-client/accounts/" . $acctObj->id; @@ -567,6 +568,7 @@ function run_acme_validation($certObj, $valObj, $acctObj) // Prepare DNS-01 hooks if ($val_method == 'dns01') { // Some common stuff + $val_id = preg_replace("/[^a-zA-Z0-9]/", "", (string)$valObj->id); $secret_key_filename = "${configdir}/secret.key"; $acme_args[] = '--dnssleep ' . $valObj->dns_sleep; @@ -655,6 +657,42 @@ function run_acme_validation($certObj, $valObj, $acctObj) case 'dns_gandi_livedns': $proc_env['GANDI_LIVEDNS_KEY'] = (string)$valObj->dns_gandi_livedns_key; break; + case 'dns_gcloud': + # Google Cloud SDK must be installed. + if ((string)$modelObj->isPluginInstalled('google-cloud-sdk') != "1") { + log_error("AcmeClient: Google Cloud SDK plugin is NOT installed. Please install os-google-cloud-sdk."); + return(1); + } + # We need a valid Google Cloud JSON key. + if (!empty((string)$valObj->dns_gcloud_key)) { + # Extract the gcloud project from the key data. + $_gcloud_data = json_decode((string)$valObj->dns_gcloud_key); + $gcloud_project = $_gcloud_data->project_id; + $gcloud_account = $_gcloud_data->client_email; + if (empty($gcloud_project)) { + log_error("AcmeClient: unable to extract project name from Google Cloud DNS JSON key"); + return(1); + } else { + log_error("AcmeClient: Google Cloud DNS project name: ${gcloud_project}"); + } + } else { + log_error("AcmeClient: no key for Google Cloud DNS was specified"); + return(1); + } + # Preparations for gcloud CLI. + $gcloud_config = "acme-${val_id}"; + $gcloud_key_file = "/tmp/acme_" . (string)$valObj->dns_service . "_${val_id}.json"; + file_put_contents($gcloud_key_file, (string)$valObj->dns_gcloud_key); + chmod($gcloud_key_file, 0600); + $proc_env['CLOUDSDK_ACTIVE_CONFIG_NAME'] = $gcloud_config; + $proc_env['CLOUDSDK_CORE_PROJECT'] = $gcloud_project; + # Ensure that a working gcloud config exists. + run_shell_command("/usr/local/bin/gcloud config configurations create ${gcloud_config}",$proc_env); + run_shell_command("/usr/local/bin/gcloud config configurations activate ${gcloud_config}",$proc_env); + run_shell_command("/usr/local/bin/gcloud auth activate-service-account --key-file=${gcloud_key_file}",$proc_env); + run_shell_command("/usr/local/bin/gcloud config set account ${gcloud_account}",$proc_env); + run_shell_command("/usr/local/bin/gcloud config set project ${gcloud_project}",$proc_env); + break; case 'dns_gd': $proc_env['GD_Key'] = (string)$valObj->dns_gd_key; $proc_env['GD_Secret'] = (string)$valObj->dns_gd_secret; @@ -1244,6 +1282,32 @@ function dump_postponed_updates() } } +function run_shell_command($proc_cmd, $proc_env = array()) +{ + $proc_desc = array( // descriptor array for proc_open() + 0 => array("pipe", "r"), // stdin + 1 => array("pipe", "w"), // stdout + 2 => array("pipe", "w") // stderr + ); + $proc_pipes = array(); + $proc = proc_open($proc_cmd, $proc_desc, $proc_pipes, null, $proc_env); + + // Make sure the resource could be setup properly + if (is_resource($proc)) { + // Close all pipes + fclose($proc_pipes[0]); + fclose($proc_pipes[1]); + fclose($proc_pipes[2]); + // Get exit code + $result = proc_close($proc); + log_error(sprintf("AcmeClient: The shell command '%s' returned exit code '%d'", $proc_cmd, $result)); + return($result); + } else { + log_error(sprintf("AcmeClient: Unable to prepare shell command '%s'",$proc_cmd)); + return(1); + } +} + // taken from certs.inc function local_cert_get_subject_array($str_crt, $decode = true) {