如何在 Ubuntu 18.04 上使用 Ansible 获取 Let's Encrypt 证书

作者选择电子前沿Foundation接受捐赠]作为写入捐赠计划的一部分。

简介

现代基础设施管理最好使用自动化流程和工具完成。使用标准的Certbot客户端获取Let's Encrypt证书既快捷又简单,但通常在调试服务器时必须手动完成。这对于单个服务器设置来说是可管理的,但在部署更大的机群时可能会变得繁琐。

使用Ansible)等配置管理工具获取证书使此任务完全自动化且可重现。如果您需要重建或更新服务器,只需运行您的Anable playbook,],而不必再次手动执行这些步骤。

在本教程中,您将编写一本Ansible攻略来为Ansible主机自动获取We‘s Encrypt证书。

前提条件

要完成本教程,您需要:

第一台服务器将用作您的Ansible服务器,在本教程中我们将其称为Ansible服务器 。这是Ansible将运行以将命令发送到主机的位置。或者,您可以使用您的本地计算机或将您的Anable库存配置为您的** Anable服务器** 的任何其他计算机。

在您的可移动服务器 上,您将需要:

  • 正确配置的可解析安装,可以通过遵循如何在Ubuntu 18.04.上安装和配置可解析的主机》来连接到可解析的主机

第二台服务器将用作Ansible主机,在本教程中我们将其称为 host machine 。这是您要配置和颁发证书的计算机。此计算机还将运行Web服务器以提供证书颁发验证文件。

在您的主机 上,您需要:

  • 您有资格获得TLS证书的域名,且所需的DNS记录配置为指向您的Ansible 宿主机** 。在此特定示例中,攻略将获取一个对you-domainwww.you-domain有效的证书,但如果需要,可以针对其他域名或子域进行调整。
  • 可以通过端口80(Http)从互联网访问的Web服务器,例如,遵循如何在Ubuntu 18.04.上安装ApacheWeb服务器》中的步骤1、2和3这也可以是Nginx服务器或任何其他合适的Web服务器软件。

准备就绪后,以非根用户身份登录到您的可用服务器 即可开始。

第一步-配置我们加密Anable模块的设置

Ansible内置了一个名为letsEncrypt的模块,允许您使用acme(自动证书管理Environment)协议)获取有效的tls证书。

在第一步中,您将添加一个主机变量配置文件,以定义使用该模块所需的配置变量。

<$>[备注] 注意: 自Ansipe2.6起,letsEncrypt模块已更名为acme_certificateletsEncrypt名称现在是acme_certificate的别名,所以仍然可以使用,但您可能希望使用acme_certificate,以确保您的剧本面向未来。您可以使用ansible--version查看您的Ansible版本。截至撰写本教程时,Ubuntu 18.04 APT存储库还不支持acme_certificate。 <$>

首先,在您的可移植服务器 上创建host_vars可移植目录:

1sudo mkdir /etc/ansible/host_vars

接下来,在/etc/ansible/host_vars目录下创建一个新文件,文件名为您的Ansible host 机器。在本例中,您将使用host 1作为主机的名称:

1sudo nano /etc/ansible/host_vars/host1

下面的示例配置包括您开始使用时所需的一切,包括:验证方法和服务器地址、接收证书到期提醒的电子邮件地址,以及保存Let's Encrypt密钥和证书的目录。

将示例配置复制到文件中:

 1[label /etc/ansible/host_vars/host1]
 2---
 3acme_challenge_type: http-01
 4acme_directory: https://acme-v02.api.letsencrypt.org/directory
 5acme_version: 2
 6acme_email: certificate-reminders@your-domain
 7letsencrypt_dir: /etc/letsencrypt
 8letsencrypt_keys_dir: /etc/letsencrypt/keys
 9letsencrypt_csrs_dir: /etc/letsencrypt/csrs
10letsencrypt_certs_dir: /etc/letsencrypt/certs
11letsencrypt_account_key: /etc/letsencrypt/account/account.key
12domain_name: your-domain

