added molecule tests, fixes and checks for tests

This commit is contained in:
AnsibleGuy 2022-08-13 22:10:28 +02:00
parent 9a47c836d3
commit 0fa55af484
14 changed files with 589 additions and 218 deletions

View File

@ -9,12 +9,13 @@ defaults_certs:
name: name:
key_size: 4096 # 1024, 2048, 4096 key_size: 4096 # 1024, 2048, 4096
key_type: 'RSA' key_type: 'RSA'
cipher: 'AES-256-CBC' # see: 'openssl list -cipher-algorithms' cipher: 'auto'
digest: 'sha256' digest: 'sha256'
regenerate: 'partial_idempotence' regenerate: 'partial_idempotence'
pwd: pwd:
domains: [] domains: []
ips: [] ips: []
backend: 'auto'
# certificate config # certificate config
cn: 'Ansible Certificate' cn: 'Ansible Certificate'
@ -23,10 +24,11 @@ defaults_certs:
country: country:
state: state:
locality: locality:
san_other: # other RAW values to set as subject alternative name => MUST BE VALID
email: # if using letsencrypt you might pass an email per domain => see letsencrypt-certs email: # if using letsencrypt you might pass an email per domain => see letsencrypt-certs
key_usage: 'serverAuth' # serverAuth, clientAuth, codeSigning, emailProtection, timeStamping, ocspSigning key_usage: 'serverAuth' # serverAuth, clientAuth, codeSigning, emailProtection, timeStamping, ocspSigning
ocsp_staple: false ocsp_staple: false
crl_distribution: [] crl_distribution: [] # list of dicts
# - full_name: # - full_name:
# - "URI:https://ca.example.com/revocations.crl" # - "URI:https://ca.example.com/revocations.crl"
# crl_issuer: # crl_issuer:
@ -54,18 +56,19 @@ defaults_certs:
service: # apache, nginx service: # apache, nginx
renew_timer: 'Mon *-*-* 01:00:00' renew_timer: 'Mon *-*-* 01:00:00'
verbosity: 'v' verbosity: 'v'
certs: {} # see 'default_le_certbot_cert_config' certs: {} # see 'default_le_certbot_cert' below
renew: false # if a renewal should be started by the role; the renewal service will auto-renew the certificates otherwise renew: false # if a renewal should be started by the role; the renewal service will auto-renew the certificates otherwise
ca: ca:
path: '/etc/certs/ca' path:
valid_days: 7300 valid_days: 7300
key_size: 8192 # 1024, 2048, 4096, 8192 key_size: 8192 # 1024, 2048, 4096, 8192
key_type: 'RSA' key_type: 'RSA'
cipher: 'AES-256-CBC' # see: 'openssl list -cipher-algorithms' cipher: 'auto'
digest: 'sha512' digest: 'sha512'
regenerate: 'partial_idempotence' regenerate: 'partial_idempotence'
pwd: pwd:
backend: 'auto'
# certificate config # certificate config
cn: 'CA Certificate' cn: 'CA Certificate'
@ -83,4 +86,14 @@ default_le_certbot_cert:
state: 'present' state: 'present'
email: email:
# letsencrypt example:
#certs:
# example1:
# domains: ['example1.ansibleguy.net']
# email: 'dummy@ansibleguy.net'
# example2:
# domains: ['example2.ansibleguy.net']
# email: 'dummy@ansibleguy.net'
debug: false debug: false
testing: false

View File

@ -1,5 +1,6 @@
from re import sub as regex_replace from re import sub as regex_replace
from re import match as regex_match from re import match as regex_match
from re import compile as regex_compile
class FilterModule(object): class FilterModule(object):
@ -7,10 +8,11 @@ class FilterModule(object):
def filters(self): def filters(self):
return { return {
"safe_key": self.safe_key, "safe_key": self.safe_key,
"valid_domain": self.valid_domain, "valid_hostname": self.valid_hostname,
"valid_ip": self.valid_ip, "valid_ip": self.valid_ip,
"check_email": self.check_email, "check_email": self.check_email,
"le_domains_changed": self.le_domains_changed, "le_domains_changed": self.le_domains_changed,
"ensure_list": self.ensure_list,
} }
@staticmethod @staticmethod
@ -18,9 +20,19 @@ class FilterModule(object):
return regex_replace(r'[^0-9a-zA-Z\.]+', '', key.replace(' ', '_')) return regex_replace(r'[^0-9a-zA-Z\.]+', '', key.replace(' ', '_'))
@staticmethod @staticmethod
def valid_domain(domain: str) -> bool: def valid_hostname(name: str) -> bool:
expr = r'^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$' # see: https://validators.readthedocs.io/en/latest/_modules/validators/domain.html
return True if regex_match(expr, domain) is not None else False domain = regex_compile(
r'^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|'
r'([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|'
r'([a-zA-Z0-9][-_.a-zA-Z0-9]{0,61}[a-zA-Z0-9]))\.'
r'([a-zA-Z]{2,13}|[a-zA-Z0-9-]{2,30}.[a-zA-Z]{2,3})$'
)
valid_domain = True if domain.match(name) is not None else False
# see: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
expr_hostname = r'^[a-zA-Z0-9-\.]{1,253}$'
valid_hostname = True if regex_match(expr_hostname, name) is not None else False
return all([valid_domain, valid_hostname])
@staticmethod @staticmethod
def valid_ip(ip: str) -> bool: def valid_ip(ip: str) -> bool:
@ -49,6 +61,7 @@ class FilterModule(object):
# removing wildcards # removing wildcards
try: try:
config_domains.remove(non_domain) config_domains.remove(non_domain)
except ValueError: except ValueError:
pass pass
@ -76,3 +89,12 @@ class FilterModule(object):
break break
return changed return changed
@staticmethod
def ensure_list(data: (str, dict, list)) -> list:
# if user supplied a string instead of a list => convert it to match our expectations
if type(data) == list:
return data
else:
return [data]

View File

