Skip to content
This repository has been archived by the owner on Jun 4, 2021. It is now read-only.

Switch to certbot for letsencrypt certificates #1668

Merged
merged 3 commits into from Dec 5, 2019

Conversation

nickgnazzo
Copy link
Contributor

Fixes issue #1662

Modifies the lets-encrypt role to use certbot for certificate issuance and auto-renewal. Also upgrades to using Let's Encrypt's ACMEv2 server.

Changes made:

  • Removes acmetool package, PPA, pubkey, etc. in favor of certbot.
  • For the initial certificate request, use the certbot certonly --standalone command to bind on port 80 and complete the ACME challenge/response process (via http-01). This helps us avoid any of certbot's nginx modification/config changes (just to avoid potential complications).
  • Modify RSA key size of requested certificate to 4096 (was previously set to 2048 with acmetool).
  • Sets up a port 80 -> 443 (http to https) redirect
    • The /.well-known/acme-challenge directory is white-listed in order to allow certificate renewal to work.
      • This directory is intentionally set to be different from Streisand's default gateway directory (where all VPN creds/pages live) to avoid any chance of leaking VPN creds/pages over port 80. There's probably a low risk of this ever happening but I figured it can't hurt.
      • This directory is also emptied of any files during setup to avoid serving anything except ACME challenge responses over port 80.
  • Modifies certbot renewal configuration to use the webroot authenticator.
    • As mentioned above, the /.well-known/acme-challenge directory will be allowed over port 80 via nginx. Certbot's webroot plugin will just write ACME challenge response files to that directory during certificate renewal (once completed the files are removed).
    • This helps us avoid any downtime since certbot won't need to modify nginx configs or restart the service when renewing the cert.

@nickgnazzo nickgnazzo changed the title Certbot letsencrypt Switch to certbot for letsencrypt certificates Oct 26, 2019
@lazerhawk
Copy link

It's November now, so this patch, or something based on the official plugin, is now needed to not break deployments (and probably ACME renewals too).

@cpu
Copy link
Collaborator

cpu commented Nov 4, 2019

(and probably ACME renewals too).

Renewals of existing certificates will not be affected by the Nov. new registration shut-off. These will continue to work until early 2021. The full schedule of dates is available here: https://community.letsencrypt.org/t/end-of-life-plan-for-acmev1/88430

@mgrankin
Copy link

mgrankin commented Nov 9, 2019

As of today, new deployments don't work due to 'Account creation on ACMEv1 is disabled. Please upgrade your ACME client to a version that supports ACMEv2'.

@mew1033
Copy link

mew1033 commented Nov 12, 2019

This looks like a great way to solve the problem. Is there anything keeping this from being merged? Any help the community can provide?

@arkarkark
Copy link

I tried this just now and got the error message at the end of this comment.

It seems pyasn1 is needed

I'm sure it's not the right way to fix it but I modified the task in playbooks/python.yml and it got a lot further, but alas, I can't get a cert using certbot without a full domain name. I used to be able to. I have streisand_domain: "" in my site.yaml
I'm a little confused why it's trying to get a lets encrypt cert when my domain is empty, setup says that's optional and a self signed cert will be used if it's empty.

---
- name: Prepare the new server for Ansible
# =========================================
  hosts: streisand-host
  gather_facts: no

  remote_user: "root"
  become: true

  tasks:
    - name: Install Python using a raw SSH command to enable the execution of Ansible modules
      raw: apt update && apt install python python-pip -y && /usr/local/bin/pip install --upgrade pip && /usr/local/bin/pip install pyasn1
      args:
        executable: /bin/bash
...

error message was:

