๐Ÿ“— Ansible playbooks and roles for building an idempotent, interconnected and scalable infrastructure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ansible-playbooks/roles/ca/tasks/add_cert.yml

228 lines
7.0 KiB

2 years ago
- include_tasks: prepare_item.yml
- name: define combined options
set_fact:
ca_combined: "{{ ca_options | d({}) | combine(item) }}"
- name: define cert parameters
set_fact:
key_path: "{%- if item.key is defined -%}{{ item.key }}\
{%- else -%}{{ ca_combined.path ~ '/' ~ kt.name ~ '.' ~ ca_key_ext }}\
{%- endif -%}"
cert_path: "{%- if item.cert is defined -%}{{ item.cert }}\
{%- else -%}{{ ca_combined.path ~ '/' ~ kt.name ~ '.' ~ ca_crt_ext }}\
{%- endif -%}"
use_acme: "{{ ca_combined.acme | d(has_acme | d(false)) }}"
- name: define tld and presets
set_fact:
ca_tld: "{{ ca_combined.tld | d(host_tld) }}"
ca_presets:
web:
cn: FQDN
eku: ['clientAuth', 'serverAuth']
ku: ['digitalSignature', 'keyEncipherment', 'keyAgreement']
san: FQDN
psh:
cn: FQDN
eku: ['serverAuth']
ku: ['digitalSignature', 'keyEncipherment', 'keyAgreement']
san: FQDN
- name: select a preset
set_fact:
ca_preset: >
{% if item.preset is defined -%}{{ ca_presets[item.preset] }}
{%- elif ca_options.preset is defined -%}{{ ca_presets[ca_options.preset] }}
{%- else -%}{{ None }}
{%- endif %}
- name: generate private key
community.crypto.openssl_privatekey:
path: "{{ key_path }}"
size: "{{ kt.size | d(omit) }}"
curve: "{{ kt.curve | d(omit) }}"
type: "{{ kt.type }}"
backup: yes
force: no
format: pkcs8
format_mismatch: convert
regenerate: never
mode: "{{ k_mode | d(omit) }}"
owner: "{{ k_owner | d(omit) }}"
group: "{{ k_group | d(omit) }}"
notify: "{{ ca_options.notify | d(omit) }}"
- name: generate in-memory csr request for private key
community.crypto.openssl_csr_pipe:
basic_constraints:
- 'CA:FALSE'
basic_constraints_critical: yes
digest: "{{ kt.digest | d(omit) }}"
key_usage_critical: yes
privatekey_path: "{{ key_path }}"
common_name: "{%- if item.cn is defined -%}{{ item.cn }}\
{%- elif ca_options.cn is defined -%}{{ ca_options.cn }}\
{%- elif ca_preset.cn == 'FQDN' -%}{{ host_name ~ '.' ~ ca_tld }}\
{%- elif ca_preset.cn is defined -%}{{ ca_preset.cn }}\
{%- endif -%}"
extended_key_usage: "{%- if item.eku is defined -%}{{ item.eku }}\
{%- elif ca_options.eku is defined -%}{{ ca_options.eku }}\
{%- elif ca_preset.eku is defined -%}{{ ca_preset.eku }}\
{%- endif -%}"
key_usage: "{%- if item.ku is defined -%}{{ item.ku }}\
{%- elif ca_options.ku is defined -%}{{ ca_options.ku }}\
{%- elif ca_preset.ku is defined -%}{{ ca_preset.ku }}\
{%- else -%}{{ ['digitalSignature', 'keyEncipherment', 'keyAgreement'] }}\
{%- endif -%}"
subject_alt_name: "{%- if item.san is defined -%}{{ item.san }}\
{%- elif ca_options.san is defined -%}{{ ca_options.san }}\
{%- elif item.cn is defined -%}{{ ['DNS:' ~ item.cn] }}\
{%- elif ca_options.cn is defined -%}{{ ['DNS:' ~ ca_options.cn] }}\
{%- elif ca_preset.san == 'FQDN' -%}{{ ['DNS:' ~ host_name ~ '.' ~ ca_tld] }}\
{%- elif ca_preset.san is defined -%}{{ ca_preset.san }}\
{%- endif -%}"
ocsp_must_staple: "{{ (has_acme | d(false)) and (ca_options.ocsp_must_staple | d(false)) }}"
register: csr
changed_when: no
- name: check if cert already exists
stat:
path: "{{ cert_path }}"
register: cert_exists
- name: slurp cert if exists
slurp:
src: "{{ cert_path }}"
when: cert_exists.stat.exists
register: cert
- name: check if the cert validity period is about to expire
community.crypto.x509_certificate_info:
content: "{{ cert.content | b64decode }}"
valid_at:
reissue_period: "+{%- if has_acme | d(false) == true -%}45d\
{%- else -%}{{ ca_reissue_period | d('8w') }}\
{%- endif -%}"
when: cert_exists.stat.exists
register: cert_info
- block:
- name: generate certificate on ca
community.crypto.x509_certificate_pipe:
content: "{{ (cert.content | b64decode) if cert_exists.stat.exists else omit }}"
csr_content: "{{ csr.csr }}"
provider: ownca
ownca_not_after: "{{ item.duration | d('+365d') }}"
ownca_not_before: -1d
ownca_digest: "{{ kt.digest | d(omit) }}"
ownca_path: "{{ ca_dir }}/{{ ca_ip }}{{ kt.name }}.{{ ca_crt_ext }}"
ownca_privatekey_path: "{{ ca_dir }}/{{ ca_ip }}{{ kt.name }}.{{ ca_key_ext }}"
ownca_privatekey_passphrase: "{{ ca_pk_inter_password }}"
force: "{{ cert_exists.stat.exists and not cert_info.valid_at.reissue_period }}"
register: cert
delegate_to: "{{ services.ca.hostname }}"
notify: "{{ ca_options.notify | d(omit) }}"
- name: save new cert if it was changed
copy:
dest: "{{ cert_path }}"
content: "{{ cert.certificate }}"
mode: "{{ k_mode | d(omit) }}"
owner: "{{ k_owner | d(omit) }}"
group: "{{ k_group | d(omit) }}"
follow: "{{ (ca_options | combine(item)).follow_symlinks | d(omit) }}"
when: cert is changed
notify: "{{ ca_options.notify | d(omit) }}"
when: has_acme | d(false) == false
- name: generate acme certificate
include_tasks: gen_acme.yml
when: has_acme | d(false) == true
- block:
- name: slurp certificate
slurp:
src: "{{ cert_path }}"
register: cert
- name: complete certificate chain
community.crypto.certificate_complete_chain:
input_chain: "{{ ((cert.content | b64decode).split('\n\n'))[0] }}"
root_certificates: /etc/ssl/certs
register: chain
- name: save chain to file
copy:
dest: "{{ item.chain }}"
content: |
{% set result = chain.complete_chain %}
{% set _ = result.pop(0) %}
{{ result | join('') }}
mode: "{{ k_mode | d(omit) }}"
owner: "{{ k_owner | d(omit) }}"
group: "{{ k_group | d(omit) }}"
follow: "{{ (ca_options | combine(item)).follow_symlinks | d(omit) }}"
notify: "{{ ca_options.notify | d(omit) }}"
when: item.chain is string
- block:
- name: slurp intermediate from ca
slurp:
src: "{{ ca_dir }}/{{ ca_ip }}{{ kt.name }}.{{ ca_crt_ext }}"
register: inter
delegate_to: "{{ services.ca.hostname }}"
- name: add intermediate cert if requested
blockinfile:
block: "{{ inter.content | b64decode }}"
insertafter: EOF
marker: ""
path: "{{ cert_path }}"
notify: "{{ ca_options.notify | d(omit) }}"
when: (use_acme | d(false) == false) and (cert is changed) and ((ca_options | combine(item)).concat_inter | d(true) == true)
- block:
- name: slurp root from ca
slurp:
src: "{{ ca_dir }}/{{ ca_rp }}{{ kt.name }}.{{ ca_crt_ext }}"
register: root
delegate_to: "{{ services.ca.hostname }}"
- name: add root cert if requested
blockinfile:
block: "{{ root.content | b64decode }}"
insertafter: EOF
marker: ""
path: "{{ cert_path }}"
notify: "{{ ca_options.notify | d(omit) }}"
when: (use_acme | d(false) == false) and (cert is changed) and ((ca_options | combine(item)).concat_root | d(false) == true)