From 3de0fee28635e3cfdc7500e2a58491dfb3c8406f Mon Sep 17 00:00:00 2001 From: AnsibleGuy Date: Sun, 12 Feb 2023 21:45:42 +0100 Subject: [PATCH] added config checks/validations --- defaults/main/0_hardcoded.yml | 12 ++++++++++++ defaults/{main.yml => main/1_main.yml} | 2 ++ filter_plugins/utils.py | 24 +++++++++++++++++++++--- tasks/debian/letsencrypt/cert.yml | 10 ++++++++++ tasks/debian/letsencrypt/main.yml | 2 +- tasks/internal/ca_minimal.yml | 6 ++++++ tasks/internal/cert.yml | 6 ++++++ 7 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 defaults/main/0_hardcoded.yml rename defaults/{main.yml => main/1_main.yml} (99%) diff --git a/defaults/main/0_hardcoded.yml b/defaults/main/0_hardcoded.yml new file mode 100644 index 0000000..5748aad --- /dev/null +++ b/defaults/main/0_hardcoded.yml @@ -0,0 +1,12 @@ +--- + +CERT_HC: + letsencrypt: + options: + service: ['apache', 'nginx'] + verbosity: ['v', 'vv', 'vvv', 'vvvv'] + + options: + key_size: + ca: [1024, '1024', 2048, '2048', 4096, '4096', 8192, '8192'] + cert: [1024, '1024', 2048, '2048', 4096, '4096'] diff --git a/defaults/main.yml b/defaults/main/1_main.yml similarity index 99% rename from defaults/main.yml rename to defaults/main/1_main.yml index 35e340b..16c43e4 100644 --- a/defaults/main.yml +++ b/defaults/main/1_main.yml @@ -63,6 +63,7 @@ defaults_certs: 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 email: + key_size: ca: path: @@ -100,3 +101,4 @@ default_le_certbot_cert: # example2: # domains: ['example2.ansibleguy.net'] # email: 'dummy@ansibleguy.net' + diff --git a/filter_plugins/utils.py b/filter_plugins/utils.py index 0f4580e..4e52864 100644 --- a/filter_plugins/utils.py +++ b/filter_plugins/utils.py @@ -13,6 +13,7 @@ class FilterModule(object): "check_email": self.check_email, "le_domains_changed": self.le_domains_changed, "ensure_list": self.ensure_list, + "validate_email": self.validate_email, } @staticmethod @@ -20,7 +21,7 @@ class FilterModule(object): return regex_replace(r'[^0-9a-zA-Z\.]+', '', key.replace(' ', '_')) @staticmethod - def valid_hostname(name: str) -> bool: + def _valid_domain(name: str) -> bool: # see: https://validators.readthedocs.io/en/latest/_modules/validators/domain.html domain = regex_compile( r'^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|' @@ -28,11 +29,14 @@ class FilterModule(object): 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 = domain.match(name) is not None + return domain.match(name) is not None + + @classmethod + def valid_hostname(cls, name: str) -> bool: # see: https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names expr_hostname = r'^[a-zA-Z0-9-\.]{1,253}$' valid_hostname = regex_match(expr_hostname, name) is not None - return all([valid_domain, valid_hostname]) + return all([cls._valid_domain(name), valid_hostname]) @staticmethod def valid_ip(ip: str) -> bool: @@ -52,6 +56,20 @@ class FilterModule(object): return True + @classmethod + def validate_email(cls, email: str) -> bool: + # ToDo: further checks like https://validators.readthedocs.io/en/latest/_modules/validators/email.html#email + if email.find('@') == -1: + return False + + full_len = len(email) + sub_len = len(email.replace('@', '')) + + if full_len != (sub_len + 1): + return False + + return cls._valid_domain(email.split('@', 1)[1]) + @staticmethod def le_domains_changed(running_config: str, cert_key: str, config_domains: list) -> bool: changed = False diff --git a/tasks/debian/letsencrypt/cert.yml b/tasks/debian/letsencrypt/cert.yml index f85f66c..218955d 100644 --- a/tasks/debian/letsencrypt/cert.yml +++ b/tasks/debian/letsencrypt/cert.yml @@ -7,6 +7,16 @@ - debug is defined - debug +# ToDo: path validation +- name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Checking config" + ansible.builtin.assert: + that: + - CERT_CONFIG.letsencrypt.service in CERT_HC.letsencrypt.options.service + - CERT_CONFIG.letsencrypt.verbosity in CERT_HC.letsencrypt.options.verbosity + - le_cert.key_size in CERT_HC.options.key_size.cert + - le_cert.domains | length > 0 + - le_cert.email | validate_email or CERT_CONFIG.cert.email | validate_email + - name: "Certificates | Debian | LetsEncrypt Certbot | {{ le_name }} | Creating directory" ansible.builtin.file: path: "{{ item }}" diff --git a/tasks/debian/letsencrypt/main.yml b/tasks/debian/letsencrypt/main.yml index bb43ae3..ff7b9f1 100644 --- a/tasks/debian/letsencrypt/main.yml +++ b/tasks/debian/letsencrypt/main.yml @@ -6,7 +6,7 @@ - CERT_CONFIG.letsencrypt.certs | length > 0 - CERT_CONFIG.letsencrypt.service | default(false, true) - CERT_CONFIG.letsencrypt.email | default(false, true) or CERT_CONFIG.letsencrypt.certs | check_email - - "CERT_CONFIG.letsencrypt.service in ['apache', 'nginx']" + - CERT_CONFIG.letsencrypt.service in CERT_HC.letsencrypt.options.service - name: Certificates | Debian | LetsEncrypt Certbot | Configure for Apache2 ansible.builtin.import_tasks: apache.yml diff --git a/tasks/internal/ca_minimal.yml b/tasks/internal/ca_minimal.yml index 0190ef2..8566798 100644 --- a/tasks/internal/ca_minimal.yml +++ b/tasks/internal/ca_minimal.yml @@ -2,6 +2,12 @@ # creating a minimal ca +- name: Certificates | Internal | Minimal CA | Checking config + ansible.builtin.assert: + that: + - config_ca.ca.key_size in CERT_HC.options.key_size.ca + - config_ca.ca.email is none or config_ca.ca.email | validate_email + - name: Certificates | Internal | Minimal CA | Creating ca directory ansible.builtin.file: path: "{{ config_ca.ca.path | default(config_ca.path, true) }}" diff --git a/tasks/internal/cert.yml b/tasks/internal/cert.yml index 5081fca..5387530 100644 --- a/tasks/internal/cert.yml +++ b/tasks/internal/cert.yml @@ -1,5 +1,11 @@ --- +- name: Certificates | Internal | Cert | Checking config + ansible.builtin.assert: + that: + - config_cert.cert.key_size in CERT_HC.options.key_size.cert + - config_cert.cert.email is none or config_cert.cert.email | validate_email + - name: Certificates | Internal | Cert | Generate private key (encrypted) community.crypto.openssl_privatekey: path: "{{ config_cert.path }}/{{ name | default(config_cert.cert.name) }}.{{ config_cert.extension_key }}"