Bug 15303 Letsencrypt option for Debian package installations
authorMirko Tietgen <mirko@abunchofthings.net>
Fri, 4 Dec 2015 00:11:17 +0000 (01:11 +0100)
committerKyle M Hall <kyle@bywatersolutions.com>
Fri, 29 Apr 2016 13:04:31 +0000 (13:04 +0000)
New option koha-create --letsencrypt

- installs the letsencrypt package if needed
- creates <instance>
- generates letsencrypt certificates for <instance>
- sets up a https-only website for <instance>
- redirects http to https for <instance>

! you need to enable jessie backports to install letsencrypt: add
deb http://http.debian.net/debian jessie-backports main contrib non-free
to your /etc/apt/sources.list

! this patch uses the letsencrypt staging server
to create real certificates, apply thy "LE production server" patch

Test plan:
- build a debian package with patch applied
- use apache mod_ssl
  sudo a2enmod ssl
- make sure the machine is accessible on 80 (needed for letsencrypt) and 443 from the internet
- install koha with your new package
- Put your (existing) domain options in /etc/koha/koha-sites.conf
- use koha-create with the new options:
  sudo koha-create --create-db --letsencrypt <instance>
- if you do not have the letsencrypt package installed, you will be prompted to do that
  [
    if there is no package available, a symlink to the git checkout will work:

    on your test server, get letsencrypt via git
    git clone https://github.com/letsencrypt/letsencrypt

    create a symlink from /usr/bin/letsencrypt to letsencrypt-auto
    sudo ln -s /path/to/letsencrypt/letsencrypt-auto /usr/bin/letsencrypt
  ]

- wait until setup is finished, check that you got a working OPAC and staff client with certificates
- check that http redirects to https

Signed-off-by: Chris Cormack <chrisc@catalyst.net.nz>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
debian/control.in
debian/docs/koha-create.xml
debian/scripts/koha-create
debian/scripts/koha-foreach
debian/scripts/koha-functions.sh
debian/scripts/koha-list
debian/templates/apache-site-https.conf.in [new file with mode: 0644]
install_misc/debian.packages

index 44060c6..6609d7f 100644 (file)
@@ -35,7 +35,8 @@ Depends: ${misc:Depends}, ${koha:Depends},
  xmlstarlet,
  yaz
 Suggests: mysql-server | virtual-mysql-server,
- memcached
+ memcached,
+letsencrypt
 Homepage: http://koha-community.org/
 Description: integrated (physical) library management system
  Koha is an Integrated Library Management system for real-world libraries
index 92785ac..a485ba8 100644 (file)
@@ -40,6 +40,7 @@
       <arg><option>--enable-sru</option></arg>
       <arg><option>--sru-port</option> port</arg>
       <arg><option>--upload-path</option> directory</arg>
+      <arg><option>--letsencrypt</option></arg>
       <arg><option>--help</option>|<option>-h</option></arg>
 
       <arg choice="req" rep="norepeat"><replaceable>instancename</replaceable></arg>
     </varlistentry>
 
     <varlistentry>
+      <term><option>--letsencrypt</option></term>
+      <listitem>
+        <para>Set up a https-only website with letsencrypt certificates</para>
+      </listitem>
+    </varlistentry>
+
+    <varlistentry>
       <term><option>--help</option>,<option>-h</option></term>
       <listitem>
         <para>Print usage information.</para>
index 2a6c87d..159193b 100755 (executable)
@@ -71,6 +71,7 @@ Options:
                             conjunction with --defaultsql and --populate-db.
   --upload-path dir         Set a user defined upload_path. It defaults to
                             /var/lib/koha/<instance>/uploads
+  --letsencrypt             Set up a https-only site with letsencrypt certificates
   --help,-h                 Show this help.
 
 Note: the instance name cannot be longer that 11 chars.
@@ -194,6 +195,20 @@ EOM
         die
     fi
 
