Ansible 部署证书
本文主要介绍如何结合 Ansible 与 cmcli 命令行工具自动化部署证书。
本文将结合 Ansible 与 cmcli 命令行工具,进行一次证书部署。由于实际部署的环境不同,请根据实际情况进行的灵活定制。
请注意: 本文不会过多介绍 Ansible 基础知识。基础知识请参考 Ansible 官方文档
准备工作
- Python 本文基于 Python 3.7
- Ansible 本文基于 Ansible 2.9.11
- cmcli 命令行工具
本示例部署证书的环境
- Nginx Docker 镜像
- Docker SDK for Python, 供 Ansible 的 docker_container 模块调用。可使用 pip 进行安装。
pip3 install docker
本示例文件目录结构
当完成配置完后当前的工作目录包括以下文件
|____hosts 配置Ansible inventory
|____play.yml 申请证书的playbook
|____ansible.cfg 配置文件
|____library
| |____request_cert.py 申请证书的模块
步骤
1. 申请证书
下文的例子,是申请多个单域名证书。可以根据实际情况编写参数。
这里主要是简单是了解 Ansible 的 Module 功能与 cmcli 结合,方便使用脚本,以下为示例。
# request_cert.py
# 调用 cmcli 命令,其中-t为OPEN API Token,-a为账户ID
cmd = 'cmcli enroll -u https://api.certcloud.cn \
-t {token} \
-a {account_id} --app-info "CertCloud-Ansible '
# 执行cmcli的命令
def get_cert(cmd):
process = subprocess.run(cmd, shell=True)
code = process.returncode
while code == 403:
process = subprocess.run(cmd, shell=True)
code = process.returncode
return process
def request():
module = AnsibleModule(argument_spec=dict(
domain_num=dict(required=True, type='int'),
validity=dict(required=True, type='int'), # 证书有效天数,填 1~365
domain=dict(required=True, type='str') # 申请的域名
))
debug_msg = [module.params['domain_num']]
basic_domain = module.params['domain']
threads = [] # 每个域名证书都会开启一个线程申请,可以按照具体情况分配
for a in range(1, module.params['domain_num']+1):
domain = str(a)+basic_domain
# 这里将 key-file 私钥,cert-file 证书都命名为当前申请的域名
request_cmd = cmd + \
"--key-file ./certs/{0}.key --cert-file ./certs/{0}.crt --cn {0} \
--validity {1}".format(
domain, module.params['validity'])
debug_msg.append(request_cmd)
t = threading.Thread(target=get_cert, args=[request_cmd])
threads.append(t)
t.start()
for t in threads:
t.join(timeout=60)
module.exit_json(changed=True, meta=debug_msg)
if __name__ == "__main__":
request()
2. 配置 playbook
以下是 playbook 示例。 其中配置需要的变量都在 hosts 文件中。
# play.yml
# 以下申请证书的过程可以在本地进行,然后部署到远程主机上
- hosts: local
tasks:
- name: 准备阶段 - 清空证书文件夹
file: path={{certs_dir}} state=absent #配置好本地申请的
tags: request
- name: 准备阶段 - 创建空的文件夹
file: path={{certs_dir}} state=directory
tags: request
- name: 请求200张证书
request_cert: # 这里调用我们上面写好的模块
# 下面的变量,都配置在 hosts 的变量中
domain: "{{domain}}"
domain_num: "{{instance_num}}"
validity: "{{validity}}"
tags: [request,certs]
loop_control:
label: "申请证书"
# 以下将申请好的证书发送到需要部署证书的主机群
- hosts: Remote
tasks:
- name: 同步证书文件
become: yes
become_user: root
synchronize:
src: "{{certs_dir}}"
dest: "{{remote_certs_dir}}"
tags: request
# 将 nginx 的容器中的配置改成申请的证书文件
- name: 在200台服务器上更新200张证书
shell: "docker exec {{ item }}{{ domain }}-nginx /bin/bash -c
'sed -i s?domain?certs/{{ item }}{{ domain }}?g /etc/nginx/nginx.conf &&
nginx -s reload'"
with_sequence: start=1 end={{ instance_num }}
tags: [replace, request]
# 以下 async,poll 可选,结合下文 mitogen 插件加快部署速度
async: 180
poll: 0
loop_control:
label: "为 https://{{ item }}{{ domain }}:{{item|int+https_port}} 部署证书"
# 可选,等待证书更新。
- name: 等待证书更新
wait_for:
timeout: 10
tags: [replace, request]
# 可选,起一定数量的服务器供实验
- name: 准备Web服务器
docker_container:
name: "{{ item }}{{ domain }}-nginx"
state: started
published_ports:
- "{{item|int+https_port}}:443"
# 这里给容器里的 Nginx 配置了一些证书的地址,方便替换,可以自行准备需要的容器。
image: nginx:1.19.1-demo
# 这里使用 volume 映射,让所有容器共用一个宿主机文件夹,方便所有容器共用。
volumes:
- "{{remote_certs_dir}}/certs:/etc/nginx/certs"
with_sequence: start=1 end={{ instance_num }}
tags: create_containers
async: 180
poll: 0
loop_control:
label: "创建 https://{{ item }}{{ domain }}:{{item|int+https_port}} 站点"
下面是 hosts 的配置示例
# hosts
[local]
localhost ansible_connection=local
[local:vars]
ansible_python_interpreter=/usr/bin/python3
[all:vars]
certs_dir=./certs
instance_num=200
domain=.cm2.httpsauto.com
https_port=50000
validity=30
# remote-host 是在 ssh config 里配置好的主机信息
[Remote]
remote-host
[Remote:vars]
ansible_python_interpreter=/usr/bin/python3
remote_certs_dir=/root/path
3. 运行 playbook
运行以下命令,可以申请并部署30天的证书:
ansible-playbook demo_play.yml --tags=request
可以通过在命令里加上 extra-vars, 填写 validity 有效期的值,可灵活改变证书申请的有效期。例如申请有效期365天的证书:
ansible-playbook demo_play.yml --tags=request --extra-vars="validity=365"
进阶
单节点加速部署
如果希望加快 Ansible 单节点的部署的速度,可使用 mitogen 插件加速。
先运行:
pip3 install mitogen
然后在 ansible.cfg 中配置 strategy 和 strategy_plugins 的插件信息。
macOS
strategy = mitogen_linear
strategy_plugins = $HOME/Library/Python/3.7/lib/python/site-packages/ansible_mitogen/plugins/strategy
Linux
strategy = mitogen_linear
strategy_plugins = /usr/local/lib/python3.7/site-packages/ansible_mitogen/plugins/strategy
Windows
strategy = mitogen_linear
strategy_plugins = C:\Python37\Lib\site-packages\site-packages\ansible_mitogen\plugins\strategy
多节点加速部署
可利用 fork、serial 等关键字配置,加快部署速率。具体方法参考官方文档。
以上是利用 Ansible 从 CertCloud 申请证书并部署到 Nginx 的示例。其他 Web 服务器也可以参考这篇文章,进行操作。Ansible 十分强大且灵活,请根据自己的需求进行自定义。
February 26, 2021