@ -0,0 +1,14 @@
# docker build -t mantest - < ./Dockerfile.j2
# docker run -it --privileged --name mantest mantest:latest /sbin/init --tmpfs /tmp --tmpfs /run --tmpfs /run/lock
FROM debian:11-slim
ENV container docker
ENV LC_ALL C
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& apt-get install -y systemd systemd-sysv python3 sudo \
&& apt-get clean
CMD ["/sbin/init"]

10
molecule/default/Usage.md Normal file
View File

@ -0,0 +1,10 @@
# Usage
Check out the [Molecule Tutorial](https://github.com/ansibleguy/ansible_tutorial/blob/main/Molecule.md) on how to get started!
# Running
```bash
cd roles/ansibleguy.ROLE
molecule test
```

View File

@ -0,0 +1,134 @@
---
# todo: test revoking
- name: Converge Internal
hosts: test-ag-certs-internal-{{ lookup('ansible.builtin.env', 'USER') }}
roles:
- role: ansibleguy.infra_certs
vars:
certs:
mode: 'selfsigned'
path: '/etc/ssl/test1'
cert:
name: 'self_srv'
domains: ['cert.test.ansibleguy.net']
ips: ['192.168.0.1']
cn: 'SelfSigned Server Cert'
org: 'AnsibleGuy Test'
email: 'testmaster@ansibleguy.net'
ou: 'Test'
country: 'AT'
state: 'Styria'
locality: 'Unknown'
valid_days: 5
key_usage: 'serverAuth'
crl_distribution:
crl_issuer: 'URI:https://ca.template.ansibleguy.net/'
full_name: 'URI:https://ca.template.ansibleguy.net/revocations.crl'
reasons: ['key_compromise', 'ca_compromise']
- role: ansibleguy.infra_certs
vars:
certs:
mode: 'selfsigned'
path: '/etc/ssl/test2'
cert:
name: 'self_cli'
cn: 'SelfSigned Client Cert'
key_usage: 'clientAuth'
- role: ansibleguy.infra_certs
vars:
certs:
mode: 'selfsigned'
path: '/etc/ssl/test3'
cert:
name: 'self_other'
san_other: 'DNS:cert.templates.ansibleguy.net,email:other@cert.template.ansibleguy.net'
cn: 'SelfSigned Other Cert'
- role: ansibleguy.infra_certs
vars:
certs:
mode: 'ca'
path: '/etc/ssl/test3'
cert:
name: 'self_minca_srv'
domains: ['cert.test.ansibleguy.net']
ips: ['192.168.0.1']
cn: 'CA-Signed Server Cert'
org: 'AnsibleGuy Test'
email: 'testmaster@ansibleguy.net'
ou: 'Test'
country: 'AT'
state: 'Styria'
locality: 'Unknown'
valid_days: 5
key_usage: 'serverAuth'
crl_distribution:
crl_issuer: 'URI:https://ca.template.ansibleguy.net/'
full_name: 'URI:https://ca.template.ansibleguy.net/revocations.crl'
reasons: ['key_compromise', 'ca_compromise']
- role: ansibleguy.infra_certs
vars:
certs:
mode: 'ca'
path: '/etc/ssl/test4'
cert:
name: 'self_minca_cli'
cn: 'CA-Signed Client Cert'
key_usage: 'clientAuth'
- role: ansibleguy.infra_certs
vars:
certs:
mode: 'ca'
path: '/etc/ssl/test5'
cert:
name: 'self_minca_pwd'
domains: ['cert.test.ansibleguy.net']
ips: [ '192.168.0.1' ]
cn: 'CA-Signed Server Cert'
pwd: 'Nope.'
key_usage: 'serverAuth'
crl_distribution:
crl_issuer: 'URI:https://ca.template.ansibleguy.net/'
full_name: 'URI:https://ca.template.ansibleguy.net/revocations.crl'
reasons: ['key_compromise', 'ca_compromise']
ca:
path: '/etc/ssl/test5/ca'
pwd: 'YouWantMyTreasure?YouCanHaveIt!SearchForIt-SomewhereOutThere-Hidden-IsTheBiggestTreasureOfTheWorld.'
cn: 'SelfSigned CA Cert'
org: 'AnsibleGuy Test'
email: 'testmaster@ansibleguy.net'
ou: 'Test'
country: 'AT'
state: 'Styria'
locality: 'Unknown'
valid_days: 5
- name: Converge LetsEncrypt
hosts: test-ag-certs-letsencrypt-{{ lookup('ansible.builtin.env', 'USER') }}
vars:
testing: true # target letsencrypt-staging
certs:
mode: 'le_certbot'
letsencrypt:
certs:
test:
domains: ['infra-certs.test.ansibleguy.net']
email: 'testmaster@ansibleguy.net'
path: '/etc/ssl/test'
renew_timer: 'Mon *-*-* 03:00:00'
service: 'nginx'
roles:
- ansibleguy.infra_certs

View File

@ -0,0 +1,60 @@
---
references:
docker:
all: &docker_all
docker_host: 'tcp://molecule-docker.local:2375'
# docker_host: 'unix://var/run/docker.sock' # localhost
purge_networks: true
image: 'debian:11-slim'
# for docker systemd config see: https://serverfault.com/questions/1053187/systemd-fails-to-run-in-a-docker-container-when-using-cgroupv2-cgroupns-priva
dockerfile: 'Dockerfile_debian11_systemd.j2'
build_image: yes
tmpfs: ['/tmp', '/run', '/run/lock']
privileged: true
command: '/sbin/init'
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: test-ag-certs-internal-${USER}
docker_networks:
- name: 'test-ag-certs-${USER}'
ipam_config:
- subnet: '192.168.6.0/24'
gateway: '192.168.6.254'
networks:
- name: 'test-ag-certs-${USER}'
ipv4_address: '192.168.6.1'
groups: [grp_targets]
<<: *docker_all
- name: test-ag-certs-letsencrypt-${USER}
networks:
- name: 'test-ag-certs-${USER}'
ipv4_address: '192.168.6.2'
groups: [grp_targets]
<<: *docker_all
exposed_ports:
- '80/tcp'
published_ports: # proxied for LetsEncrypt tests
- '0.0.0.0:8080:80/tcp'
provisioner:
name: ansible
verifier:
name: ansible
scenario:
name: default
test_sequence:
- lint
- destroy
- syntax
- create
- converge
- verify # MUST NOT make changes
- idempotence
- check
- destroy

View File

@ -0,0 +1,19 @@
---
- name: Prepare
hosts: test-ag-certs-letsencrypt-{{ lookup('ansible.builtin.env', 'USER') }}
tasks:
- name: Installing nginx
ansible.builtin.apt:
name: 'nginx'
- name: Starting nginx
ansible.builtin.systemd:
name: 'nginx.service'
enabled: yes
state: started
- name: Checking if nginx is running
wait_for:
port: 80
timeout: 4

View File

@ -1,5 +1,12 @@
--- ---
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Showing debug info"
ansible.builtin.debug:
var: le_cert
when:
- debug is defined
- debug
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Creating directory" - name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Creating directory"
ansible.builtin.file: ansible.builtin.file:
path: "{{ item }}" path: "{{ item }}"
@ -13,25 +20,29 @@
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Certbot command (FYI)" - name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Certbot command (FYI)"
ansible.builtin.debug: ansible.builtin.debug:
msg: "certbot certonly --non-interactive --agree-tos --no-redirect{% if debug %} --staging{% endif %} msg: "certbot certonly --non-interactive --agree-tos --no-redirect{% if debug or testing %} --staging{% endif %}
--{{ CERT_CONFIG.letsencrypt.service }} --cert-name {{ le_name }} --{{ CERT_CONFIG.letsencrypt.service }} --cert-name {{ le_name }}
-{{ CERT_CONFIG.letsencrypt.verbosity }} -{{ CERT_CONFIG.letsencrypt.verbosity }}
--rsa-key-size {{ le_cert.key_size | default(CERT_CONFIG.cert.key_size, true) }} --rsa-key-size {{ le_cert.key_size | default(CERT_CONFIG.cert.key_size, true) }}
--config-dir {{ CERT_CONFIG.letsencrypt.path }} --config-dir {{ CERT_CONFIG.letsencrypt.path }}
{% for domain in le_cert.domains %}{% if domain | valid_domain %}--domain {{ domain }} {% endif %}{% endfor %} {% for domain in le_cert.domains %}{% if domain | valid_hostname %}--domain {{ domain }} {% endif %}{% endfor %}
{% if le_cert.email is not none %}--email {{ le_cert.email }} {% else %}--email {{ CERT_CONFIG.cert.email }} {% endif %}" {% if le_cert.email is not none %}--email {{ le_cert.email }} {% else %}--email {{ CERT_CONFIG.cert.email }} {% endif %}"
when: le_changed when: le_changed
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Running certbot" - name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Running certbot"
ansible.builtin.command: "certbot certonly --non-interactive --agree-tos --no-redirect{% if debug %} --staging{% endif %} ansible.builtin.command: "certbot certonly --non-interactive --agree-tos --no-redirect{% if debug or testing %} --staging{% endif %}
--{{ CERT_CONFIG.letsencrypt.service }} --cert-name {{ le_name }} --{{ CERT_CONFIG.letsencrypt.service }} --cert-name {{ le_name }}
-{{ CERT_CONFIG.letsencrypt.verbosity }} -{{ CERT_CONFIG.letsencrypt.verbosity }}
--rsa-key-size {{ le_cert.key_size | default(CERT_CONFIG.cert.key_size, true) }} --rsa-key-size {{ le_cert.key_size | default(CERT_CONFIG.cert.key_size, true) }}
--config-dir {{ CERT_CONFIG.letsencrypt.path }} --config-dir {{ CERT_CONFIG.letsencrypt.path }}
{% for domain in le_cert.domains %}{% if domain | valid_domain %}--domain {{ domain }} {% endif %}{% endfor %} {% for domain in le_cert.domains %}{% if domain | valid_hostname %}--domain {{ domain }} {% endif %}{% endfor %}
{% if le_cert.email is not none %}--email {{ le_cert.email }} {% else %}--email {{ CERT_CONFIG.cert.email }} {% endif %}" {% if le_cert.email is not none %}--email {{ le_cert.email }} {% else %}--email {{ CERT_CONFIG.cert.email }} {% endif %}"
when: le_changed when: le_changed
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Adding dummy certs"
ansible.builtin.include_tasks: test.yml
when: testing
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Linking cert" - name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Linking cert"
ansible.builtin.file: ansible.builtin.file:
state: link state: link

View File

@ -17,11 +17,18 @@
when: CERT_CONFIG.letsencrypt.service == 'nginx' when: CERT_CONFIG.letsencrypt.service == 'nginx'
- name: Certificates | Debian | LetsEncrypt Certbot | Pulling existing certs - name: Certificates | Debian | LetsEncrypt Certbot | Pulling existing certs
ansible.builtin.command: 'certbot certificates' ansible.builtin.command: "certbot certificates --config-dir {{ CERT_CONFIG.letsencrypt.path }}{% if debug or testing %} --staging{% endif %}"
register: existing_certs_raw register: existing_certs_raw
changed_when: false changed_when: false
check_mode: false check_mode: false
- name: Certificates | Debian | LetsEncrypt Certbot | Existing certificates
ansible.builtin.debug:
var: existing_certs_raw.stdout
when:
- debug is defined
- debug
- name: Certificates | Debian | LetsEncrypt Certbot | Adding certificates - name: Certificates | Debian | LetsEncrypt Certbot | Adding certificates
ansible.builtin.include_tasks: cert.yml ansible.builtin.include_tasks: cert.yml
when: when:
@ -39,7 +46,7 @@
# todo: task gets stuck # todo: task gets stuck
- name: Certificates | Debian | LetsEncrypt Certbot | Revoking certificates - name: Certificates | Debian | LetsEncrypt Certbot | Revoking certificates
ansible.builtin.command: "certbot revoke --cert-name {{ le_name }}{% if debug %} --staging{% endif %}" ansible.builtin.command: "certbot revoke --cert-name {{ le_name }}{% if debug or testing %} --staging{% endif %}"
when: when:
- le_cert.state != 'present' - le_cert.state != 'present'
- existing_certs_raw.stdout.find(le_name) != -1 - existing_certs_raw.stdout.find(le_name) != -1
@ -51,7 +58,7 @@
with_dict: "{{ CERT_CONFIG.letsencrypt.certs }}" with_dict: "{{ CERT_CONFIG.letsencrypt.certs }}"
- name: Certificates | Debian | LetsEncrypt Certbot | Deleting certificates - name: Certificates | Debian | LetsEncrypt Certbot | Deleting certificates
ansible.builtin.command: "certbot delete --cert-name {{ le_name }}{% if debug %} --staging{% endif %}" ansible.builtin.command: "certbot delete --cert-name {{ le_name }}{% if debug or testing %} --staging{% endif %}"
when: when:
- le_cert.state != 'present' - le_cert.state != 'present'
- existing_certs_raw.stdout.find(le_name) != -1 - existing_certs_raw.stdout.find(le_name) != -1
@ -89,6 +96,6 @@
state: started state: started
- name: Certificates | Debian | LetsEncrypt Certbot | Running renewal - name: Certificates | Debian | LetsEncrypt Certbot | Running renewal
ansible.builtin.command: "certbot renew --force-renewal{% if debug %} --staging{% endif %}" ansible.builtin.command: "certbot renew --force-renewal{% if debug or testing %} --staging{% endif %}"
when: CERT_CONFIG.letsencrypt.renew when: CERT_CONFIG.letsencrypt.renew
ignore_errors: true ignore_errors: true

View File

@ -0,0 +1,30 @@
---
# adding dummy certificates for ansible-molecule testing
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | DUMMY | Setting dummy config"
ansible.builtin.set_fact:
dummy_cert:
path: "{{ le_path }}"
cert:
cn: 'Molecule Dummy Cert'
domains: "{{ le_cert.domains }}"
email: "{{ le_cert.email }}"
ca:
cn: 'Molecule Dummy CA'
email: "{{ le_cert.email }}"
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | DUMMY | Installing dependencies"
ansible.builtin.package:
pkg: ['python3-cryptography']
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | DUMMY | Creating dummy CA"
ansible.builtin.include_tasks: internal/ca_minimal.yml
vars:
config_ca: "{{ CERT_CONFIG | combine(dummy_cert, recursive=true) }}"
- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | DUMMY | Creating dummy Certificate"
ansible.builtin.include_tasks: internal/cert.yml
vars:
config_cert: "{{ CERT_CONFIG | combine(dummy_cert, recursive=true) }}"

View File

@ -4,103 +4,109 @@
- name: Certificates | Internal | Minimal CA | Creating ca directory - name: Certificates | Internal | Minimal CA | Creating ca directory
ansible.builtin.file: ansible.builtin.file:
path: "{{ CERT_CONFIG.ca.path }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}"
state: directory state: directory
- name: Certificates | Internal | Minimal CA | Generate ca private key (encrypted key) - name: Certificates | Internal | Minimal CA | Generate ca private key (encrypted key)
community.crypto.openssl_privatekey: community.crypto.openssl_privatekey:
path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_key }}"
passphrase: "{{ CERT_CONFIG.ca.pwd }}" passphrase: "{{ config_ca.ca.pwd }}"
cipher: "{{ CERT_CONFIG.ca.cipher }}" select_crypto_backend: "{{ config_ca.ca.backend }}"
size: "{{ CERT_CONFIG.ca.key_size }}" cipher: "{{ config_ca.ca.cipher }}"
type: "{{ CERT_CONFIG.ca.key_type }}" size: "{{ config_ca.ca.key_size }}"
regenerate: "{{ CERT_CONFIG.ca.regenerate }}" type: "{{ config_ca.ca.key_type }}"
mode: "{{ CERT_CONFIG.mode_key }}" regenerate: "{{ config_ca.ca.regenerate }}"
owner: "{{ CERT_CONFIG.owner_key }}" mode: "{{ config_ca.mode_key }}"
group: "{{ CERT_CONFIG.group_key }}" owner: "{{ config_ca.owner_key }}"
group: "{{ config_ca.group_key }}"
no_log: true no_log: true
when: CERT_CONFIG.ca.pwd | default(none, true) is not none when: config_ca.ca.pwd | default(none, true) is not none
- name: Certificates | Internal | Minimal CA | Generate ca private key (plain key) - name: Certificates | Internal | Minimal CA | Generate ca private key (plain key)
community.crypto.openssl_privatekey: community.crypto.openssl_privatekey:
path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_key }}"
size: "{{ CERT_CONFIG.ca.key_size }}" select_crypto_backend: "{{ config_ca.ca.backend }}"
type: "{{ CERT_CONFIG.ca.key_type }}" size: "{{ config_ca.ca.key_size }}"
regenerate: "{{ CERT_CONFIG.ca.regenerate }}" type: "{{ config_ca.ca.key_type }}"
mode: "{{ CERT_CONFIG.mode_key }}" regenerate: "{{ config_ca.ca.regenerate }}"
owner: "{{ CERT_CONFIG.owner_key }}" mode: "{{ config_ca.mode_key }}"
group: "{{ CERT_CONFIG.group_key }}" owner: "{{ config_ca.owner_key }}"
group: "{{ config_ca.group_key }}"
no_log: true no_log: true
when: CERT_CONFIG.ca.pwd | default(none, true) is none when: config_ca.ca.pwd | default(none, true) is none
# NOTE: for details see https://www.openssl.org/docs/man1.0.2/man5/x509v3_config.html # NOTE: for details see https://www.openssl.org/docs/man1.0.2/man5/x509v3_config.html
- name: Certificates | Internal | Minimal CA | Generating ca signing-request (encrypted key) - name: Certificates | Internal | Minimal CA | Generating ca signing-request (encrypted key)
community.crypto.openssl_csr: community.crypto.openssl_csr:
path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_csr }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_csr }}"
privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_ca.ca.backend }}"
privatekey_passphrase: "{{ CERT_CONFIG.ca.pwd }}" privatekey_path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_key }}"
privatekey_passphrase: "{{ config_ca.ca.pwd }}"
basic_constraints: ['CA:TRUE', 'pathlen:2'] basic_constraints: ['CA:TRUE', 'pathlen:2']
basic_constraints_critical: true basic_constraints_critical: true
key_usage: ['cRLSign', 'digitalSignature', 'keyCertSign'] key_usage: ['cRLSign', 'digitalSignature', 'keyCertSign']
key_usage_critical: true key_usage_critical: true
digest: "{{ CERT_CONFIG.ca.digest }}" digest: "{{ config_ca.ca.digest }}"
common_name: "{{ CERT_CONFIG.ca.cn }}" common_name: "{{ config_ca.ca.cn }}"
organization_name: "{{ CERT_CONFIG.ca.org }}" organization_name: "{{ config_ca.ca.org }}"
country_name: "{{ CERT_CONFIG.ca.country }}" country_name: "{{ config_ca.ca.country }}"
state_or_province_name: "{{ CERT_CONFIG.ca.state }}" state_or_province_name: "{{ config_ca.ca.state }}"
locality_name: "{{ CERT_CONFIG.ca.locality }}" locality_name: "{{ config_ca.ca.locality }}"
email_address: "{{ CERT_CONFIG.ca.email }}" email_address: "{{ config_ca.ca.email }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_ca.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_ca.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_ca.group_cert }}"
no_log: true no_log: true
when: CERT_CONFIG.ca.pwd | default(none, true) is not none when: config_ca.ca.pwd | default(none, true) is not none
- name: Certificates | Internal | Minimal CA | Generating ca signing-request (plain key) - name: Certificates | Internal | Minimal CA | Generating ca signing-request (plain key)
community.crypto.openssl_csr: community.crypto.openssl_csr:
path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_csr }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_csr }}"
privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_ca.ca.backend }}"
privatekey_path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_key }}"
basic_constraints: ['CA:TRUE', 'pathlen:2'] basic_constraints: ['CA:TRUE', 'pathlen:2']
basic_constraints_critical: true basic_constraints_critical: true
key_usage: ['cRLSign', 'digitalSignature', 'keyCertSign'] key_usage: ['cRLSign', 'digitalSignature', 'keyCertSign']
key_usage_critical: true key_usage_critical: true
digest: "{{ CERT_CONFIG.ca.digest }}" digest: "{{ config_ca.ca.digest }}"
common_name: "{{ CERT_CONFIG.ca.cn }}" common_name: "{{ config_ca.ca.cn }}"
organization_name: "{{ CERT_CONFIG.ca.org }}" organization_name: "{{ config_ca.ca.org }}"
country_name: "{{ CERT_CONFIG.ca.country }}" country_name: "{{ config_ca.ca.country }}"
state_or_province_name: "{{ CERT_CONFIG.ca.state }}" state_or_province_name: "{{ config_ca.ca.state }}"
locality_name: "{{ CERT_CONFIG.ca.locality }}" locality_name: "{{ config_ca.ca.locality }}"
email_address: "{{ CERT_CONFIG.ca.email }}" email_address: "{{ config_ca.ca.email }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_ca.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_ca.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_ca.group_cert }}"
no_log: true no_log: true
when: CERT_CONFIG.ca.pwd | default(none, true) is none when: config_ca.ca.pwd | default(none, true) is none
- name: Certificates | Internal | Minimal CA | Generating ca certificate (encrypted key) - name: Certificates | Internal | Minimal CA | Generating ca certificate (encrypted key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_cert }}"
csr_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_csr }}" select_crypto_backend: "{{ config_ca.ca.backend }}"
privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" csr_path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_csr }}"
privatekey_passphrase: "{{ CERT_CONFIG.ca.pwd }}" privatekey_path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_key }}"
privatekey_passphrase: "{{ config_ca.ca.pwd }}"
provider: selfsigned provider: selfsigned
selfsigned_not_after: "+{{ CERT_CONFIG.ca.valid_days }}d" selfsigned_not_after: "+{{ config_ca.ca.valid_days }}d"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_ca.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_ca.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_ca.group_cert }}"
no_log: true no_log: true
when: CERT_CONFIG.ca.pwd | default(none, true) is not none when: config_ca.ca.pwd | default(none, true) is not none
- name: Certificates | Internal | Minimal CA | Generating ca certificate (plain key) - name: Certificates | Internal | Minimal CA | Generating ca certificate (plain key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_ca.ca.backend }}"
csr_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_csr }}" privatekey_path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_key }}"
csr_path: "{{ config_ca.ca.path | default(config_ca.path, true) }}/ca.{{ config_ca.extension_csr }}"
provider: selfsigned provider: selfsigned
selfsigned_not_after: "+{{ CERT_CONFIG.ca.valid_days }}d" selfsigned_not_after: "+{{ config_ca.ca.valid_days }}d"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_ca.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_ca.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_ca.group_cert }}"
no_log: true no_log: true
when: CERT_CONFIG.ca.pwd | default(none, true) is none when: config_ca.ca.pwd | default(none, true) is none

