作者选择电子前沿Foundation接受捐赠]作为写入捐赠计划的一部分。
简介
现代基础设施管理最好使用自动化流程和工具完成。使用标准的Certbot客户端获取Let's Encrypt证书既快捷又简单,但通常在调试服务器时必须手动完成。这对于单个服务器设置来说是可管理的,但在部署更大的机群时可能会变得繁琐。
使用Ansible)等配置管理工具获取证书使此任务完全自动化且可重现。如果您需要重建或更新服务器,只需运行您的Anable playbook,],而不必再次手动执行这些步骤。
在本教程中,您将编写一本Ansible攻略来为Ansible主机自动获取We‘s Encrypt证书。
前提条件
要完成本教程,您需要:
- 两台Ubuntu 18.04服务器按照Ubuntu 18.04初始服务器设置设置,包括一个sudo非root用户。
第一台服务器将用作您的Ansible服务器,在本教程中我们将其称为Ansible服务器 。这是Ansible将运行以将命令发送到主机的位置。或者,您可以使用您的本地计算机或将您的Anable库存配置为您的** Anable服务器** 的任何其他计算机。
在您的可移动服务器 上,您将需要:
- 正确配置的可解析安装,可以通过遵循如何在Ubuntu 18.04.上安装和配置可解析的主机》来连接到可解析的主机
第二台服务器将用作Ansible主机,在本教程中我们将其称为 host machine 。这是您要配置和颁发证书的计算机。此计算机还将运行Web服务器以提供证书颁发验证文件。
在您的主机 上,您需要:
- 您有资格获得TLS证书的域名,且所需的DNS记录配置为指向您的Ansible 宿主机** 。在此特定示例中,攻略将获取一个对
you-domain
和www.you-domain
有效的证书,但如果需要,可以针对其他域名或子域进行调整。 - 可以通过端口
80
(Http)从互联网访问的Web服务器,例如,遵循如何在Ubuntu 18.04.上安装ApacheWeb服务器》中的步骤1、2和3这也可以是Nginx服务器或任何其他合适的Web服务器软件。
准备就绪后,以非根用户身份登录到您的可用服务器 即可开始。
第一步-配置我们加密Anable模块的设置
Ansible内置了一个名为letsEncrypt
的模块,允许您使用acme(自动证书管理Environment)协议)获取有效的tls证书。
在第一步中,您将添加一个主机变量配置文件,以定义使用该模块所需的配置变量。
<$>[备注]
注意: 自Ansipe2.6起,letsEncrypt
模块已更名为acme_certificate
。letsEncrypt
名称现在是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
中创建account
、certs
、csrs
和keys
目录,获取证书所需的文件将存储在该目录中。
您将目录的所有者设置为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教程: