Categories
Generally Sysadmin Technologies

Let’s Encrypt: Public Beta – Starting with today, Let’s Encrypt is now open for everyone – Update

In the past Let’s Encrypt was only available via an invitation or by signing up to a waiting list. Starting with today Let’s Encrypt entered public beta meaning everybody can now start creating their own free certificates. General information regarding Let’s Encrypt and the differences over other CAs are covered in the article: “Let’s Encrypt initiative enters beta stage on December 3rd 2015“. Now we will start to create our own free domain validated certificates.

Preliminary notes

Let’s Encrypt introduces a now protocoll called “ACME”. Pun may be inteneded. The Let’s Encrypt client communicates via “ACME” with the Let’s Encrypt CA server to start the validation process. The client is already available and easily downloaded using git. This client is able to automatically request and install certificates for all domains used on a server.

Let’s Encrypt certificates are only valid for 90 days. Therefore it’s important to establish a automated renewal process to avoid expired certificates.

Installing the Let’s Encrypt Client

The Client can be downloaded from Github. The current version number is 0.5.0. The git command line tool is needed for that.

cd /opt
sudo git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

The letsencrypt client itself is based on Python. During the first start it attempts to install any required Python packages automatically.

A list of all available options can be displayed using the –help all paramenter.

The various certificate request methods

The Let’s Encrypt client has several modes to request and validate certificates. It can use an Apache PlugIn, a stand alone webserver as well as simple files places in the document root of each domain. Stand alone requires the regular webserver to be shut down, to allow access to port 80 on the machine. All other methods doesn’t require a service interruption.

Automated certificates

If the client ist started without any paramters it will try to guess the type of webserver as well as the configured domains. A list of all the domains found is shown to select the once for which certificates should be requested.

cd /opt/letsencrypt
./letsencrypt-auto

This should be used with caution. If the configuration is a little out of the ordinary, the configuration may fail and has to be fixed manually. Backing up the configuration should be the first step prior to this.

Manual installation with files places in the document root

This working mode simply creates some files in the domains document root folder. This files are read by the CA server to validate the domain and the certificate is issued. This is more or less one of the standard procedures of domain validated certificates besides sending mails to postmaster@domain.tld.

There might be an issue if the domain uses rewrites because of search engine friendly URLs. In that case the CA server might not be able to read the files.

cd /opt/letsencrypt
./letsencrypt-auto certonly -d domain.tld --webroot

The certonly tells the client to not install the certificates. The option webroot (servers document root) tells to store the files in the document root folder of domain domain.tld. If the client cannot found the document root it can be specified using –webroot-path=/var/www/…

The certificate will then be stored in /etc/letsencrypt/live/domain.tld/. With the same methode the certificate for this blog was issued as well.

Multiple domains and subdomains.

We can also create a cert for multiple domains

cd /opt/letsencrypt
./letsencrypt-auto certonly -d domain.tld -d www.domain.tld -d mail.domain.tld --webroot -w /var/www/domain.tld/htdocs

The standalone mode

To avoid any problems regarding the webserver software, the client can also work in standalone mode, simulating a webserver.

./letsencrypt-auto certonly --standalone -d domain.tld

For this to work, the letsencrypt client must be able to bind to TCP port 80 on our server. Meaning the “real” webserver has to be shut down during the certification process.

Result:

Updating letsencrypt and virtual environment dependencies.......
Running with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly --standalone -d domain.tld

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/domain.tld/fullchain.pem. Your
   cert will expire on 2016-03-01. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - If like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Renew certificates automatically

Because of the live time of 90 days a automated renewal process is in order. It’s not exactly clear who this will work in the future. Theoretically the client still knows which options where used during the creation of a certificate.  A  letsencrypt-auto -d domain.tld should be enough the renew the certificate.

The following simple PHP script uses that and tries to renew certificate that will expire soon.

Simple Let’s Encrypt renewal script

Currently this script doesn’t check if the renewal was successful. Also it only renews the certificates and not the configuration files. But at least itreloads Apache if any changes where made.

#!/usr/bin/php