完成后保存并关闭该文件。

根据需要调整域名和邮箱地址。你可以使用任何电子邮件地址--它不一定是Your-Domain上的那个。

您的服务器上可能还不存在某些定义的目录/文件路径。这是可以的;攻略的第一部分将是创建这些目录并分配相关权限。

您已经将所需的配置变量添加到Ansible清单文件中。接下来,您将开始编写攻略以获取证书。

第二步-创建让我们加密目录和帐号密钥

在本步骤中,您将编写用于创建所需的We‘s Encrypted目录、分配正确权限和生成We’s Encrypt帐户密钥的Anable任务。

首先,在您的Ansible服务器 上,在您选择的新目录下创建一个名为letscrypt-Issue.yml的新剧本,例如/home/user/ansible-playbooks

1cd ~
2mkdir ansible-playbooks
3cd ansible-playbooks
4nano letsencrypt-issue.yml

在开始编写Ansible任务之前,您需要指定主机和相关设置。根据您在先决条件教程中引用主机的方式调整以下内容。然后将以下内容添加到文件的顶部:

1[label letsencrypt-issue.yml]
2---
3- hosts: "host1"
4  tasks:

现在您可以开始编写所需的任务,第一个任务是创建存储We‘s Encrypt文件所需的文件系统目录。在前面的内容之后,将以下Ansible任务添加到文件中:

 1[label letsencrypt-issue.yml]
 2...
 3  - name: "Create required directories in /etc/letsencrypt"
 4    file:
 5      path: "/etc/letsencrypt/{{ item }}"
 6      state: directory
 7      owner: root
 8      group: root
 9      mode: u=rwx,g=x,o=x
10    with_items:
11    - account
12    - certs
13    - csrs
14    - keys

此Ansible任务将在/etc/letsencrypt中创建accountcertscsrskeys目录,获取证书所需的文件将存储在该目录中。

您将目录的所有者设置为root,并应用权限u=rwx,g=x,o=x,这样只有root才有读写权限。建议这样做,因为目录将包含私钥证书签名请求(CSRs),和签名证书,它们应该保密。

接下来,需要创建We‘s Encrypt帐户密钥。您将使用它向We‘s Encrypt服务标识您的身份。

将以下任务添加到您的行动手册中:

1[label letsencrypt-issue.yml]
2...
3  - name: "Generate a Let's Encrypt account key"
4    shell: "if [ ! -f {{ letsencrypt_account_key }} ]; then openssl genrsa 4096 | sudo tee {{ letsencrypt_account_key }}; fi"

不需要在每次续订证书时重新创建帐户密钥,因此还需要添加对现有密钥的检查if [!-f {{ letsencrypt_account_key }} ];,以确保它不会被覆盖。

在下一步中,您将继续在letsENCRYPT-Issue.yml中工作,所以暂时不要关闭此文件。

您已经创建了playbook并设置了初始配置和任务,以便准备获取Let's Encrypt证书。接下来,您将为私钥和CSR生成添加更多任务。

Step 3 -生成私钥和证书签名请求

在本步骤中,您将编写剧本任务以生成所需的私钥和证书签名请求。

本节中的第一个任务将为您的证书生成所需的私钥。将以下内容添加到您在步骤2中开始编写的攻略末尾:

1[label letsencrypt-issue.yml]
2...
3  - name: "Generate Let's Encrypt private key"
4    shell: "openssl genrsa 4096 | sudo tee /etc/letsencrypt/keys/{{ domain_name }}.key"

同一域名下的子域都会通过主题备用名(SANs),]添加到同一个证书中,暂时只需要生成一个私钥即可。

您将使用下一个任务为要获取的证书生成证书签名请求(CSR)。这是提交给让我们加密,以便他们验证和颁发每个证书。

在攻略的末尾添加以下内容:

