From 3aaf87ee6d4cfe32b607ed4c2a04044e8ad8ad12 Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Wed, 4 Mar 2020 10:45:41 +1100 Subject: [PATCH] letsencrypt: Register email with accounts Currently we don't set a contact email with our accounts. This is an optional feature, but would be helpful for things like [1] where we would be notified of certificates affected by bugs, etc. Setup the email address in the acme.sh config which will apply with any new accounts created. To update all the existing hosts, we see if the account email is added/modified in the config *and* if we have existing account details; if so we need a manual update call. For anyone who might be poking here, we also add a note on sharing an account based on some broadly agreed upon discussion in IRC. [1] https://community.letsencrypt.org/t/revoking-certain-certificates-on-march-4/114864 Change-Id: Ib4dc3e179010419a1b18f355d13b62c6cc4bc7e8 --- .../letsencrypt-acme-sh-install/README.rst | 6 +++ .../tasks/main.yaml | 53 +++++++++++++++++++ .../templates/group_vars/letsencrypt.yaml.j2 | 2 + testinfra/test_letsencrypt.py | 8 +++ 4 files changed, 69 insertions(+) diff --git a/playbooks/roles/letsencrypt-acme-sh-install/README.rst b/playbooks/roles/letsencrypt-acme-sh-install/README.rst index 2f55644bf4..d14c468fb1 100644 --- a/playbooks/roles/letsencrypt-acme-sh-install/README.rst +++ b/playbooks/roles/letsencrypt-acme-sh-install/README.rst @@ -15,3 +15,9 @@ authentication procedure and parse output. on the `/etc/letsencrypt-certificates` directory. If unset, uses system default. Useful if this conflicts with another role that assumes a `gid` value. + +.. zuul:rolevar:: letsencrypt_account_email + :default: undefined + + The email address to register with accounts. Renewal mail and + other info may be sent here. Must be defined. diff --git a/playbooks/roles/letsencrypt-acme-sh-install/tasks/main.yaml b/playbooks/roles/letsencrypt-acme-sh-install/tasks/main.yaml index 5f7e10d955..d4ce9796e1 100644 --- a/playbooks/roles/letsencrypt-acme-sh-install/tasks/main.yaml +++ b/playbooks/roles/letsencrypt-acme-sh-install/tasks/main.yaml @@ -35,3 +35,56 @@ owner: root group: letsencrypt mode: u=rwx,g=rx,o=,g+s + +- name: Create acme.sh config directory + file: + path: /root/.acme.sh + state: directory + owner: root + group: root + mode: u=rwx,g=rx,o= + +# An implementation note on accounts: We could share an account key +# across all our hosts and this would be the logical place to deploy +# it. However, really the only thing you can do with an account key +# is revoke a certificate if you lose the private key. It makes more +# sense to have an account per host with key material that never +# leaves the host rather than keeping a global secret that, if leaked, +# could revoke all keys simultaneously. + +- name: Check for account email + assert: + that: letsencrypt_account_email is defined + +- name: Configure account email + lineinfile: + path: /root/.acme.sh/account.conf + regexp: '^ACCOUNT_EMAIL=' + line: 'ACCOUNT_EMAIL={{ letsencrypt_account_email }}' + create: true + register: account_email + +# If we updated the email and we have existing accounts, we should +# update the address. + +# NOTE(ianw) 2020-03-04 : acme.sh dumps the 200 response json from the +# ACME api when creating an account into this file to keep track of +# the account-id. However, it doesn't actually then update it in +# response to --updateaccount although the details in the account +# *are* correctly updated. It doesn't make a difference to ongoing +# operation since all that cares about is the unchanging id, but can +# be confusing if you check this and don't see an updated email +# address. I have filed: +# https://github.com/acmesh-official/acme.sh/pull/2769 +- name: Check for existing account setup + stat: + path: '{{ item }}' + loop: + - /root/.acme.sh/ca/acme-v02.api.letsencrypt.org/account.json + - /root/.acme.sh/ca/acme-staging-v02.api.letsencrypt.org/account.json + register: existing_accounts + +- name: Run account update # noqa 503 + shell: | + /opt/acme.sh/acme.sh --debug --updateaccount + when: account_email.changed and (existing_accounts.results | selectattr('stat.exists') | map(attribute='item') | list | length > 0) diff --git a/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 b/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 index aaf62c6518..5125b32f3f 100644 --- a/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 +++ b/playbooks/zuul/templates/group_vars/letsencrypt.yaml.j2 @@ -4,3 +4,5 @@ # gate, only generate a place-holder self-signed cert for testing. letsencrypt_use_staging: True letsencrypt_self_sign_only: True + +letsencrypt_account_email: le-test@opendev.org \ No newline at end of file diff --git a/testinfra/test_letsencrypt.py b/testinfra/test_letsencrypt.py index a7415c419f..083236dae9 100644 --- a/testinfra/test_letsencrypt.py +++ b/testinfra/test_letsencrypt.py @@ -130,3 +130,11 @@ def test_updated_handler(host): else: pytest.skip() + +def test_acme_sh_config(host): + if not host.backend.get_hostname().startswith('letsencrypt0'): + pytest.skip() + + config = host.file('/root/.acme.sh/account.conf') + assert config.exists + assert config.contains("^ACCOUNT_EMAIL='le-test@opendev.org'")