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

Add example wrapper script for multi-cert/multi-account management. #14

Open
zenhack opened this issue Jan 3, 2017 · 12 comments
Open

Comments

@zenhack
Copy link
Owner

zenhack commented Jan 3, 2017

Issue by skorokithakis
Sunday Dec 06, 2015 at 09:44 GMT
Originally opened as kuba/simp_le#37


Why is it a directive that output paths must not be specified? It's inconvenient, at the very least I would like to be able to output the files with their own names. I don't understand why we can't assume that the user knows what they're doing.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by kuba
Sunday Dec 06, 2015 at 10:01 GMT


One of the problems: currently plugin name is equivalent to the output path, so we would have to introduce -f fullchain.pem:/path/to/your/file syntax. That's... less simple: both for the user and the implementation.

There are probably a ton of other problems around such solution. On the other hand, why do you even need to specify output path? In other words, does the current design stop you from achieving a particular setup? Unless you can specify the full path to simp_le files, you can always symlink...

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by skorokithakis
Sunday Dec 06, 2015 at 14:59 GMT


The problem is that, usually, all my certs are in /etc/ssl/certs, which already has proper permissions. simp_le outputs the same file every time, which means files will get overwritten. It's not a huge hassle, it would just be easier if it was a bit more flexible.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by Lekensteyn
Wednesday Dec 09, 2015 at 15:16 GMT


@kuba The filename == contents type concept is simple, but not very user friendly. It is currently also not possible to store keys and certificates in separate directories, except by creating symlinks.

The -f fullchain.pem:/etc/ssl/certs/example.com.crt -f key.pem:/etc/ssl/private/example.com.key approach seems a good compromise between complexity and flexibility (both for the code and the user).

@skorokithakis the issue of overwriting unchanged files (data that is not "dirty") is a different issue and I agree that it is not nice (different timestamp). Can you open a new issue for that?

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by skorokithakis
Wednesday Dec 09, 2015 at 15:23 GMT


@Lekensteyn My issue is not really on overwriting files, just that I can't store multiple certs in the same dir because they will use the same filename, so I can't differentiate. I can open an issue for overwriting, but I haven't seen that happen.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by ptman
Thursday Dec 10, 2015 at 11:48 GMT


This would make my life easier as well.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by AndrewNeo
Thursday Dec 17, 2015 at 06:03 GMT


The only reason I don't like the symlink or absolute path reference is that you have to put the key in the same directory as the cert. Not being able to specify filenames isn't great but it's a more minor issue by how inconvenient simp_le is to use with multiple certificates at once.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by Rotonen
Sunday Dec 20, 2015 at 21:46 GMT


Cert location management is better left unhandled by a single purpose software and left at the devises of the sysadmin-fu of the deployment target. What this project could do is to document a sane baseline practice to adhere to.

Below is a rough outline of what I'm doing in a cronjob sans error handling and system specific aspects (for readability).

#!/bin/bash

cd /root/ssltemp

/root/simp_le/venv/bin/simp_le \
--email admin@example.com \
--default_root /var/www/letsencrypt \
-f account_key.json \
-f fullchain.pem \
-f cert.pem \
-f chain.pem \
-f key.pem \
-d example.com \
-d www.example.com

mv key.pem privkey.pem
mv *pem /etc/letsencrypt/live/example.com/

simp_le \
--default_root /var/www/letsencrypt \
--email admin@example.org \
-f account_key.json \
-f cert.pem \
-f chain.pem \
-f fullchain.pem \
-f key.pem \
-d example.org \
-d www.example.org \
-d mail.example.org

mv key.pem privkey.pem
mv *pem /etc/letsencrypt/live/example.org/

systemctl reload nginx postfix

systemctl restart dovecot

# EOF

For authentication with Nginx, I have the following:

/etc/nginx/sites-enabled/default

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    include letsencrypt-webroot.conf;
    location / {
        return 444;
    }
}

/etc/nginx/letsencrypt-webroot.conf

# The regex match is here to allow it to work from within otherwise denied locations.
# This is a corner of Nginx I do not fully understand.
location ^~ /.well-known {
    allow all;
    alias /var/www/letsencrypt/.well-known;
}

/etc/nginx/sites-enabled/example.com