1[label letsencrypt-issue.yml]
2...
3  - name: "Generate Let's Encrypt CSR"
4    shell: "openssl req -new -sha256 -key /etc/letsencrypt/keys/{{ domain_name }}.key -subj \"/CN={{ domain_name }}\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"\n[SAN]\nsubjectAltName=DNS:{{ domain_name }},DNS:www.{{ domain_name }}\")) | sudo tee /etc/letsencrypt/csrs/{{ domain_name }}.csr"
5    args:
6      executable: /bin/bash

此任务为您的域生成CSR,并将www子域作为SAN添加到证书中。

在下一步中,您将继续在letsENCRYPT-Issue.yml中工作,所以暂时不要关闭此文件。

您已经编写了Ansible任务来为您的证书生成私钥和CSR。接下来,您将处理将开始验证和发布过程的任务。

第四步-启动ACME验证流程

在本步骤中,您将编写一个任务,使用步骤3中记录的任务的输出文件将证书签名请求提交给We‘s Encryption。这将返回一些challenge文件,您需要在您的Web服务器上提供这些文件,以证明您正在为其请求证书的域名和子域的所有权。

以下任务将提交you-domain的CSR。将其添加到您的攻略的末尾:

 1[label letsencrypt-issue.yml]
 2...
 3  - name: "Begin Let's Encrypt challenges"
 4    letsencrypt:
 5      acme_directory: "{{ acme_directory }}"
 6      acme_version: "{{ acme_version }}"
 7      account_key_src: "{{ letsencrypt_account_key }}"
 8      account_email: "{{ acme_email }}"
 9      terms_agreed: 1
10      challenge: "{{ acme_challenge_type }}"
11      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
12      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
13      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}.crt"
14      remaining_days: 91
15    register: acme_challenge_your_domain

此任务广泛使用您在步骤1中配置的变量。它注册一个变量,其中包含您将在下一步中使用的ACME质询文件。您需要手动调整变量名,使其包含you-domain,但将所有.字符替换为_,因为变量名中不能使用圆点。例如,Example.com的变量将变为acme_challenger_Example_com

在下一步中,您将继续在letsENCRYPT-Issue.yml中工作,所以暂时不要关闭此文件。

您已经编写了一项任务,将您的CSR提交给We‘s Encryption。接下来,您将添加一项任务来实施ACME质询文件,以最终完成证书验证过程。

第五步-实施ACME挑战文件

在本步骤中,您将编写一个可分析的任务来读取和实施ACME质询文件。这些文件证明您有资格获得所请求的域和子域的证书。

ACME Challenger files必须在监听80端口的Web服务器上,位于您要申请证书的域名或子域的/.well/acme-challengl/路径下。例如,为了验证www.Your-Domain的证书请求,需要能够通过Internet访问位于以下路径的acme质询文件:http://www.your-domain/.well-known/acme-challenge.

根据您当前的Web服务器设置,在所需目标位置提供这些文件的方法会有很大不同。但是,在本指南中,我们将假设您已经配置了Web服务器(根据必备教程),以提供/var/www/html目录中的文件。因此,您可能需要相应地调整任务,以便与您自己的Web服务器设置兼容。

首先,添加以下任务,创建.well-known/acme-challenge/目录结构,以便将文件提供到playbook的末尾:

1[label letsencrypt-issue.yml]
2...
3  - name: "Create .well-known/acme-challenge directory"
4    file:
5      path: /var/www/html/.well-known/acme-challenge
6      state: directory
7      owner: root
8      group: root
9      mode: u=rwx,g=rx,o=rx

如果您的Web服务器使用/var/www/html以外的目录提供文件,请确保相应地调整路径。

接下来,您将通过以下任务实现在步骤4中保存到acme_challengl_you-domain变量中的ACME质询文件:

 1[label letsencrypt-issue.yml]
 2...
 3  - name: "Implement http-01 challenge files"
 4    copy:
 5      content: "{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource_value'] }}"
 6      dest: "/var/www/html/{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource'] }}"
 7      owner: root
 8      group: root
 9      mode: u=rw,g=r,o=r
10    with_items:
11    - "{{ domain_name }}"
12    - "www.{{ domain_name }}"

