Introduction
The community.crypto collection provides Ansible modules for complete PKI management — generate private keys, create CSRs, sign certificates, build certificate authorities, manage certificate chains, and check expiry. No need for manual openssl commands; everything is declarative and idempotent.
Prerequisites
ansible-galaxy collection install community.crypto
pip install cryptography
Module Reference
| Module | Purpose |
|---|---|
openssl_privatekey | Generate RSA/EC private keys |
openssl_csr | Create Certificate Signing Requests |
x509_certificate | Generate/sign certificates |
x509_certificate_info | Read certificate details |
certificate_complete_chain | Build certificate chains |
openssl_pkcs12 | Create PKCS12 keystores |
Generate Private Key
- name: Generate RSA private key
community.crypto.openssl_privatekey:
path: /etc/ssl/private/server.key
size: 4096
type: RSA
mode: '0600'
- name: Generate EC private key (faster, smaller)
community.crypto.openssl_privatekey:
path: /etc/ssl/private/server-ec.key
type: ECC
curve: secp384r1
mode: '0600'
Create CSR
- name: Generate CSR
community.crypto.openssl_csr:
path: /etc/ssl/csr/server.csr
privatekey_path: /etc/ssl/private/server.key
common_name: www.example.com
organization_name: Example Corp
organizational_unit_name: IT
country_name: US
state_or_province_name: California
locality_name: San Francisco
email_address: admin@example.com
subject_alt_name:
- "DNS:www.example.com"
- "DNS:example.com"
- "DNS:api.example.com"
- "IP:203.0.113.10"
key_usage:
- digitalSignature
- keyEncipherment
extended_key_usage:
- serverAuth
- clientAuth
Self-Signed Certificate
- name: Generate self-signed certificate
community.crypto.x509_certificate:
path: /etc/ssl/certs/server.crt
privatekey_path: /etc/ssl/private/server.key
csr_path: /etc/ssl/csr/server.csr
provider: selfsigned
selfsigned_not_after: "+365d"
mode: '0644'
Build a Certificate Authority
Root CA
---
- name: Create Certificate Authority
hosts: ca_server
become: true
vars:
ca_dir: /etc/pki/ca
tasks:
- name: Create CA directories
ansible.builtin.file:
path: "{{ ca_dir }}/{{ item }}"
state: directory
mode: '0700'
loop: [private, certs, csr, newcerts]
- name: Generate CA private key
community.crypto.openssl_privatekey:
path: "{{ ca_dir }}/private/ca.key"
size: 4096
mode: '0400'
passphrase: "{{ vault_ca_passphrase }}"
cipher: auto
- name: Generate CA CSR
community.crypto.openssl_csr:
path: "{{ ca_dir }}/csr/ca.csr"
privatekey_path: "{{ ca_dir }}/private/ca.key"
privatekey_passphrase: "{{ vault_ca_passphrase }}"
common_name: "Example Corp Root CA"
organization_name: "Example Corp"
country_name: US
basic_constraints:
- "CA:TRUE"
- "pathlen:1"
basic_constraints_critical: true
key_usage:
- keyCertSign
- cRLSign
key_usage_critical: true
- name: Self-sign CA certificate
community.crypto.x509_certificate:
path: "{{ ca_dir }}/certs/ca.crt"
privatekey_path: "{{ ca_dir }}/private/ca.key"
privatekey_passphrase: "{{ vault_ca_passphrase }}"
csr_path: "{{ ca_dir }}/csr/ca.csr"
provider: selfsigned
selfsigned_not_after: "+3650d"
mode: '0644'
Sign Server Certificates
- name: Sign certificate with CA
community.crypto.x509_certificate:
path: /etc/ssl/certs/server.crt
csr_path: /etc/ssl/csr/server.csr
ownca_path: "{{ ca_dir }}/certs/ca.crt"
ownca_privatekey_path: "{{ ca_dir }}/private/ca.key"
ownca_privatekey_passphrase: "{{ vault_ca_passphrase }}"
ownca_not_after: "+365d"
provider: ownca
mode: '0644'
Distribute CA Certificate
- name: Distribute CA certificate to all servers
hosts: all
become: true
tasks:
- name: Copy CA cert
ansible.builtin.copy:
src: "{{ ca_dir }}/certs/ca.crt"
dest: /usr/local/share/ca-certificates/example-ca.crt
mode: '0644'
- name: Update CA trust store
ansible.builtin.command: update-ca-certificates
changed_when: true
Check Certificate Expiry
- name: Check certificate info
community.crypto.x509_certificate_info:
path: /etc/ssl/certs/server.crt
register: cert_info
- name: Display certificate details
ansible.builtin.debug:
msg: |
Subject: {{ cert_info.subject }}
Issuer: {{ cert_info.issuer }}
Not After: {{ cert_info.not_after }}
SANs: {{ cert_info.subject_alt_name }}
- name: Alert if expiring within 30 days
ansible.builtin.assert:
that:
- cert_info.not_after is community.crypto.x509_certificate_info
fail_msg: "Certificate expires soon: {{ cert_info.not_after }}"
ignore_errors: true
Fleet-Wide Certificate Audit
---
- name: Audit all TLS certificates
hosts: all
become: true
tasks:
- name: Find all certificates
ansible.builtin.find:
paths:
- /etc/ssl/certs
- /etc/nginx/ssl
- /etc/haproxy/certs
patterns: "*.crt,*.pem"
recurse: true
register: cert_files
- name: Check each certificate
community.crypto.x509_certificate_info:
path: "{{ item.path }}"
loop: "{{ cert_files.files }}"
register: all_certs
- name: Report expiring certificates
ansible.builtin.debug:
msg: "⚠️ {{ item.item.path }} expires {{ item.not_after }}"
loop: "{{ all_certs.results }}"
when: item.not_after is defined
PKCS12 Keystore (Java/Tomcat)
- name: Create PKCS12 keystore
community.crypto.openssl_pkcs12:
action: export
path: /etc/ssl/keystore.p12
privatekey_path: /etc/ssl/private/server.key
certificate_path: /etc/ssl/certs/server.crt
other_certificates:
- /etc/ssl/certs/ca.crt
passphrase: "{{ vault_keystore_password }}"
friendly_name: server
mode: '0600'
Certificate Chain
- name: Build complete certificate chain
ansible.builtin.assemble:
src: /etc/ssl/chain-parts/
dest: /etc/ssl/certs/fullchain.pem
mode: '0644'
# Directory should contain: server.crt, intermediate.crt, root.crt
Troubleshooting
Verify Certificate Matches Key
- name: Get certificate modulus
ansible.builtin.command: openssl x509 -noout -modulus -in /etc/ssl/certs/server.crt
register: cert_modulus
changed_when: false
- name: Get key modulus
ansible.builtin.command: openssl rsa -noout -modulus -in /etc/ssl/private/server.key
register: key_modulus
changed_when: false
- name: Verify match
ansible.builtin.assert:
that: cert_modulus.stdout == key_modulus.stdout
fail_msg: "Certificate and key do not match!"
Related Articles
Conclusion
The community.crypto collection makes PKI management fully declarative — generate keys, create CSRs, build CAs, sign certificates, check expiry, and create keystores without a single openssl command. Use self-signed certs for internal services, your own CA for fleet-wide trust, and Let's Encrypt for public-facing services. Certificate management as code means every cert is tracked, versioned, and reproducible.