# In the future:
# listen 80 h2c;
server {
    listen 80;
    listen [::]:80;

    server_name example.com;

    access_log /var/log/nginx/example.com-access.log;
    error_log /var/log/nginx/example.com-error.log;

    return 301 https://$server_name$request_uri;
}

# In the future:
# listen 443 h2;
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name example.com;

    access_log /var/log/nginx/example.com-access.log;
    error_log /var/log/nginx/example.com-error.log;

    include ssl-example.com.conf;

    root /var/www/example.com;
    index index.html index.htm;

    charset utf-8;

    include letsencrypt-webroot.conf;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location ~ ^/~(.+?)(/.*)?$ {
        alias /home/$1/public_html$2;
        index  index.html index.htm;
        autoindex on;
    }
}

/etc/nginx/ssl-example.com.conf

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_dhparam /etc/letsencrypt/live/example.com/dhparam.pem;

include ssl-common.conf;

Do note that HSTS can equate to painting yourself into a corner - you will have to serve over HTTPS.

/etc/nginx/ssl-common.conf

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;

ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_prefer_server_ciphers on;

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by kuba
Sunday Dec 20, 2015 at 22:47 GMT


While this is completely off-topic for this PR, @Rotonen, unfortunately, there are a couple of problems with your setup:

  1. You should not move/rename output files of the script, i.e. the following is wrong:

    mv key.pem privkey.pem
    mv *pem /etc/letsencrypt/live/example.com/

    This way every time you run the cron, certs will be renewed. If you really need the key to be called privkey.pem then ln -s key.pem privkey.pem. If you really cannot specify full path to simp_le $CWD in your server configs, then ln -s $CWD/key.pem /etc/letsencrypt/live/example.com/key.pem etc. Every time simp_le is run it rereads the certs and renews it only if necessary (month before expiry), so it's safe to put it into daily crontab.

  2. Use the exit codes to restart services only if necessary. The following is wrong:

    systemctl reload nginx postfix
    systemctl restart dovecot

    as it will always reload/restart your servers even if certs were not renewed. What's better is something along these lines: simp_le ... && systemctl reload nginx postfix

Nevertheless, you do have a point. I should work on canonical examples and put them down in https://github.com/kuba/simp_le/wiki/Examples.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by Rotonen
Monday Dec 21, 2015 at 00:53 GMT


Yes, as stated, the script excerpt is sans error handling and system specific aspects. It should not end up in anyone's production setup verbatim, it is provided purely for reference use only. A generalized solution would on top of exit code handling also have to discover which services use the cert (take that as a parametre, for instance) and which init system is used by the system in question.

The key renaming is in there to conform to the naming scheme the Letsencrypt client has out of the box (to ease with transition from that tool to this tool). I admit this is not obvious from the example.

I'm always renewing the certs as the script is in cron to be run every second month of the year (as suggested by Letsencrypt). This is not transparently obvious either, yes, but I explicitly want to renew the certs every time this script gets run and it is the admin's responsibility to behave and adhere to the renews over time limits of the CA.

As for the relevancy for the pull request - if one is to take my view on how to handle this, providing such skeletal sketching for documentation is at the core of the issue. This might not be the correct forum for that due to the verbosity imposed on this thread, though.

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by ThiefMaster
Saturday Dec 26, 2015 at 01:57 GMT


I'd also like some more flexibility, such as being able to specify a path that's already mapped as .well-known/acme-challenge (i.e. the files would do there directly instead of creating those subdirectories).

The reason for this is that I'm mostly running Python applications which don't have a true "web root". While e.g. /static is mapped to a physical directory, everything else goes straight to the Python webapp. In this case the easiest solution would be mapping .well-known/acme-challenge/ to e.g. /var/lib/letsencrypt/<domain>/ - no need to have two extra levels of subdirectories in there!

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by kuba
Saturday Dec 26, 2015 at 10:02 GMT


@ThiefMaster that's a bit different problem, and should be opened as a new issue: #53

@zenhack
Copy link
Owner Author

zenhack commented Jan 3, 2017

Comment by kuba
Sunday Apr 17, 2016 at 18:57 GMT


I want to keep this software as simple as possible. Flexibility of specifying your own paths is achievable by creating a wrapper script. I would be potentially interested in adding such a wrapper to examples, but I'm not happy to make it part of the core script. Also, I'm afraid that I will not be able to work this out myself in foreseeable future, so if anyone is interested, feel free to grab it! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant