Acme & cPanel/WHM
I am seeking for a way to automatically copy my Let's Encrypt certificate from my cPanel host to pfSense. cPanel does the auto-renewal for this (wildcard) certificate.
I copied the certificate manually by opening a FTP session to my cPanel host and grabbing the lets-encrypt config file from my domain.
The certificate data is stored as JSON in file /.cpanel/nvdata/letsencrypt-cpanel. This file holds every certificate requested by the Let's encrypt plugin in cPanel. I have manually extracted the private and public key (for my wildcard domain *.lan.domain.com) and inserted these in pfSense. This seems to work great. The router and even my captive portal have a valid certificate now. Great!
Next step is to automate the renewal process... Do I need to write a pfSense plugin for this? Or am I overlooking something?
I still have to figure out if I need to copy the private key again after a certificate renewal. I assume that the private key stays the same and I only need the public key to be renewed on pfSense. Which would be easier as I can grab this key from an https request.
What would be the best option to automate these renewals with a host running on cPanel/WHM? Any advice?
Sincerely yours, VinzzB
I have never developed on freenas or pfSense before so i am searching for good (and easy) ways to accomplish my task.
I just discovered the PHP shell and i made a small script to download the json file from my host. This seems to work just fine.
Now i need to parse this json file and extract the necessary ssl keys (public/private/issuer). This should be an easy one. But the next step is still unknown territory for me.
How can i replace a certificate in pfSense within this PHP shell?
Can i run this script as a cronjob (including the php pfsense tools)?
This is the code i have so far (downloading file through FTPS protocol):
<?php $ftp_server = 'ftp.domain.com'; $local_file = '/home/letsencrypt-cpanel'; $server_file = '/.cpanel/nvdata/letsencrypt-cpanel'; $ftp_user_name = 'username'; $ftp_user_pass = 'password'; $conn_id = ftp_ssl_connect($ftp_server); $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass); ftp_pasv($conn_id, true); if (!$login_result) die("can't login"); if (ftp_get($conn_id, $local_file, $server_file, FTP_BINARY)) echo "Successfully written to $local_file\n"; else echo "There was a problem\n"; ftp_close($conn_id);
I will update this post when i got more stuff working. (json parser, updating certs on pfsense)
I've completed my small php script and it seems to work well.
This is the result in case anyone needs it:
// -- CONFIG $certname = 'lan.domain.com'; //a registered FQDN in cPanel with acme let's encrypt enabled (wildcard cert) $pfsense_cert_id = 1; // certificate id in pfsense to overwrite. (The correct ID can be found by hovering over an icon in the cert manager or by looking in the config file. $ftp_server = 'ftp.domain.com'; //ftps location to your domain (cpanel). $ftp_user_name = ''; $ftp_user_pass = ''; $server_file = '/.cpanel/nvdata/letsencrypt-cpanel'; //download file used by cPanel holding every certificate (in JSON format). // -- PROGRAM $conn_id = ftp_ssl_connect($ftp_server); $login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass); ftp_pasv($conn_id, true); if (!$login_result) die("can't login"); ob_start(); $dataLoaded = ftp_get($conn_id, "php://output", $server_file, FTP_BINARY); $data = ob_get_contents(); ob_end_clean(); ftp_close($conn_id); if (!$dataLoaded) die("There was a problem downloading the json data from $ftp_server"); $jsonData = json_decode($data, true); $cert = $jsonData['certs'][$certname]; if(empty($cert)) die("Certificate with name $certname not found"); $config['cert'][$pfsense_cert_id ]['prv'] = base64_encode($cert['key']); $config['cert'][$pfsense_cert_id ]['crt'] = base64_encode($cert['cert']); write_config(); exec('/etc/rc.restart_webgui'); //echo 'Certificate:', PHP_EOL, $cert['cert'], PHP_EOL; //echo 'Key:', PHP_EOL, $cert['key'], PHP_EOL; echo 'New certificate for ', $certname, ' is valid untill ', gmdate('r',$cert['cert_expiry']), PHP_EOL; exit;
I've uploaded the file (named sslupdate) to the /etc/phpshellsessions directory in pfsense and I added the following cron job (through the cron package):
0 0 1 1/3 * : /usr/local/sbin/pfSsh.php playback sslupdate