View File

@ -2,204 +2,230 @@
- name: Certificates | Internal | Cert | Generate private key (encrypted) - name: Certificates | Internal | Cert | Generate private key (encrypted)
community.crypto.openssl_privatekey: community.crypto.openssl_privatekey:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
cipher: "{{ CERT_CONFIG.cert.cipher }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
size: "{{ CERT_CONFIG.cert.key_size }}" cipher: "{{ config_cert.cert.cipher }}"
type: "{{ CERT_CONFIG.cert.key_type }}" size: "{{ config_cert.cert.key_size }}"
passphrase: "{{ CERT_CONFIG.cert.pwd }}" type: "{{ config_cert.cert.key_type }}"
regenerate: "{{ CERT_CONFIG.cert.regenerate }}" passphrase: "{{ config_cert.cert.pwd }}"
mode: "{{ CERT_CONFIG.mode_key }}" regenerate: "{{ config_cert.cert.regenerate }}"
owner: "{{ CERT_CONFIG.owner_key }}" mode: "{{ config_cert.mode_key }}"
group: "{{ CERT_CONFIG.group_key }}" owner: "{{ config_cert.owner_key }}"
group: "{{ config_cert.group_key }}"
no_log: true no_log: true
when: CERT_CONFIG.cert.pwd | default(none, true) is not none when: config_cert.cert.pwd | default(none, true) is not none
- name: Certificates | Internal | Cert | Generate private key (plain) - name: Certificates | Internal | Cert | Generate private key (plain)
community.crypto.openssl_privatekey: community.crypto.openssl_privatekey:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
size: "{{ CERT_CONFIG.cert.key_size }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
type: "{{ CERT_CONFIG.cert.key_type }}" size: "{{ config_cert.cert.key_size }}"
regenerate: "{{ CERT_CONFIG.cert.regenerate }}" type: "{{ config_cert.cert.key_type }}"
mode: "{{ CERT_CONFIG.mode_key }}" regenerate: "{{ config_cert.cert.regenerate }}"
owner: "{{ CERT_CONFIG.owner_key }}" mode: "{{ config_cert.mode_key }}"
group: "{{ CERT_CONFIG.group_key }}" owner: "{{ config_cert.owner_key }}"
group: "{{ config_cert.group_key }}"
no_log: true no_log: true
when: CERT_CONFIG.cert.pwd | default(none, true) is none when: config_cert.cert.pwd | default(none, true) is none
- name: Certificates | Internal | Cert | Setting SAN - name: Certificates | Internal | Cert | Setting SAN
ansible.builtin.set_fact: ansible.builtin.set_fact:
cert_san: "{% for domain in CERT_CONFIG.cert.domains %} cert_san: "{% for domain in config_cert.cert.domains %}
{% if domain | valid_domain %}DNS:{{ domain }}{% if not loop.last %},{% endif %}{% endif %} {% if domain | valid_hostname %}DNS:{{ domain }}{% if not loop.last %},{% endif %}{% endif %}
{% endfor %} {% endfor %}
{% for ip in CERT_CONFIG.cert.ips %} {% for ip in config_cert.cert.ips %}
{% if ip | valid_ip %},IP:{{ ip }}{% endif %} {% if ip | valid_ip %},IP:{{ ip }}{% endif %}
{% endfor %}" {% endfor %}
{% if config_cert.cert.san_other %}
{% if config_cert.cert.domains | length > 0 or config_cert.cert.ips | length > 0 %},{% endif %}
{{ config_cert.cert.san_other }}
{% endif %}"
when: >
config_cert.cert.domains | length > 0 or
config_cert.cert.ips | length > 0 or
config_cert.cert.san_other
- name: Certificates | Internal | Cert | Setting SAN (fallback)
ansible.builtin.set_fact:
cert_san: ''
when:
- config_cert.cert.domains | length == 0
- config_cert.cert.ips | length == 0
- not config_cert.cert.san_other
- name: Certificates | Internal | Cert | Generating signing-request (encrypted key) - name: Certificates | Internal | Cert | Generating signing-request (encrypted key)
community.crypto.openssl_csr: community.crypto.openssl_csr:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
privatekey_passphrase: "{{ CERT_CONFIG.cert.pwd }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
digest: "{{ CERT_CONFIG.cert.digest }}" privatekey_passphrase: "{{ config_cert.cert.pwd }}"
common_name: "{{ CERT_CONFIG.cert.cn }}" digest: "{{ config_cert.cert.digest }}"
organization_name: "{{ CERT_CONFIG.cert.org }}" common_name: "{{ config_cert.cert.cn }}"
country_name: "{{ CERT_CONFIG.cert.country }}" organization_name: "{{ config_cert.cert.org }}"
state_or_province_name: "{{ CERT_CONFIG.cert.state }}" country_name: "{{ config_cert.cert.country }}"
locality_name: "{{ CERT_CONFIG.cert.locality }}" state_or_province_name: "{{ config_cert.cert.state }}"
email_address: "{{ CERT_CONFIG.cert.email }}" locality_name: "{{ config_cert.cert.locality }}"
extended_key_usage: "{{ CERT_CONFIG.cert.key_usage }}" email_address: "{{ config_cert.cert.email }}"
ocsp_must_staple: "{{ CERT_CONFIG.cert.ocsp_staple }}" extended_key_usage: "{{ config_cert.cert.key_usage }}"
crl_distribution_points: "{{ CERT_CONFIG.cert.crl_distribution }}" ocsp_must_staple: "{{ config_cert.cert.ocsp_staple }}"
subject_alt_name: "{{ cert_san | replace(' ', '') | default('DNS:localhost', true) }}" crl_distribution_points: "{{ config_cert.cert.crl_distribution | ensure_list }}"
mode: "{{ CERT_CONFIG.mode_cert }}" subject_alt_name: "{{ cert_san | replace(' ', '') | default(omit, true) }}"
owner: "{{ CERT_CONFIG.owner_cert }}" mode: "{{ config_cert.mode_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: CERT_CONFIG.cert.pwd | default(none, true) is not none when: config_cert.cert.pwd | default(none, true) is not none
changed_when: false changed_when: false
- name: Certificates | Internal | Cert | Generating signing-request (plain key) - name: Certificates | Internal | Cert | Generating signing-request (plain key)
community.crypto.openssl_csr: community.crypto.openssl_csr:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
digest: "{{ CERT_CONFIG.cert.digest }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
common_name: "{{ CERT_CONFIG.cert.cn }}" digest: "{{ config_cert.cert.digest }}"
organization_name: "{{ CERT_CONFIG.cert.org }}" common_name: "{{ config_cert.cert.cn }}"
country_name: "{{ CERT_CONFIG.cert.country }}" organization_name: "{{ config_cert.cert.org }}"
state_or_province_name: "{{ CERT_CONFIG.cert.state }}" country_name: "{{ config_cert.cert.country }}"
locality_name: "{{ CERT_CONFIG.cert.locality }}" state_or_province_name: "{{ config_cert.cert.state }}"
email_address: "{{ CERT_CONFIG.cert.email }}" locality_name: "{{ config_cert.cert.locality }}"
extended_key_usage: "{{ CERT_CONFIG.cert.key_usage }}" email_address: "{{ config_cert.cert.email }}"
ocsp_must_staple: "{{ CERT_CONFIG.cert.ocsp_staple }}" extended_key_usage: "{{ config_cert.cert.key_usage }}"
crl_distribution_points: "{{ CERT_CONFIG.cert.crl_distribution }}" ocsp_must_staple: "{{ config_cert.cert.ocsp_staple }}"
subject_alt_name: "{{ cert_san | replace(' ', '') | default('DNS:localhost', true) }}" crl_distribution_points: "{{ config_cert.cert.crl_distribution | ensure_list }}"
mode: "{{ CERT_CONFIG.mode_cert }}" subject_alt_name: "{{ cert_san | replace(' ', '') | default(omit, true) }}"
owner: "{{ CERT_CONFIG.owner_cert }}" mode: "{{ config_cert.mode_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: CERT_CONFIG.cert.pwd | default(none, true) is none when: config_cert.cert.pwd | default(none, true) is none
changed_when: false changed_when: false
- name: Certificates | Internal | Cert | Self-Signed | Generating certificate (encrypted key) - name: Certificates | Internal | Cert | Self-Signed | Generating certificate (encrypted key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
privatekey_passphrase: "{{ CERT_CONFIG.cert.pwd }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
csr_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" privatekey_passphrase: "{{ config_cert.cert.pwd }}"
csr_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
provider: selfsigned provider: selfsigned
selfsigned_not_after: "+{{ CERT_CONFIG.cert.valid_days }}d" selfsigned_not_after: "+{{ config_cert.cert.valid_days }}d"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: when:
- CERT_CONFIG.cert.pwd | default(none, true) is not none - config_cert.cert.pwd | default(none, true) is not none
- CERT_CONFIG.mode == 'selfsigned' - config_cert.mode == 'selfsigned'
- name: Certificates | Internal | Cert | Self-Signed | Generating certificate (plain key) - name: Certificates | Internal | Cert | Self-Signed | Generating certificate (plain key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
csr_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
csr_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
provider: selfsigned provider: selfsigned
selfsigned_not_after: "+{{ CERT_CONFIG.cert.valid_days }}d" selfsigned_not_after: "+{{ config_cert.cert.valid_days }}d"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: when:
- CERT_CONFIG.cert.pwd | default(none, true) is none - config_cert.cert.pwd | default(none, true) is none
- CERT_CONFIG.mode == 'selfsigned' - config_cert.mode == 'selfsigned'
- name: Certificates | Internal | Cert | CA-Signed | Generating certificate (encrypted key; encrypted ca-key) - name: Certificates | Internal | Cert | CA-Signed | Generating certificate (encrypted key; encrypted ca-key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
privatekey_passphrase: "{{ CERT_CONFIG.cert.pwd }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
csr_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" privatekey_passphrase: "{{ config_cert.cert.pwd }}"
csr_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
provider: ownca provider: ownca
ownca_not_after: "+{{ CERT_CONFIG.cert.valid_days }}d" ownca_not_after: "+{{ config_cert.cert.valid_days }}d"
ownca_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }}" ownca_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_cert }}"
ownca_privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" ownca_privatekey_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_key }}"
ownca_privatekey_passphrase: "{{ CERT_CONFIG.ca.pwd }}" ownca_privatekey_passphrase: "{{ config_cert.ca.pwd }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: when:
- CERT_CONFIG.ca.pwd | default(none, true) is not none - config_cert.ca.pwd | default(none, true) is not none
- CERT_CONFIG.cert.pwd | default(none, true) is not none - config_cert.cert.pwd | default(none, true) is not none
- CERT_CONFIG.mode == 'ca' - config_cert.mode == 'ca'
- name: Certificates | Internal | Cert | CA-Signed | Generating certificate (plain key; encrypted ca-key) - name: Certificates | Internal | Cert | CA-Signed | Generating certificate (plain key; encrypted ca-key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
csr_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
csr_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
provider: ownca provider: ownca
ownca_not_after: "+{{ CERT_CONFIG.cert.valid_days }}d" ownca_not_after: "+{{ config_cert.cert.valid_days }}d"
ownca_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }}" ownca_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_cert }}"
ownca_privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" ownca_privatekey_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_key }}"
ownca_privatekey_passphrase: "{{ CERT_CONFIG.ca.pwd }}" ownca_privatekey_passphrase: "{{ config_cert.ca.pwd }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: when:
- CERT_CONFIG.ca.pwd | default(none, true) is not none - config_cert.ca.pwd | default(none, true) is not none
- CERT_CONFIG.cert.pwd | default(none, true) is none - config_cert.cert.pwd | default(none, true) is none
- CERT_CONFIG.mode == 'ca' - config_cert.mode == 'ca'
- name: Certificates | Internal | Cert | CA-Signed | Generating certificate (encrypted key; plain ca-key) - name: Certificates | Internal | Cert | CA-Signed | Generating certificate (encrypted key; plain ca-key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
privatekey_passphrase: "{{ CERT_CONFIG.cert.pwd }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
csr_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" privatekey_passphrase: "{{ config_cert.cert.pwd }}"
csr_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
provider: ownca provider: ownca
ownca_not_after: "+{{ CERT_CONFIG.cert.valid_days }}d" ownca_not_after: "+{{ config_cert.cert.valid_days }}d"
ownca_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }}" ownca_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_cert }}"
ownca_privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" ownca_privatekey_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_key }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: when:
- CERT_CONFIG.ca.pwd | default(none, true) is none - config_cert.ca.pwd | default(none, true) is none
- CERT_CONFIG.cert.pwd | default(none, true) is not none - config_cert.cert.pwd | default(none, true) is not none
- CERT_CONFIG.mode == 'ca' - config_cert.mode == 'ca'
- name: Certificates | Internal | Cert | CA-Signed | Generating certificate (plain key; plain ca-key) - name: Certificates | Internal | Cert | CA-Signed | Generating certificate (plain key; plain ca-key)
community.crypto.x509_certificate: community.crypto.x509_certificate:
path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}"
privatekey_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_key }}" select_crypto_backend: "{{ config_cert.cert.backend }}"
csr_path: "{{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_csr }}" privatekey_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"
csr_path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_csr }}"
provider: ownca provider: ownca
ownca_not_after: "+{{ CERT_CONFIG.cert.valid_days }}d" ownca_not_after: "+{{ config_cert.cert.valid_days }}d"
ownca_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }}" ownca_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_cert }}"
ownca_privatekey_path: "{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_key }}" ownca_privatekey_path: "{{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_key }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
no_log: true no_log: true
when: when:
- CERT_CONFIG.ca.pwd | default(none, true) is none - config_cert.ca.pwd | default(none, true) is none
- CERT_CONFIG.cert.pwd | default(none, true) is none - config_cert.cert.pwd | default(none, true) is none
- CERT_CONFIG.mode == 'ca' - config_cert.mode == 'ca'
- name: Certificates | Internal | Cert | CA-Signed | Creating chained certificate - name: Certificates | Internal | Cert | CA-Signed | Creating chained certificate
ansible.builtin.shell: "cat {{ CERT_CONFIG.path }}/{{ name }}.{{ CERT_CONFIG.extension_cert }} ansible.builtin.shell: "cat {{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_cert }}
{{ CERT_CONFIG.ca.path }}/ca.{{ CERT_CONFIG.extension_cert }} > {{ config_cert.ca.path | default(config_cert.path, true) }}/ca.{{ config_cert.extension_cert }} >
{{ CERT_CONFIG.path }}/{{ name }}.chain.{{ CERT_CONFIG.extension_cert }}" {{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.chain.{{ config_cert.extension_cert }}"
args: args:
creates: "{{ CERT_CONFIG.path }}/{{ name }}.chain.{{ CERT_CONFIG.extension_cert }}" creates: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.chain.{{ config_cert.extension_cert }}"
when: CERT_CONFIG.mode == 'ca' when: config_cert.mode == 'ca'
check_mode: false check_mode: false
- name: Certificates | Internal | Cert | CA-Signed | Setting privileges on chained certificate - name: Certificates | Internal | Cert | CA-Signed | Setting privileges on chained certificate
ansible.builtin.file: ansible.builtin.file:
path: "{{ CERT_CONFIG.path }}/{{ name }}.chain.{{ CERT_CONFIG.extension_cert }}" path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.chain.{{ config_cert.extension_cert }}"
mode: "{{ CERT_CONFIG.mode_cert }}" mode: "{{ config_cert.mode_cert }}"
owner: "{{ CERT_CONFIG.owner_cert }}" owner: "{{ config_cert.owner_cert }}"
group: "{{ CERT_CONFIG.group_cert }}" group: "{{ config_cert.group_cert }}"
when: CERT_CONFIG.mode == 'ca' when: config_cert.mode == 'ca'

