如何创建一个小型 CA
community.crypto 集合提供了多个模块,用于创建私钥、证书签名请求和证书。本指南展示了如何创建您自己的小型 CA,以及如何使用它来签署证书。
在所有示例中,我们假设 CA 的私钥是密码保护的,密码在 secret_ca_passphrase
变量中提供。
设置 CA
任何证书都可以用作 CA 证书。您可以创建自签名证书(请参阅如何创建自签名证书),使用另一个 CA 证书来签名新证书(使用下面签名证书的说明),请求(并支付费用)商业 CA 来签名您的 CA 证书等等。
以下说明展示了如何设置一个简单的自签名 CA 证书。
- name: Create private key with password protection
community.crypto.openssl_privatekey:
path: /path/to/ca-certificate.key
passphrase: "{{ secret_ca_passphrase }}"
- name: Create certificate signing request (CSR) for CA certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/ca-certificate.key
privatekey_passphrase: "{{ secret_ca_passphrase }}"
common_name: Ansible CA
use_common_name_for_san: false # since we do not specify SANs, don't use CN as a SAN
basic_constraints:
- 'CA:TRUE'
basic_constraints_critical: true
key_usage:
- keyCertSign
key_usage_critical: true
register: ca_csr
- name: Create self-signed CA certificate from CSR
community.crypto.x509_certificate:
path: /path/to/ca-certificate.pem
csr_content: "{{ ca_csr.csr }}"
privatekey_path: /path/to/ca-certificate.key
privatekey_passphrase: "{{ secret_ca_passphrase }}"
provider: selfsigned
使用 CA 签署证书
要签名证书,您必须将 CSR 传递给 community.crypto.x509_certificate 模块 或 community.crypto.x509_certificate_pipe 模块。
在以下示例中,我们假设要签名的证书(包括其私钥)位于 server_1
上,而我们的 CA 证书位于 server_2
上。我们不希望任何密钥材料离开各自的服务器。
- name: Create private key for new certificate on server_1
community.crypto.openssl_privatekey:
path: /path/to/certificate.key
delegate_to: server_1
run_once: true
- name: Create certificate signing request (CSR) for new certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/certificate.key
subject_alt_name:
- "DNS:ansible.com"
- "DNS:www.ansible.com"
- "DNS:docs.ansible.com"
delegate_to: server_1
run_once: true
register: csr
- name: Sign certificate with our CA
community.crypto.x509_certificate_pipe:
csr_content: "{{ csr.csr }}"
provider: ownca
ownca_path: /path/to/ca-certificate.pem
ownca_privatekey_path: /path/to/ca-certificate.key
ownca_privatekey_passphrase: "{{ secret_ca_passphrase }}"
ownca_not_after: +365d # valid for one year
ownca_not_before: "-1d" # valid since yesterday
delegate_to: server_2
run_once: true
register: certificate
- name: Write certificate file on server_1
copy:
dest: /path/to/certificate.pem
content: "{{ certificate.certificate }}"
delegate_to: server_1
run_once: true
请注意,以上过程是非幂等的。以下扩展示例从 server_1
读取现有证书(如果存在),并将其提供给 community.crypto.x509_certificate_pipe 模块,并且仅在更改时才将结果写回
- name: Create private key for new certificate on server_1
community.crypto.openssl_privatekey:
path: /path/to/certificate.key
delegate_to: server_1
run_once: true
- name: Create certificate signing request (CSR) for new certificate
community.crypto.openssl_csr_pipe:
privatekey_path: /path/to/certificate.key
subject_alt_name:
- "DNS:ansible.com"
- "DNS:www.ansible.com"
- "DNS:docs.ansible.com"
delegate_to: server_1
run_once: true
register: csr
- name: Check whether certificate exists
stat:
path: /path/to/certificate.pem
delegate_to: server_1
run_once: true
register: certificate_exists
- name: Read existing certificate if exists
slurp:
src: /path/to/certificate.pem
when: certificate_exists.stat.exists
delegate_to: server_1
run_once: true
register: certificate
- name: Sign certificate with our CA
community.crypto.x509_certificate_pipe:
content: "{{ (certificate.content | b64decode) if certificate_exists.stat.exists else omit }}"
csr_content: "{{ csr.csr }}"
provider: ownca
ownca_path: /path/to/ca-certificate.pem
ownca_privatekey_path: /path/to/ca-certificate.key
ownca_privatekey_passphrase: "{{ secret_ca_passphrase }}"
ownca_not_after: +365d # valid for one year
ownca_not_before: "-1d" # valid since yesterday
delegate_to: server_2
run_once: true
register: certificate
- name: Write certificate file on server_1
copy:
dest: /path/to/certificate.pem
content: "{{ certificate.certificate }}"
delegate_to: server_1
run_once: true
when: certificate is changed