Skip to content

Handles the interaction with the ACME Server of Let's Encrypt.

License

Notifications You must be signed in to change notification settings

danvaida/ansible-roles-letsencrypt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status Galaxy

Ansible Let's Encrypt role

Obtains TLS certificates through ACME from Let's Encrypt.

Once you complete the challenge(s) and obtain the Certificate(s), you are responsible for setting it/them up in your web server(s) of choice.

Requirements

  • openssl
  • Python >= 2.7.9

Role Variables

  • letsencrypt_certs_dir: Path to work-dir, where all CSRs, Keys and Certs will be stored.

  • letsencrypt_account_key_name: Name of the Let's Encrypt account's RSA key.

  • letsencrypt_account_key_size: Size of the Let's Encrypt account's RSA key.

  • letsencrypt_certs_to_generate: List of certs to generate.

    • account_email: E-mail address that's going to be exchanged with the ACME server. You'll get cert expiration warnings.

    • account_key: Path to the RSA key file.

    • acme_directory: ACME API endpoint. Uses Let's Encrypt's Staging by default.

    • agreement: URI to TOS doc you agree with.

    • challenge: The accepted challenge type.

    • csr: Path to the CSR file.

    • dest: Path to the resulting Certificate file (where you want to store it).

    • remaining_days: Number of days for the cert to be valid.

Dependencies

N/A

Example Playbook

In this example, we are requesting a certificate from Let's Encrypt, although in theory, this Ansible module should be compatible with any ACME server.

We have three plays:

  1. create CSR, Key and issue request for certificate release
  2. complete the challenge (DNS record in Route53 in this case)
  3. ask to validate the challenge and grant the certificate.
    - name: ACME Step 1
      hosts: localhost
      connection: local
      roles:
        - role: letsencrypt
          letsencrypt_certs_dir:         './files/production/certs'
          letsencrypt_account_key_name:  'letsencrypt_account'
          letsencrypt_account_key_size:  2048
          letsencrypt_certs_to_generate:
            - domain: 'your-domain.com'
              key_size: 2048
              account_email: 'info@your-domain.com'
              account_key: "{{ letsencrypt_certs_dir }}/{{ letsencrypt_account_key_name }}.key"
              challenge: 'dns-01'
              agreement: 'https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf'
              csr: "{{ letsencrypt_certs_dir }}/your-domain.com/your.csr"
              dest: "{{ letsencrypt_certs_dir }}/your-domain.com/domain.crt"
              acme_directory: 'https://acme-v01.api.letsencrypt.org/directory'
          tags: letsencrypt

      tasks:
        - name: List of Route53 records to create should be set as fact
          set_fact:
            route53_records_to_add: "{{
              route53_records_to_add | default([]) +
              [{'zone': item.1.domain,
              'record': item.0.challenge_data[item.1.domain]['dns-01']['resource'] + '.' + item.1.domain + '.',
              'ttl': 300,
              'type': 'TXT',
              'value': '\"' + item.0.challenge_data[item.1.domain]['dns-01']['resource_value'] + '\"' }]
              }}"
          with_together:
            - "{{ letsencrypt_acme_step_one }}"
            - "{{ letsencrypt_certs_to_obtain | default([]) }}"
          when: item.1.domain == item.0.item.domain
          tags: route53

    - name: ACME challenge solving (DNS record in Route53)
      hosts: localhost
      connection: local
      roles:
        - role: route53
          tags: route53

    - name: ACME Step 2
      hosts: localhost
      connection: local
      pre_tasks:
        - name: We should wait for the DNS changes to propagate
          pause: minutes=1

      roles:
        - role: letsencrypt
          letsencrypt_acme_step: two
          tags: letsencrypt

Completing other challenge types should be all the same and opaque to this role.

Testing

The tests are relying on the DNS challenge type and are solving it via AWS Route53.

If you want to run the tests on the provided docker environment, run the following commands:

$ cd /path/to/ansible-roles/letsencrypt
$ ansible-galaxy install \
    --force \
    --role-file=./tests/requirements.yml \
    --roles-path=./tests/dependencies
$ docker build \
    --no-cache \
    --pull \
    --tag ansible-roles-test \
    tests/support
$ docker run \
    --rm \
    --interactive \
    --tty \
    --volume $PWD:/etc/ansible/roles/letsencrypt \
    --volume $PWD/tests/dependencies:/etc/ansible/roles/letsencrypt/tests/roles:ro \
    --env AWS_ACCESS_KEY=$AWS_ACCESS_KEY \
    --env AWS_SECRET_KEY=$AWS_SECRET_KEY \
    --workdir /etc/ansible/roles/letsencrypt/tests \
    ansible-roles-test

To-do

  • Support other challenge types
  • Support other DNS services APIs (i.e. Cloud DNS)
  • Integration with some web servers roles (i.e. NGINX, Apache)
  • Support renewal
  • Support multiple Ansible versions and Distros
  • Update Ansible in the tests Docker image to be able to not specify the agreement for the DNS challenge.

License

This project is licensed under the terms of the GNU GPL v3.0 license.

Author Information

Role created by Dan Vaida.

Contributions

See the ToDo list. Contributions are welcome.