// Let's Encrypt automated renewal tool
// To be put in /etc/cron.daily
//
// https://ufie.de/en/lets-encrypt-public-beta-starting-today-lets-encrypt-now-open-everyone/
//
// Author: Christian Stengel <christian.stengel@gmail.com>
// 

//  Let's Encrypt config dir
$CONF_DIR="/etc/letsencrypt";
// Let's Encrypt binary
$CMD="/opt/letsencrypt/letsencrypt-auto";
// Openssl binary
$SSLBIN="/usr/bin/openssl";
// Apache restart script
$APACHETOOL="/etc/init.d/apache2";
// Name of apache process
$APACHENAME="apache2";
// Remaining days before renewal
$MAX_DAYS="7";

// Don't change anyting below this point

$certs=array();$standalone=$apache_on=false;$apache_turned_off=false;$certs_total=$certs_renewed=0;

// Is apache running
if (shell_exec('ps ax | grep '.$APACHENAME.' | wc -l'))
   $apache_on=true;

// Search for letsencrypt certs
if (is_dir($CONF_DIR.'/live') && ($dh = opendir($CONF_DIR.'/live')))
{
   echo '###########################################################################'."\n";
   echo 'Renew Let\'s Encrypt Certificates '."\n";
   echo '###########################################################################'."\n";
   while (( $cert = readdir($dh)) !== false)
   {
      if (substr($cert,0,1)==".") continue;
      // Configuration found?
      if ($conf = simple_parse_config($CONF_DIR.'/renewal/'.$cert.'.conf'))
      {
         echo "\n";
         echo '##### Cert: '.$cert."\n";
         $certs_total++;
         $temp_standalone=false;

         // Check if server reload needed (standalone config)
         if (isset($conf["standalone"]) && (strtolower($conf["standalone"])=="true"))
         {
            $standalone=true;
            echo 'Type: standalone'."\n";
            $temp_standalone=true;
         }
         // Cert file found?
         if (is_file($conf['cert']))
         {
            $date=shell_exec($SSLBIN.' x509 -noout -dates -in '.$conf['cert'].' | grep notAfter');
            list($foo,$date)=explode("=",$date);
            $date=strtotime($date);
            echo 'Valid until: '.date("Y-m-d H:i:s",$date)."\n";

            // Calculate remaining days
            $days = floor(($date-time())/24/3600);
            echo 'Remaining days: '.$days."\n";

            // Up for reneal?
            if ($days<=$MAX_DAYS)
            {
               echo 'Renew today: yes'."\n";

               // Shut down apache
               if ($temp_standalone && $apache_on && !$apache_turned_off)
               {
                  echo 'Standalone: Shutting down apache'."\n";
                  shell_exec($APACHETOOL.' stop');
                  $apache_turned_off=true;
               }

               $return=shell_exec('echo "R" | '.$CMD.' certonly '.($temp_standalone?'--standalone':'').' -t -d '.$cert);
               $certs_renewed++;

               // ToDo: check for errors

            } echo 'Renew today: false'."\n";
         } else { echo "Error: cert file missing"; continue; }
      }
   }
   closedir($dh);
   echo "\n";
   echo '###########################################################################'."\n";
   echo "Certs total: ".$certs_total."\n";
   echo "Certs renewed: ".$certs_renewed."\n";
   // Restart Apache if necessary otherweise reload
   if ($apache_turned_off && $apache_on)
   {
      echo 'Standalone: Restarting apache'."\n";
      shell_exec($APACHETOOL.' start');
   }
   else if ($apache_on && ($certs_renewed>0 ))
   {
     echo 'Apache: reload'."\n";
     shell_exec($APACHETOOL.' reload');
   }
   echo '###########################################################################'."\n";
   echo "\n";
}
else
   die('No certs in '.$CONF_DIR.'/live');


function simple_parse_config ($file)
{
   $conf=array();
   if (!file_exists($file)) return false;
   $temp = file($file);
   foreach ($temp as $foo => $bar) { if (strpos($bar,"=")!==false) { list($var,$val) =explode("=",$bar); if (trim($var)) { $conf[trim($var)]=trim($val); } } }
   return $conf;
}

?>

 

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.