Certificate Authority Role — Linux Hosts
This page covers issuing certificates to Linux hosts. Two workflows are supported:
- Ansible-internal CA — the role generates a key and CSR on the Linux target, signs the CSR on the control node, and writes the certificate to the target.
- Windows delegate host (Microsoft CA) — the CSR is generated and signed on a Windows delegate using
certreq.exe, the resulting PFX is exported, and then the certificate and key are extracted and pushed to the Linux target.
See the overview for guidance on choosing a signing back-end and the full tag reference.
Tags Used
| Tag | Description |
|---|---|
generate_key_linux |
Generate an RSA or ECC private key on the Linux host |
generate_csr_linux |
Generate a CSR on the Linux host and load it for signing |
sign_certificate |
Sign the CSR with the Ansible-managed CA on the control node |
write_certificate_linux |
Write the signed certificate PEM to a file on the Linux host |
deploy_certificate_linux |
Fetch a PFX from a Windows delegate host, extract the cert and key on the controller, and push them to the Linux target |
Prerequisites
Ansible-internal CA workflow
- A root CA must exist at
extra_vars/certificate_authority.yml. See Generating the Ansible Root CA. - The vault file must be loaded at run time via
-e @extra_vars/certificate_authority.yml. python3-cryptographymust be available on the target. Thegenerate_key_linuxandgenerate_csr_linuxtasks install it automatically viadnf/apt.- The play must run with
--become(orbecome: true) when writing to privileged paths such as/etc/ssl/private/.
Windows delegate host workflow
- A Windows host must be available as
certificate_authority_delegate_hostand have enrollment access to the Microsoft CA. - The certificate must have been issued with
certificate_authority_cert_exportable: true. - The Python
cryptographylibrary must be available on the Ansible control node (already required bycommunity.crypto). - The play must run with
--becomewhen writing to privileged paths on the Linux target. - Always use
--forks=1when targeting multiple Linux hosts — concurrentcertreq.exeoperations against the same Windows delegate can corrupt pending requests.
Usage
Issue a certificate via Ansible CA (full chain)
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags generate_key_linux,generate_csr_linux,sign_certificate,write_certificate_linux \
-e @extra_vars/certificate_authority.yml \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
-e certificate_authority_linux_cert_path=/etc/ssl/certs/myhost.crt \
--become
Deploying via a Windows delegate host (Microsoft CA)
Use this workflow when a Microsoft Enterprise CA must sign the certificate. The CSR, signing, and PFX export all happen on the Windows delegate. The deploy_certificate_linux tag then:
- Fetches the PFX from the Windows delegate to the controller.
- Extracts the certificate and private key from the PFX on the controller using the Python
cryptographylibrary. - Pushes the certificate and key to the Linux target at
certificate_authority_linux_cert_pathandcertificate_authority_linux_key_path. - Removes the certificate from the delegate's
LocalMachine\Mystore. - Cleans up temporary PFX, cert, and key files from the controller's
/tmp.
ansible-playbook --limit=mylinuxhost.example.com --forks=1 playbooks/certificate-authority-issue.yml \
--tags generate_csr_windows,sign_certificate_microsoft_ca,import_certificate_windows,export_certificate_windows,deploy_certificate_linux \
-e 'certificate_authority_cert_template=SANWebServer(90Days)' \
-e certificate_authority_delegate_host=mywindowshost.example.com \
-e certificate_authority_cert_exportable=true \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
-e certificate_authority_linux_cert_path=/etc/ssl/certs/myhost.crt \
--become
One target at a time
Always use --forks=1 when running against multiple Linux hosts with a delegate. Concurrent certreq.exe operations on the same Windows delegate can corrupt pending requests.
Exportable flag must be set at request time
The private key can only be extracted from the PFX if the original CSR was generated with certificate_authority_cert_exportable: true. Set this before generate_csr_windows runs — there is no way to export an already-issued non-exportable certificate.
Running steps individually
# Generate the private key only
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags generate_key_linux \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
--become
# Generate a CSR only (content is shown in task output and loaded into certificate_authority_sign_csr)
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags generate_csr_linux \
-e @extra_vars/certificate_authority.yml \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
--become
# Write a certificate that was already signed (pass cert content directly)
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags write_certificate_linux \
-e certificate_authority_linux_cert_path=/etc/ssl/certs/myhost.crt \
-e certificate_authority_cert_content="$(cat signed.pem)" \
--become
Replacing an existing certificate
Renew cert and key (keep 2 backups)
Set certificate_authority_cert_keep_copies to rotate old files into numbered backups before writing the new ones. .1 is the most recent backup; .2 is one older; and so on. Files older than the limit are pruned automatically.
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags generate_key_linux,generate_csr_linux,sign_certificate,write_certificate_linux \
-e @extra_vars/certificate_authority.yml \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
-e certificate_authority_linux_cert_path=/etc/ssl/certs/myhost.crt \
-e certificate_authority_cert_keep_copies=2 \
--become
After two renewals the target will have:
/etc/ssl/private/myhost.key ← current
/etc/ssl/private/myhost.key.1 ← previous
/etc/ssl/private/myhost.key.2 ← one before that
/etc/ssl/certs/myhost.crt
/etc/ssl/certs/myhost.crt.1
/etc/ssl/certs/myhost.crt.2
Key staging
The new private key is written to certificate_authority_linux_key_stage_path (default /tmp/<hostname>_pending.key) during generate_key_linux and only promoted to its final path by write_certificate_linux after the certificate is signed. If signing fails, the existing key at the final path is untouched.
Renew cert only, reuse existing key
Set certificate_authority_linux_reuse_key: true to sign a new certificate against the key already on the target. Key files are not touched at all — no generation, no backup, no overwrite.
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags generate_key_linux,generate_csr_linux,sign_certificate,write_certificate_linux \
-e @extra_vars/certificate_authority.yml \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
-e certificate_authority_linux_cert_path=/etc/ssl/certs/myhost.crt \
-e certificate_authority_linux_reuse_key=true \
-e certificate_authority_cert_keep_copies=1 \
--become
The generate_key_linux tag must still be included in the tag list — when reuse_key is true it runs but immediately verifies the key exists and exits, rather than generating a new one. The role fails fast with a clear error if the key file is not found.
ECC key
Set certificate_authority_linux_key_type: ecc in host_vars or pass it on the command line. The default curve is prime256v1; override with certificate_authority_linux_ecc_curve.
ansible-playbook --limit=myhost.example.com playbooks/certificate-authority-issue.yml \
--tags generate_key_linux,generate_csr_linux,sign_certificate,write_certificate_linux \
-e @extra_vars/certificate_authority.yml \
-e certificate_authority_linux_key_path=/etc/ssl/private/myhost.key \
-e certificate_authority_linux_cert_path=/etc/ssl/certs/myhost.crt \
-e certificate_authority_linux_key_type=ecc \
--become
Variables
All variables use the full certificate_authority_* name. They can be set in host_vars, group_vars, or via -e on the command line.
Required Variables
| Variable | Description |
|---|---|
certificate_authority_linux_key_path |
Destination path for the private key file (e.g. /etc/ssl/private/myhost.key). No default — must be set. |
certificate_authority_linux_cert_path |
Destination path for the certificate file (e.g. /etc/ssl/certs/myhost.crt). No default — must be set. |
Linux-specific Variables
| Variable | Default | Description |
|---|---|---|
certificate_authority_linux_key_type |
rsa |
Key algorithm. Accepted values: rsa, ecc. |
certificate_authority_linux_ecc_curve |
prime256v1 |
ECC curve name. Only used when key_type is ecc. |
certificate_authority_linux_key_mode |
0600 |
File mode applied to the private key file. |
certificate_authority_linux_cert_mode |
0644 |
File mode applied to the certificate file. |
certificate_authority_linux_csr_path |
/tmp/{{ inventory_hostname }}.csr |
Path where the CSR is written on the target before signing. |
certificate_authority_linux_csr_cleanup |
true |
Remove the CSR file from the target after it has been read and loaded for signing. |
certificate_authority_linux_reuse_key |
false |
When true, skip key generation and reuse the existing key at certificate_authority_linux_key_path. Key rotation is also skipped. The key file must already exist on the target — the role fails immediately with a clear error if it does not. |
certificate_authority_linux_key_stage_path |
/tmp/{{ inventory_hostname }}_pending.key |
Temporary path on the target where a newly generated key is written before the certificate is confirmed. Promoted to certificate_authority_linux_key_path by write_certificate_linux only after issuance succeeds, so the old key remains in service until the new cert is in hand. |
Certificate Variables
The Linux workflow reuses the same certificate shaping variables as the Windows workflow. See the Ansible Internal CA variables table for the full list. The most commonly set ones are:
| Variable | Default | Description |
|---|---|---|
certificate_authority_cert_sans |
[] |
Additional SANs. Bare values are treated as DNS SANs. |
certificate_authority_cert_include_default_names |
true |
Auto-add FQDN, inventory hostname, and short hostname as DNS SANs. |
certificate_authority_cert_include_ip_san |
false |
Auto-add the host's primary IPv4 as an IP SAN. |
certificate_authority_cert_validity_days |
825 |
Certificate validity in days. |
certificate_authority_cert_key_length |
2048 |
RSA key size in bits. |
certificate_authority_cert_key_usage |
[digitalSignature, keyEncipherment] |
Key usage values. |
certificate_authority_cert_extended_key_usage |
[serverAuth] |
Extended key usage OIDs. |
certificate_authority_cert_keep_copies |
(unset — no backup) | How many numbered backup copies of the cert and key files to keep before overwriting. 0 deletes the current files and all existing backups; N keeps N backups (.1 = most recent) and prunes the rest. Leave unset to overwrite with no backup. Key backup only applies when certificate_authority_linux_reuse_key is false; deploy_certificate_linux always backs up both since the PFX always contains a new key. |
Sample host_vars
# host_vars/myhost.example.com.yml
certificate_authority_linux_key_path: /etc/ssl/private/myhost.key
certificate_authority_linux_cert_path: /etc/ssl/certs/myhost.crt
certificate_authority_linux_key_type: rsa
certificate_authority_cert_include_ip_san: true
certificate_authority_cert_validity_days: 365
certificate_authority_cert_keep_copies: 2
# certificate_authority_linux_reuse_key: true # uncomment to renew cert without regenerating the key