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.
227 lines
7.0 KiB
227 lines
7.0 KiB
- 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)
|
|
|