fatal: [209.250.240.149]: FAILED! => {"changed": true, "cmd": ["certbot", "certonly", "--standalone", "-d", "--register-unsafely-without-email", "--agree-tos", "--non-interactive", "--rsa-key-size", "4096", "--server", "https://acme-v02.api.letsencrypt.org/directory"], "delta": "0:00:00.537951", "end": "2019-11-18 10:28:55.846269", "msg": "non-zero return code", "rc": 2, "start": "2019-11-18 10:28:55.308318", "stderr": "/usr/lib/python3/dist-packages/ndg/httpsclient/subj_alt_name.py:22: UserWarning: Error importing pyasn1, subjectAltName check for SSL peer verification will be disabled.  Import error is: No module named 'pyasn1'\n  warnings.warn(import_error_msg)\n/usr/lib/python3/dist-packages/ndg/httpsclient/ssl_peer_verification.py:25: UserWarning: SubjectAltName support is disabled - check pyasn1 package installation to enable\n  warnings.warn(SUBJ_ALT_NAME_SUPPORT_MSG)\n/usr/lib/python3/dist-packages/ndg/httpsclient/subj_alt_name.py:22: UserWarning: Error importing pyasn1, subjectAltName check for SSL peer verification will be disabled.  Import error is: No module named 'pyasn1'\n  warnings.warn(import_error_msg)\nusage: \n  certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...\n\nCertbot can obtain and install HTTPS/TLS/SSL certificates.  By default,\nit will attempt to use a webserver both for obtaining and installing the\ncertificate. \ncertbot: error: argument -d/--domains/--domain: expected one argument", "stderr_lines": ["/usr/lib/python3/dist-packages/ndg/httpsclient/subj_alt_name.py:22: UserWarning: Error importing pyasn1, subjectAltName check for SSL peer verification will be disabled.  Import error is: No module named 'pyasn1'", "  warnings.warn(import_error_msg)", "/usr/lib/python3/dist-packages/ndg/httpsclient/ssl_peer_verification.py:25: UserWarning: SubjectAltName support is disabled - check pyasn1 package installation to enable", "  warnings.warn(SUBJ_ALT_NAME_SUPPORT_MSG)", "/usr/lib/python3/dist-packages/ndg/httpsclient/subj_alt_name.py:22: UserWarning: Error importing pyasn1, subjectAltName check for SSL peer verification will be disabled.  Import error is: No module named 'pyasn1'", "  warnings.warn(import_error_msg)", "usage: ", "  certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...", "", "Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,", "it will attempt to use a webserver both for obtaining and installing the", "certificate. ", "certbot: error: argument -d/--domains/--domain: expected one argument"], "stdout": "", "stdout_lines": []}

@nickgnazzo
Copy link
Contributor Author

nickgnazzo commented Nov 18, 2019

@arkarkark I'm unable to reproduce that error locally. When I run with a blank domain in a noninteractive deploy, the lets-encrypt role never runs. Can you post the contents of your site.yaml file (redacting any API keys/sensitive info)?

I suspect it could be an issue with the variable name streisand_domain. The variable should be named streisand_domain_var inside your site.yaml, as this is checked in the playbooks/lets-encrypt.yml file, and if that variable is blank, it disables the lets-encrypt role. Any tasks inside the role shouldn't run at all (like the certbot command that failed for you). So I suspect something is making that role run for you when it shouldn't.

This is the site config I used:
https://gist.github.com/nickgnazzo/e52c2fc85077d9671b884cbb945089f4

@arkarkark
Copy link

Thanks @nickgnazzo, you're right! I set streisand_domain_var: "" and indeed it no longer tries to use letsencrypt. So I'm all set.

Even though it's probably not the right way to get pyasn1 it did seem to get it far enough along to know I didn't have a domain name so it might help someone else.

@serjflint
Copy link

serjflint commented Nov 25, 2019

Tried merging this pull request

fatal: [213.183.51.167]: FAILED! => {"changed": false, "msg": "Unable to restart service nginx: Job for nginx.service failed because the control process exited with error code. See \"systemctl status nginx.service\" and \"journalctl -xe\" for details.\n"}
# nginx -t 
nginx: [emerg] Unknown curve name "auto" (SSL:)
nginx: configuration file /etc/nginx/nginx.conf test failed
# nginx -v      
nginx version: nginx/1.10.3 (Ubuntu)

@lazerhawk
Copy link

lazerhawk commented Dec 2, 2019

Possibly related, user experiencing certbot failure though, not acmetool of the original fresh install issue.

#1674

@nickgnazzo
Copy link
Contributor Author

@serjflint I can't seem to reproduce that error. Can you share your site.yml file, if you used one (with any API keys redacted)? Which cloud provider were you using?

@nickgnazzo
Copy link
Contributor Author

nickgnazzo commented Dec 2, 2019

@lazerhawk that issue seems to be using the current Streisand master branch, which does not include the changes in this PR yet. They appear to have run Certbot after Streisand provisioned the server without the lets-encrypt role enabled, which will not work by default until (or if) the changes in this PR are merged into master. At the moment (current master branch), port 80 is not open in the firewall unless you enable the lets-encrypt role, so running Certbot manually will fail since the ACME server will be blocked by Streisand's firewall.

Copy link
Member

@nopdotcom nopdotcom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging, although if it's writing to /usr, it's a bug — but not a showstopper.

@@ -9,3 +9,4 @@ apache_packages_to_remove:
- apache2-mpm-worker

nginx_systemd_service_path: /etc/systemd/system/nginx.service.d
nginx_default_html_path: /usr/share/nginx/html
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't really be writing to /usr. Somewhere in /var maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think something like /var/www/streisand-letsencrypt would be more appropriate?

@nopdotcom nopdotcom merged commit 0130140 into StreisandEffect:master Dec 5, 2019
@nopdotcom
Copy link
Member

Yeah, or even /var/lib/streisand-letsencrypt/ or /var/lib/streisand-letsencrypt/html/. Just /usr is bad. :‑)

You're probably right that something under /var/www makes more sense.

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

Successfully merging this pull request may close these issues.

None yet

8 participants