+    # Check that mod_ssl is installed and enabled.
+    if [ "$CLO_LETSENCRYPT" = "yes" ]; then
+        if ! /usr/sbin/apachectl -M 2> /dev/null | grep -q 'ssl_module'; then
+            cat 1>&2  <<EOM
+
+Koha requires mod_ssl to be enabled within Apache in order to run with --letsencrypt.
+Typically this can be enabled with:
+
+    sudo a2enmod ssl
+EOM
+            die
+        fi
+    fi
+
 }
 
 set_biblios_indexing_mode()
@@ -313,6 +328,44 @@ enable_sru_server()
     fi
 }
 
+check_letsencrypt()
+{
+    if [ $(dpkg-query -W -f='${Status}' letsencrypt 2>/dev/null | grep -c "ok installed") -eq 0 ]; then
+        apt-cache show letsencrypt &>/dev/null
+        if [ $? -eq 0 ]; then
+                read -r -p "The letsencrypt package is not installed. Do it now?  [y/N] " response
+                if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
+                    apt-get install -y letsencrypt
+                else
+                    die "You have to install letsencrypt to use the --letsencrypt parameter."
+                fi
+        else
+            echo "No installation candidate available for package letsencrypt."
+            read -r -p "If you have a symlink from /usr/bin/letsencrypt to letsencrypt-auto, it should work. [y/N] " response
+            if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
+                die "You have to install letsencrypt to use the --letsencrypt parameter."
+            fi
+        fi
+    fi
+}
+
+letsencrypt_instance()
+{
+    # Get letsencrypt certificates
+    letsencrypt --agree-tos --renew-by-default --webroot --staging certonly \
+        -w /usr/share/koha/opac/htdocs/ -d $opacdomain -w /usr/share/koha/intranet/htdocs/ -d $intradomain
+    # enable all ssl settings (apache won't start with these before certs are present)
+    sed -i "s:^\s*#\(\s*SSL.*\)$:\1:" "/etc/apache2/sites-available/$name.conf"
+    # change port from 80 to 443. (apache won't start if it is 443 without certs present)
+    sed -i "s:^\s*\(<VirtualHost \*\:\)80> #https$:\1443>:" "/etc/apache2/sites-available/$name.conf"
+    # enable redirect from http to https on port 80
+    sed -i "s:^\s*#\(.*\)#nohttps$:\1:" "/etc/apache2/sites-available/$name.conf"
+    # make koha-list --letsencrypt aware of this instance # could be done by checking apache conf instead
+    touch /var/lib/koha/$name/letsencrypt.enabled
+    # restart apache with working certs
+    service apache2 restart
+}
+
 # Set defaults and read config file, if it exists.
 DOMAIN=""
 OPACPORT="80"
@@ -356,6 +409,8 @@ END_BIBLIOS_RETRIEVAL_INFO=""
 START_AUTHORITIES_RETRIEVAL_INFO=""
 END_AUTHORITIES_RETRIEVAL_INFO=""
 
+APACHE_CONFIGFILE=""
+
 if [ -e /etc/koha/koha-sites.conf ]
 then
     . /etc/koha/koha-sites.conf
@@ -363,7 +418,7 @@ fi
 
 [ $# -ge 1 ] && [ $# -le 16 ] || ( usage ; die "Error: wrong parameters" )
 
-TEMP=`getopt -o chrpm:l:d:f:b:a: -l create-db,request-db,populate-db,use-db,use-memcached,enable-sru,sru-port:,help,marcflavor:,auth-idx:,biblio-idx:,zebralang:,defaultsql:,configfile:,passwdfile:,database:,adminuser:,memcached-servers:,memcached-prefix:,upload-path:, \
+TEMP=`getopt -o chrpm:l:d:f:b:a: -l create-db,request-db,populate-db,use-db,use-memcached,enable-sru,sru-port:,help,marcflavor:,auth-idx:,biblio-idx:,zebralang:,defaultsql:,configfile:,passwdfile:,database:,adminuser:,memcached-servers:,memcached-prefix:,upload-path:,letsencrypt, \
      -n "$0" -- "$@"`
 
 # Note the quotes around `$TEMP': they are essential!
@@ -379,7 +434,7 @@ CLO_AUTHORITIES_INDEXING_MODE=""
 CLO_MEMCACHED_SERVERS=""
 CLO_MEMCACHED_PREFIX=""
 CLO_UPLOAD_PATH=""
-
+CLO_LETSENCRYPT=""
 
 while true ; do
     case "$1" in
@@ -421,6 +476,8 @@ while true ; do
             SRU_SERVER_PORT="$2" ; shift 2 ;;
         --upload-path)
             CLO_UPLOAD_PATH="$2" ; shift 2 ;;