View File

@ -1,5 +1,12 @@
--- ---
- name: Certificates | Internal | Checking config
ansible.builtin.assert:
that:
- CERT_CONFIG.cert.name or name
- CERT_CONFIG.cert.cn
- CERT_CONFIG.mode != 'ca' or CERT_CONFIG.ca.cn
- name: Certificates | Internal | Installing dependencies - name: Certificates | Internal | Installing dependencies
ansible.builtin.package: ansible.builtin.package:
pkg: ['python3-cryptography'] pkg: ['python3-cryptography']
@ -13,10 +20,14 @@
- name: Certificates | Internal | Minimal CA - name: Certificates | Internal | Minimal CA
ansible.builtin.import_tasks: ca_minimal.yml ansible.builtin.import_tasks: ca_minimal.yml
vars:
config_ca: "{{ CERT_CONFIG }}"
when: CERT_CONFIG.mode == 'ca' when: CERT_CONFIG.mode == 'ca'
tags: [ca] tags: [ca]
- name: Certificates | Internal | Cert - name: Certificates | Internal | Cert
ansible.builtin.import_tasks: cert.yml ansible.builtin.import_tasks: cert.yml
vars:
config_cert: "{{ CERT_CONFIG }}"
when: "CERT_CONFIG.mode in ['ca', 'selfsigned']" when: "CERT_CONFIG.mode in ['ca', 'selfsigned']"
tags: [certs] tags: [certs]

View File

@ -1,5 +1,7 @@
--- ---
# todo: allow for a dictionary of certs to be passed
- name: Certificates | Checking config - name: Certificates | Checking config
ansible.builtin.assert: ansible.builtin.assert:
that: that:
@ -19,6 +21,12 @@
- debug is defined - debug is defined
- debug - debug
- name: Certificates | Checking for invalid domains/hostnames
ansible.builtin.pause:
prompt: "It seems you have configured an invalid domain/hostname: '{{ item }}' - do you want to continue?"
when: not item | valid_hostname
loop: "{{ CERT_CONFIG.cert.domains }}"
- name: Certificates | Internal signed - name: Certificates | Internal signed
ansible.builtin.include_tasks: internal/main.yml ansible.builtin.include_tasks: internal/main.yml
when: "CERT_CONFIG.mode in ['pki', 'ca', 'selfsigned']" when: "CERT_CONFIG.mode in ['pki', 'ca', 'selfsigned']"