需要注意的是,您需要手动将任务中的acme_challengl_Your_domain变量名调整为您的ACME挑战变量的名称,即acme_challenger_后跟您的域名,但将所有的.字符替换为_。此Anable任务将ACME验证文件从变量复制到您的Web服务器上的.well-now/acme-challenge路径中。这将允许我们加密检索它们,以便验证域的所有权和您是否有资格获得证书。

在下一步中,您将继续在letsENCRYPT-Issue.yml中工作,所以暂时不要关闭此文件。

您已经编写了创建ACME验证目录和文件所需的Ansible任务。接下来,您将完成ACME验证过程并获取签名证书。

第六步-获取您的证书

在本步骤中,您将编写一个任务来触发We‘s Encrypt以验证您提交的ACME质询文件,这将允许您获取您的签名证书(S)。

以下任务验证您在步骤5中实施的ACME质询文件,并将您的签名证书保存到指定路径。将其添加到您的攻略的末尾:

 1[label letsencrypt-issue.yml]
 2...
 3  - name: "Complete Let's Encrypt challenges"
 4    letsencrypt:
 5      acme_directory: "{{ acme_directory }}"
 6      acme_version: "{{ acme_version }}"
 7      account_key_src: "{{ letsencrypt_account_key }}"
 8      account_email: "{{ acme_email }}"
 9      challenge: "{{ acme_challenge_type }}"
10      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
11      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
12      chain_dest: "{{ letsencrypt_certs_dir }}/chain_{{ domain_name }}.crt"
13      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}"
14      data: "{{ acme_challenge_your_domain }}"

与步骤4类似,此任务使用您在步骤1中配置的变量。任务完成后,它会将签名的证书保存到指定的路径,允许您开始将其用于应用程序或服务。

请注意,您需要手动调整任务中的data值,以将其设置为您的ACME质询变量的名称,类似于步骤5。

以下是显示您添加的每项任务的完整攻略:

 1[label letsencrypt-issue.yml]
 2- hosts: "host1"
 3  tasks:
 4
 5  - name: "Create required directories in /etc/letsencrypt"
 6    file:
 7      path: "/etc/letsencrypt/{{ item }}"
 8      state: directory
 9      owner: root
10      group: root
11      mode: u=rwx,g=x,o=x
12    with_items:
13    - account
14    - certs
15    - csrs
16    - keys
17
18  - name: "Generate a Let's Encrypt account key"
19    shell: "if [ ! -f {{ letsencrypt_account_key }} ]; then openssl genrsa 4096 | sudo tee {{ letsencrypt_account_key }}; fi"
20
21  - name: "Generate Let's Encrypt private key"
22    shell: "openssl genrsa 4096 | sudo tee /etc/letsencrypt/keys/{{ domain_name }}.key"
23
24  - name: "Generate Let's Encrypt CSR"
25    shell: "openssl req -new -sha256 -key /etc/letsencrypt/keys/{{ domain_name }}.key -subj \"/CN={{ domain_name }}\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"\n[SAN]\nsubjectAltName=DNS:{{ domain_name }},DNS:www.{{ domain_name }}\")) | sudo tee /etc/letsencrypt/csrs/{{ domain_name }}.csr"
26    args:
27      executable: /bin/bash
28
29  - name: "Begin Let's Encrypt challenges"
30    letsencrypt:
31      acme_directory: "{{ acme_directory }}"
32      acme_version: "{{ acme_version }}"
33      account_key_src: "{{ letsencrypt_account_key }}"
34      account_email: "{{ acme_email }}"
35      terms_agreed: 1
36      challenge: "{{ acme_challenge_type }}"
37      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
38      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
39      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}.crt"
40      remaining_days: 91
41    register: acme_challenge_your_domain
42
43  - name: "Create .well-known/acme-challenge directory"
44    file:
45      path: /var/www/html/.well-known/acme-challenge
46      state: directory
47      owner: root
48      group: root
49      mode: u=rwx,g=rx,o=rx
50
51  - name: "Implement http-01 challenge files"
52    copy:
53      content: "{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource_value'] }}"
54      dest: "/var/www/html/{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource'] }}"
55      owner: root
56      group: root
57      mode: u=rw,g=r,o=r
58    with_items:
59    - "{{ domain_name }}"
60    - "www.{{ domain_name }}"
61
62  - name: "Complete Let's Encrypt challenges"
63    letsencrypt:
64      acme_directory: "{{ acme_directory }}"
65      acme_version: "{{ acme_version }}"
66      account_key_src: "{{ letsencrypt_account_key }}"
67      account_email: "{{ acme_email }}"
68      challenge: "{{ acme_challenge_type }}"
69      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
70      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
71      chain_dest: "{{ letsencrypt_certs_dir }}/chain_{{ domain_name }}.crt"
72      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}"
73      data: "{{ acme_challenge_your_domain }}"