+        --letsencrypt)
+            CLO_LETSENCRYPT="yes" ; shift ;;
         -h|--help)
             usage ; exit 0 ;;
         --)
@@ -516,6 +573,8 @@ check_apache_config
 opacdomain="$OPACPREFIX$name$OPACSUFFIX$DOMAIN"
 intradomain="$INTRAPREFIX$name$INTRASUFFIX$DOMAIN"
 
+# Check everything is ok with letsencrypt, die otherwise
+check_letsencrypt
 
 if [ -f $PASSWDFILE ] && [ `cat $PASSWDFILE | grep "^$name:"` ]
 then
@@ -600,8 +659,13 @@ FLUSH PRIVILEGES;
 eof
     fi #`
 
+    if [ "$CLO_LETSENCRYPT" = "yes" ]; then
+        APACHE_CONFIGFILE="apache-site-https.conf.in"
+    else
+        APACHE_CONFIGFILE="apache-site.conf.in"
+    fi
     # Generate and install Apache site-available file and log dir.
-    generate_config_file apache-site.conf.in \
+    generate_config_file $APACHE_CONFIGFILE \
         "/etc/apache2/sites-available/$name.conf"
     mkdir "/var/log/koha/$name"
     chown "$username:$username" "/var/log/koha/$name"
@@ -710,6 +774,11 @@ then
         # Start Indexer daemon
         koha-indexer --start "$name"
     fi
+
+    if [ "$CLO_LETSENCRYPT" = "yes" ]; then
+        # Get letsencrypt certificates
+        letsencrypt_instance
+    fi
 fi
 
 
index 925d90b..7a3341d 100755 (executable)
@@ -30,6 +30,8 @@ do
         --nosip) listopts="$listopts --nosip";;
         --plack) listopts="$listopts --plack";;
       --noplack) listopts="$listopts --noplack";;
+  --letsencrypt) listopts="$listopts --letsencrypt" ;;
+--noletsencrypt) listopts="$listopts --noletsencrypt" ;;
               *) break;;
     esac
     shift
index 87a84a1..ef71a3a 100755 (executable)
@@ -84,6 +84,17 @@ is_email_enabled()
     fi
 }
 
+is_letsencrypt_enabled()
+{
+    local instancename=$1
+
+    if [ -e /var/lib/koha/$instancename/letsencrypt.enabled ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
 is_sip_enabled()
 {
     local instancename=$1
index 73ce075..0dd72e1 100755 (executable)
@@ -36,24 +36,27 @@ show_instances()
     for instance in $( get_instances ); do
         case $show in
           "all")
-              if instance_filter_email $instance $show_email && \
-                 instance_filter_plack $instance $show_plack && \
-                 instance_filter_sip   $instance $show_sip; then
+              if instance_filter_email       $instance $show_email && \
+                 instance_filter_letsencrypt $instance $show_letsencrypt && \
+                 instance_filter_plack       $instance $show_plack && \
+                 instance_filter_sip         $instance $show_sip; then
                     echo $instance
               fi ;;
           "enabled")
               if is_enabled $instance; then
-                  if instance_filter_email $instance $show_email && \
-                     instance_filter_plack $instance $show_plack && \
-                     instance_filter_sip   $instance $show_sip; then
+                  if instance_filter_email       $instance $show_email && \
+                     instance_filter_letsencrypt $instance $show_letsencrypt && \
+                     instance_filter_plack       $instance $show_plack && \
+                     instance_filter_sip         $instance $show_sip; then
                       echo $instance
                   fi
               fi ;;
           "disabled")
               if ! is_enabled $instance; then
-                  if instance_filter_email $instance $show_email && \
-                     instance_filter_plack $instance $show_plack && \
-                     instance_filter_sip   $instance $show_sip; then
+                  if instance_filter_email       $instance $show_email && \
+                     instance_filter_letsencrypt $instance $show_letsencrypt && \
+                     instance_filter_plack       $instance $show_plack && \
+                     instance_filter_sip         $instance $show_sip; then
                       echo $instance
                   fi
               fi ;;
@@ -106,6 +109,28 @@ instance_filter_plack()
     return 1
 }
 
+instance_filter_letsencrypt()
+{
+    local instancename=$1
+    local show_letsencrypt=$2;
+
+    case $show_letsencrypt in
+        "all")
+            return 0 ;;
+        "enabled")
+            if is_letsencrypt_enabled $instancename; then
+                return 0
+            fi ;;
+        "disabled")
+            if ! is_letsencrypt_enabled $instancename; then
+                return 0
+            fi ;;
+    esac
+
+    # Didn't match any criteria
+    return 1
+}
+
 instance_filter_email()
 {
     local instancename=$1
@@ -150,6 +175,17 @@ set_show_email()
     fi
 }
 
+set_show_letsencrypt()
+{
+    local letsencrypt_param=$1
+
+    if [ "$show_letsencrypt" = "all" ]; then
+        show_letsencrypt=$letsencrypt_param
+    else
+        die "Error: --letsencrypt and --noletsencrypt are mutually exclusive."
+    fi
+}
+
 set_show_plack()
 {
     local plack_param=$1
@@ -190,6 +226,8 @@ Options:
     --nosip         Show instances with SIP disabled
     --plack         Show instances with Plack enabled
     --noplack       Show instances with Plack disabled
+    --letsencrypt   Show instances with letsencrypt enabled
+    --noletsencrypt Show instances with letsencrypt disabled
     --help | -h     Show this help
 
 The filtering options can be combined, and you probably want to do this
@@ -201,23 +239,26 @@ show="all"
 show_email="all"
 show_sip="all"
 show_plack="all"
+show_letsencrypt="all"
 
-args=$(getopt -l help,enabled,disabled,email,noemail,sip,nosip,plack,noplack -o h -n $0 -- "$@")
+args=$(getopt -l help,enabled,disabled,email,noemail,sip,nosip,plack,noplack,letsencrypt,noletsencrypt -o h -n $0 -- "$@")
 set -- $args
 
 while [ ! -z "$1" ]
 do
     case "$1" in
-  -h|--help) usage; exit;;
-    --email) set_show_email "enabled" ;;
-  --noemail) set_show_email "disabled" ;;
-      --sip) set_show_sip "enabled" ;;
-    --nosip) set_show_sip "disabled" ;;
-    --plack) set_show_plack "enabled" ;;
-  --noplack) set_show_plack "disabled" ;;
-  --enabled) set_show "enabled" ;;
- --disabled) set_show "disabled" ;;
-          *) break;;
+      -h|--help) usage; exit;;
+        --email) set_show_email "enabled" ;;
+      --noemail) set_show_email "disabled" ;;
+          --sip) set_show_sip "enabled" ;;
+        --nosip) set_show_sip "disabled" ;;
+        --plack) set_show_plack "enabled" ;;
+      --noplack) set_show_plack "disabled" ;;
+  --letsencrypt) set_show_letsencrypt "enabled" ;;
+--noletsencrypt) set_show_letsencrypt "disabled" ;;
+      --enabled) set_show "enabled" ;;
+     --disabled) set_show "disabled" ;;
+              *) break;;
     esac
     shift
 done