完成后保存并关闭您的文件。

您已经添加了完成ACME挑战并获取签名证书的任务。接下来,您将在Ansible主机 上运行剧本,以便运行所有操作。

第7步-运行攻略

现在您已经编写了攻略和所有必需的任务,您可以在您的Ansible主机 上运行它来颁发证书。

在您的 Ansible服务器 上,可以使用ansible-playbook命令运行playbook:

1ansible-playbook letsencrypt-issue.yml

这将运行剧本,一次执行一项任务。您将看到类似于以下内容的输出:

 1[secondary_label Output]
 2PLAY [host1] **********************************************************************************
 3
 4TASK [Gathering Facts] ************************************************************************
 5ok: [host1]
 6
 7TASK [Create required directories in /etc/letsencrypt] ****************************************
 8changed: [host1] => (item=account)
 9changed: [host1] => (item=certs)
10changed: [host1] => (item=csrs)
11changed: [host1] => (item=keys)
12
13TASK [Generate a Let's Encrypt account key] ***************************************************
14changed: [host1]
15
16TASK [Generate Let's Encrypt private key] *****************************************************
17changed: [host1]
18
19TASK [Generate Let's Encrypt CSR] *************************************************************
20changed: [host1]
21
22TASK [Begin Let's Encrypt challenges] *********************************************************
23changed: [host1]
24
25TASK [Create .well-known/acme-challenge directory] ********************************************
26changed: [host1]
27
28TASK [Implement http-01 challenge files] ******************************************************
29changed: [host1] => (item=your-domain)
30changed: [host1] => (item=www.your-domain)
31
32TASK [Complete Let's Encrypt challenges] ******************************************************
33changed: [host1]
34
35PLAY RECAP ************************************************************************************
36host1                      : ok=9 changed=8 unreachable=0 failed=0

如果在playbook运行时遇到任何错误,这些错误将输出供您查看。

一旦攻略完成,您的有效We‘s Encrypt证书将保存到您主机 上的/etc/letscrypt/certs目录中。然后,您可以使用该密钥以及/etc/letscrypt/keys中的私钥来保护与您的Web服务器、邮件服务器等的连接。

让我们加密证书,默认情况下证书的有效期为90天。您将通过电子邮件将续订提醒发送到您在步骤1中指定的地址。要续订您的证书,您可以再次运行攻略。确保使用您的证书的任何服务都已采用新证书,因为有时您可能需要手动安装它、将其移动到特定目录或重新启动服务以使其正确采用新证书。

在这一步中,您运行了您的剧本,其中发布了有效的We‘s Encrypt证书。

结论

在本文中,您编写了一本Anable攻略来请求和获取有效的We‘s Encrypt证书。

下一步,您可以考虑使用您的新剧本为大量服务器颁发证书。您甚至可以创建一个中央ACME验证服务器,该服务器可以集中颁发证书并将其分发到Web服务器。

最后,如果您想了解更多关于ACME规范和Let's Encrypt项目的信息,您可能希望查看以下链接:

您可能还想查看其他一些相关的Anable教程:

Published At
Categories with 技术
comments powered by Disqus