diff --git a/debian/templates/apache-site-https.conf.in b/debian/templates/apache-site-https.conf.in
new file mode 100644 (file)
index 0000000..44a4fc8
--- /dev/null
@@ -0,0 +1,70 @@
+# Koha instance __KOHASITE__ Apache config.
+
+# redirect http to https
+#<VirtualHost *:80> #nohttps
+#   ServerName __OPACSERVER__ #nohttps
+#   ServerAlias __INTRASERVER__ #nohttps
+#   RewriteEngine On #nohttps
+#   RewriteCond %{HTTPS} !=on #nohttps
+#   RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] #nohttps
+#</VirtualHost> #nohttps
+
+# OPAC
+<VirtualHost *:80> #https
+#  SSLEngine on
+#  SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
+#  SSLCompression off
+#  SSLHonorCipherOrder on
+#  SSLCipherSuite "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-SA-
+#  SSLCertificateKeyFile   /etc/letsencrypt/live/__OPACSERVER__/privkey.pem
+#  SSLCertificateFile      /etc/letsencrypt/live/__OPACSERVER__/cert.pem
+#  SSLCertificateChainFile /etc/letsencrypt/live/__OPACSERVER__/chain.pem
+
+  <IfVersion >= 2.4>
+   Define instance "__KOHASITE__"
+  </IfVersion>
+   Include /etc/koha/apache-shared.conf
+#  Include /etc/koha/apache-shared-disable.conf
+#  Include /etc/koha/apache-shared-opac-plack.conf
+   Include /etc/koha/apache-shared-opac.conf
+
+   ServerName __OPACSERVER__
+   SetEnv KOHA_CONF "/etc/koha/sites/__KOHASITE__/koha-conf.xml"
+   SetEnv MEMCACHED_SERVERS "__MEMCACHED_SERVERS__"
+   SetEnv MEMCACHED_NAMESPACE "__MEMCACHED_NAMESPACE__"
+   AssignUserID __UNIXUSER__ __UNIXGROUP__
+
+   ErrorLog    /var/log/koha/__KOHASITE__/opac-error.log
+#  TransferLog /var/log/koha/__KOHASITE__/opac-access.log
+#  RewriteLog  /var/log/koha/__KOHASITE__/opac-rewrite.log
+</VirtualHost>
+
+# Intranet
+<VirtualHost *:80> #https
+#  SSLEngine on
+#  SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
+#  SSLCompression off
+#  SSLHonorCipherOrder on
+#  SSLCipherSuite "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES
+#  SSLCertificateKeyFile   /etc/letsencrypt/live/__OPACSERVER__/privkey.pem
+#  SSLCertificateFile      /etc/letsencrypt/live/__OPACSERVER__/cert.pem
+#  SSLCertificateChainFile /etc/letsencrypt/live/__OPACSERVER__/chain.pem
+
+  <IfVersion >= 2.4>
+   Define instance "__KOHASITE__"
+  </IfVersion>
+   Include /etc/koha/apache-shared.conf
+#  Include /etc/koha/apache-shared-disable.conf
+#  Include /etc/koha/apache-shared-intranet-plack.conf
+   Include /etc/koha/apache-shared-intranet.conf
+
+   ServerName __INTRASERVER__
+   SetEnv KOHA_CONF "/etc/koha/sites/__KOHASITE__/koha-conf.xml"
+   SetEnv MEMCACHED_SERVERS "__MEMCACHED_SERVERS__"
+   SetEnv MEMCACHED_NAMESPACE "__MEMCACHED_NAMESPACE__"
+   AssignUserID __UNIXUSER__ __UNIXGROUP__
+
+   ErrorLog    /var/log/koha/__KOHASITE__/intranet-error.log
+#  TransferLog /var/log/koha/__KOHASITE__/intranet-access.log
+#  RewriteLog  /var/log/koha/__KOHASITE__/intranet-rewrite.log
+</VirtualHost>
index f520898..7d0c747 100644 (file)
@@ -8,6 +8,7 @@ idzebra-2.0     install
 idzebra-2.0-common     install
 idzebra-2.0-doc        install
 idzebra-2.0-utils      install
+letsencrypt install
 libalgorithm-checkdigits-perl  install
 libanyevent-http-perl          install
 libanyevent-perl               install