diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f800a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vault_pass \ No newline at end of file diff --git a/inventories/group_vars/all.example.yml b/inventories/group_vars/all.example.yml new file mode 100644 index 0000000..401ba80 --- /dev/null +++ b/inventories/group_vars/all.example.yml @@ -0,0 +1,52 @@ +backupcow__repo_url: "git@gitea.servercow.de:Servercow-Internal/backupcow-dockerized.git" # Or else +backupcow__install_path: "/opt/backupcow-dockerized" + +opnsense_host: "45.85.48.5" + +pdnsadmin_api_host: "pde.servercow.com" + +deploy_keys: True + +use_docker_image_mirror: true +docker_mirror_location: "tinc" # or "tinc" based on your preference +docker_install_source: "tinc" +crowdsec_install_source: "tinc" # or "official" based on your preference +crowdsec_lapi_url: "https://45.85.49.1:8080" + + +# Basic server and authentication information. +# You have to provide the distributed setup yourself. +checkmk_agent_version: "2.3.0p34" +checkmk_agent_edition: "cee" +checkmk_agent_user: "{{ checkmk_automation_user }}" +checkmk_agent_pass: "{{ checkmk_automation_pass }}" +# Here comes the part, where we get into remote registration +checkmk_agent_server_protocol: https +# The following should be set to the central site. +# This where you configure the host objects. +# Currently the agent package is also pulled from here. +checkmk_agent_server: servercow.observer +checkmk_agent_site: "scowmon" +checkmk_server_url: "https://servercow.observer" +checkmk_monitoring_site: "scowmon" +checkmk_host_folder: "backupmx" +# The following should be pointed to the respective remote site. +# This is where the registration will happen. +checkmk_agent_registration_server: "{{ checkmk_agent_server }}" +checkmk_agent_registration_site: "{{ checkmk_agent_site }}" +# These options need to be enabled for all registrations to work. +# You can however disable the one you do not want to perform. +# But the host needs to be added and changes activated in any case. +checkmk_agent_auto_activate: 'true' +checkmk_agent_update: 'true' +checkmk_agent_tls: 'true' +# checkmk_agent_server_validate_certs: 'true' +# These are some generic agent options you might want to configure. +checkmk_agent_discover: 'true' +checkmk_agent_discover_max_parallel_tasks: 2 +checkmk_agent_force_install: 'true' +checkmk_agent_delegate_api_calls: localhost +checkmk_agent_delegate_download: localhost +checkmk_agent_host_name: "{{ backupcow__hostname }}" +checkmk_agent_host_folder: "{{ checkmk_agent_folder }}" +checkmk_agent_host_ip: "{{ bmx_ipv4_public }}" \ No newline at end of file diff --git a/inventories/group_vars/all.yml b/inventories/group_vars/all.yml new file mode 100644 index 0000000..3281e60 --- /dev/null +++ b/inventories/group_vars/all.yml @@ -0,0 +1,47 @@ +# Standardwerte, die überschrieben werden können +os_update_auto_upgrade: true +os_also_update_mirror: true # Can either be true or false | Use this to enable mirror changes. Useful for first runs. +os_update_mirrors: + - mirror: "http://mirror.tinc.gmbh/debian" # Enter a main mirror here (not security) + type: "main" + - mirror: "http://mirror.tinc.gmbh/debian-security" # Enter a security mirror here + type: "security" +os_update_major_version: false # Can either be true or false | To toggle if systems need to be upgraded to newer codename +os_update_version_codename: "bookworm" # Change to switch major release (e.g. bookworm or trixie) | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on + +# Basic server and authentication information. +# You have to provide the distributed setup yourself. +checkmk_agent_version: "2.3.0p34" +checkmk_agent_edition: "cee" +checkmk_agent_user: "{{ checkmk_automation_user }}" +checkmk_agent_pass: "{{ checkmk_automation_pass }}" +# Here comes the part, where we get into remote registration +checkmk_agent_server_protocol: https +# The following should be set to the central site. +# This where you configure the host objects. +# Currently the agent package is also pulled from here. +checkmk_agent_server: servercow.observer +checkmk_agent_site: "scowmon" +checkmk_server_url: "https://servercow.observer" +checkmk_monitoring_site: "scowmon" +checkmk_host_folder: "backupmx" +# The following should be pointed to the respective remote site. +# This is where the registration will happen. +checkmk_agent_registration_server: "{{ checkmk_agent_server }}" +checkmk_agent_registration_site: "{{ checkmk_agent_site }}" +# These options need to be enabled for all registrations to work. +# You can however disable the one you do not want to perform. +# But the host needs to be added and changes activated in any case. +checkmk_agent_auto_activate: 'true' +checkmk_agent_update: 'true' +checkmk_agent_tls: 'true' +# checkmk_agent_server_validate_certs: 'true' +# These are some generic agent options you might want to configure. +checkmk_agent_discover: 'true' +checkmk_agent_discover_max_parallel_tasks: 2 +checkmk_agent_force_install: 'true' +checkmk_agent_delegate_api_calls: localhost +checkmk_agent_delegate_download: localhost +checkmk_agent_host_name: "{{ backupcow__hostname }}" +checkmk_agent_host_folder: "{{ checkmk_agent_folder }}" +checkmk_agent_host_ip: "{{ bmx_ipv4_public }}" diff --git a/inventories/group_vars/icp-fra-pve1.yml b/inventories/group_vars/icp-fra-pve1.yml new file mode 100644 index 0000000..e2f55e7 --- /dev/null +++ b/inventories/group_vars/icp-fra-pve1.yml @@ -0,0 +1,36 @@ +# Basic server and authentication information. +# You have to provide the distributed setup yourself. +checkmk_agent_version: "2.4.0p8" +checkmk_agent_edition: "cee" +checkmk_agent_user: "{{ checkmk_automation_user }}" +checkmk_agent_pass: "{{ checkmk_automation_pass }}" +# Here comes the part, where we get into remote registration +checkmk_agent_server_protocol: https +# The following should be set to the central site. +# This where you configure the host objects. +# Currently the agent package is also pulled from here. +checkmk_agent_server: servercow.observer +checkmk_agent_site: "scowmon" +checkmk_server_url: "https://servercow.observer" +checkmk_monitoring_site: "scowmon" +checkmk_host_folder: "pves/icp-fra-pve1" +# The following should be pointed to the respective remote site. +# This is where the registration will happen. +checkmk_agent_registration_server: "{{ checkmk_agent_server }}" +checkmk_agent_registration_site: "{{ checkmk_agent_site }}" +# These options need to be enabled for all registrations to work. +# You can however disable the one you do not want to perform. +# But the host needs to be added and changes activated in any case. +checkmk_agent_auto_activate: 'true' +checkmk_agent_update: 'true' +checkmk_agent_tls: 'true' +checkmk_agent_server_validate_certs: 'true' +# These are some generic agent options you might want to configure. +checkmk_agent_discover: 'true' +checkmk_agent_discover_max_parallel_tasks: 2 +checkmk_agent_force_install: 'true' +checkmk_agent_delegate_api_calls: localhost +checkmk_agent_delegate_download: localhost +checkmk_agent_host_name: "{{ ansible_hostname }}" +checkmk_agent_host_folder: "{{ checkmk_agent_folder }}" +checkmk_agent_host_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv6']['address'] }}" \ No newline at end of file diff --git a/inventories/icp-fra-pve1.yml b/inventories/icp-fra-pve1.yml new file mode 100644 index 0000000..ea26983 --- /dev/null +++ b/inventories/icp-fra-pve1.yml @@ -0,0 +1,20 @@ +icp-fra-pve1: + hosts: + icp-fra-pve1-01: + ansible_host: "2a07:6fc0:b:2808::81" + ansible_user: "tincadmin" + icp-fra-pve1-02: + ansible_host: "2a07:6fc0:b:2808::82" + ansible_user: "tincadmin" + icp-fra-pve1-03: + ansible_host: "2a07:6fc0:b:2808::83" + ansible_user: "tincadmin" + icp-fra-pve1-04: + ansible_host: "2a07:6fc0:b:2808::84" + ansible_user: "tincadmin" + icp-fra-pve1-05: + ansible_host: "2a07:6fc0:b:2808::85" + ansible_user: "tincadmin" + icp-fra-pve1-06: + ansible_host: "2a07:6fc0:b:2808::86" + ansible_user: "tincadmin" \ No newline at end of file diff --git a/inventories/icp-frav-packer01.yml b/inventories/icp-frav-packer01.yml new file mode 100644 index 0000000..d4b3c5c --- /dev/null +++ b/inventories/icp-frav-packer01.yml @@ -0,0 +1,4 @@ + +icp-frav-packer01: + ansible_host: "2a07:6fc0:b:2817::70" + ansible_user: "root" \ No newline at end of file diff --git a/playbooks/deploy-clamav-server.yml b/playbooks/deploy-clamav-server.yml new file mode 100644 index 0000000..1991732 --- /dev/null +++ b/playbooks/deploy-clamav-server.yml @@ -0,0 +1,4 @@ +--- +- hosts: clamav-servers + roles: + - deploy-clamd \ No newline at end of file diff --git a/playbooks/hardening/manage-ssh-keys.yaml b/playbooks/hardening/manage-ssh-keys.yaml index 8098838..e6c7be9 100644 --- a/playbooks/hardening/manage-ssh-keys.yaml +++ b/playbooks/hardening/manage-ssh-keys.yaml @@ -1,6 +1,6 @@ - hosts: all - vars: - good_keys: "{{ lookup('env', 'good_keys') | from_json }}" - bad_keys: "{{ lookup('env', 'bad_keys') | from_json }}" + # vars: + # good_keys: "{{ lookup('env', 'good_keys') | from_json }}" + # bad_keys: "{{ lookup('env', 'bad_keys') | from_json }}" roles: - role: manage-ssh-keys \ No newline at end of file diff --git a/playbooks/managed-mailcow/count-mailboxes.yml b/playbooks/managed-mailcow/count-mailboxes.yml new file mode 100644 index 0000000..a69888c --- /dev/null +++ b/playbooks/managed-mailcow/count-mailboxes.yml @@ -0,0 +1,43 @@ +--- +- name: Mailcow Mailbox Counter + hosts: all + gather_facts: no + tasks: + - import_role: + name: managed-mailcow + tasks_from: find-mailcow-composedir.yml + + - name: Read mailcow.conf and extract DBROOT + ansible.builtin.shell: | + bash -c 'source {{ mailcow_dir_result.files[0].path }}/mailcow.conf && echo $DBROOT' + register: dbroot_output + + - name: Count active mailboxes from mailcow database + ansible.builtin.shell: | + docker compose exec mysql-mailcow \ + mysql -u root -p{{ dbroot_output.stdout }} -D mailcow -N -e \ + "SELECT COUNT(*) FROM mailbox WHERE active=1;" + args: + chdir: "{{ mailcow_dir_result.files[0].path }}" + register: mailbox_count + changed_when: false + + - name: Set fact with mailbox count as integer + ansible.builtin.set_fact: + mailbox_count_int: "{{ mailbox_count.stdout | int }}" + +- name: Summiere alle Mailboxen über alle Hosts + hosts: all + gather_facts: false + run_once: true + tasks: + + - name: Summiere aktive Mailboxen + ansible.builtin.set_fact: + total_mailboxes: "{{ (total_mailboxes | default(0) | int) + (item.value.mailbox_count_int | default(0) | int) }}" + loop: "{{ hostvars | dict2items }}" + when: "'mailbox_count_int' in item.value" + + - name: Zeige Gesamtsumme + ansible.builtin.debug: + msg: "Gesamtanzahl aktiver Mailboxen: {{ total_mailboxes }}" \ No newline at end of file diff --git a/playbooks/managed-mailcow/find-roundcube-versions.yaml b/playbooks/managed-mailcow/find-roundcube-versions.yaml new file mode 100644 index 0000000..4351173 --- /dev/null +++ b/playbooks/managed-mailcow/find-roundcube-versions.yaml @@ -0,0 +1,69 @@ +--- +- name: Prüfe mailcow-Installation und extrahiere Roundcube-Version aus CHANGELOG.md + hosts: all + become: true + vars: + mailcow_search_paths: + - /opt + - /data + - /root + - /storage + rc_dirs: + - rc + - roundcube + - roundcubemail + + tasks: + - name: Finde mailcow-dockerized Verzeichnis + ansible.builtin.find: + file_type: directory + paths: "{{ mailcow_search_paths }}" + patterns: mailcow-dockerized + recurse: yes + register: mailcow_dir_result + ignore_errors: true + + - name: Setze mailcow_root wenn gefunden + ansible.builtin.set_fact: + mailcow_root: "{{ mailcow_dir_result.files[0].path }}" + when: mailcow_dir_result.matched > 0 + + - name: Prüfe auf Roundcube-Ordner unter data/web + ansible.builtin.stat: + path: "{{ mailcow_root }}/data/web/{{ item }}" + loop: "{{ rc_dirs }}" + register: rc_stat + when: mailcow_root is defined + + - name: Bestimme den tatsächlichen Roundcube-Pfad + ansible.builtin.set_fact: + rc_path: "{{ mailcow_root }}/data/web/{{ item.item }}" + loop: "{{ rc_stat.results }}" + when: item.stat.exists and item.stat.isdir + + - name: Prüfe ob CHANGELOG.md existiert + ansible.builtin.stat: + path: "{{ rc_path }}/CHANGELOG.md" + register: changelog_stat + when: rc_path is defined + + - name: Extrahiere Version aus CHANGELOG.md + ansible.builtin.shell: | + grep -m1 -Po '(?<=## Release )\S+' {{ rc_path }}/CHANGELOG.md + register: rc_version + changed_when: false + when: + - changelog_stat.stat.exists + - changelog_stat.stat.isfile + + - name: Gib gefundene Roundcube-Version aus + ansible.builtin.debug: + msg: "Roundcube-Version (laut CHANGELOG.md): {{ rc_version.stdout }}" + when: rc_version.stdout != "" + + - name: Warnung wenn keine CHANGELOG.md gefunden wurde + ansible.builtin.debug: + msg: "Keine CHANGELOG.md unter {{ rc_path }} gefunden." + when: + - rc_path is defined + - not changelog_stat.stat.exists \ No newline at end of file diff --git a/playbooks/managed-mailcow/install-register-cmk-agent.yaml b/playbooks/managed-mailcow/install-register-cmk-agent.yaml new file mode 100644 index 0000000..756ee66 --- /dev/null +++ b/playbooks/managed-mailcow/install-register-cmk-agent.yaml @@ -0,0 +1,44 @@ +- name: "Register hosts against a remote site. Both for updates and TLS." + hosts: all + strategy: linear + vars: + # Basic server and authentication information. + # You have to provide the distributed setup yourself. + checkmk_agent_version: "2.3.0p14" + checkmk_agent_edition: "cee" + checkmk_agent_user: "automation" + checkmk_agent_pass: "@JQVEOANOYTUKWGALS@E" + # Here comes the part, where we get into remote registration + checkmk_agent_server_protocol: https + # The following should be set to the central site. + # This where you configure the host objects. + # Currently the agent package is also pulled from here. + checkmk_agent_server: servercow.observer + checkmk_agent_site: "scowmon" + # The following should be pointed to the respective remote site. + # This is where the registration will happen. + checkmk_agent_registration_server: "{{ checkmk_agent_server }}" + checkmk_agent_registration_site: "{{ checkmk_agent_site }}" + # The folder might differ from your remote site name, + # as it is the technical path. Check your configuration for this information. + checkmk_agent_folder: "/managed_mailcows" + # These options need to be enabled for all registrations to work. + # You can however disable the one you do not want to perform. + # But the host needs to be added and changes activated in any case. + checkmk_agent_auto_activate: 'true' + checkmk_agent_update: 'true' + checkmk_agent_tls: 'true' + checkmk_agent_add_host: 'true' + # These are some generic agent options you might want to configure. + checkmk_agent_discover: 'true' + checkmk_agent_discover_max_parallel_tasks: 2 + checkmk_agent_force_install: 'true' + checkmk_agent_delegate_api_calls: localhost + checkmk_agent_delegate_download: "{{ inventory_hostname }}" + checkmk_agent_host_name: "{{ inventory_hostname }}" + checkmk_agent_host_folder: "{{ checkmk_agent_folder }}" + checkmk_agent_host_ip: "{{ ansible_host }}" + checkmk_agent_host_attributes: + ipaddress: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + roles: + - checkmk.general.agent \ No newline at end of file diff --git a/playbooks/managed-mailcow/update-mailcow.yaml b/playbooks/managed-mailcow/update-mailcow.yaml index 737b66e..adb0b37 100644 --- a/playbooks/managed-mailcow/update-mailcow.yaml +++ b/playbooks/managed-mailcow/update-mailcow.yaml @@ -1,14 +1,27 @@ - name: Update mailcow (update.sh) hosts: all + vars: + github_mailcow_ver: "2025-09b" # GitHub Version Tag | Value to compare the current running mailcow version to. + disk_space_percent_max: "97" # Number in percent | Defines the max allowed disk utilization until ansible is not updating mailcow automatically + debug: true # Or False if you dont' wanna see verbose outputs of role outputs tasks: - import_role: name: roles/managed-mailcow tasks_from: find-mailcow-composedir.yml - + + - import_role: + name: roles/managed-mailcow + tasks_from: install-mailcow-components.yml + - import_role: name: roles/managed-mailcow tasks_from: update-mailcow.yml - vars: - github_mailcow_ver: "2024-11b" # GitHub Version Tag | Value to compare the current running mailcow version to. - disk_space_percent_max: "97" # Number in percent | Defines the max allowed disk utilization until ansible is not updating mailcow automatically - debug: true # Or False if you dont' wanna see verbose outputs of role outputs \ No newline at end of file + + - import_role: + name: roles/docker + tasks_from: restart-daemon.yml + when: github_mailcow_ver == "2025-09b" # Only restart docker if mailcow was updated + + - import_role: + name: roles/docker + tasks_from: cleanup-all.yml \ No newline at end of file diff --git a/playbooks/os-change-mirror.yml b/playbooks/os-change-mirror.yml new file mode 100644 index 0000000..2184dd9 --- /dev/null +++ b/playbooks/os-change-mirror.yml @@ -0,0 +1,17 @@ +- name: "Change Mirror" + hosts: all + tasks: + - name: Verify if system is Debian + ansible.builtin.debug: + msg: "This playbook is running on a Debian system." + when: ansible_os_family == "Debian" + + - name: Stop playbook if system is not Debian + ansible.builtin.fail: + msg: "This playbook only supports Debian." + when: ansible_os_family != "Debian" + + - name: Include OS change mirror role + ansible.builtin.include_role: + name: os-updates + tasks_from: update_mirrors \ No newline at end of file diff --git a/playbooks/os-major-upgrade.yml b/playbooks/os-major-upgrade.yml new file mode 100644 index 0000000..52c3f61 --- /dev/null +++ b/playbooks/os-major-upgrade.yml @@ -0,0 +1,20 @@ +- hosts: all + vars: + os_update_major_version: true # Can either be true or false | To toggle if systems need to be upgraded to newer codename + os_update_version_codename: "trixie" # Change to switch major release (e.g. bookworm or trixie) | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on + tasks: + - name: Verify if system is Debian + debug: + msg: "This playbook is running on a Debian system." + when: ansible_os_family == "Debian" + + - name: Stop playbook if system is not Debian + fail: + msg: "This playbook only supports Debian." + when: ansible_os_family != "Debian" + + - name: Include OS update role + ansible.builtin.include_role: + name: os-updates + tasks_from: update_major_version + when: ansible_os_family == "Debian" \ No newline at end of file diff --git a/playbooks/os-update.yml b/playbooks/os-update.yml index b054ebb..12a273d 100644 --- a/playbooks/os-update.yml +++ b/playbooks/os-update.yml @@ -1,4 +1,7 @@ - hosts: all + vars: + os_update_major_version: true # Can either be true or false | To toggle if systems need to be upgraded to newer codename + os_update_version_codename: "trixie" # Change to switch major release (e.g. bookworm or trixie) | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on tasks: - name: Verify if system is Debian debug: diff --git a/playbooks/setup-checkmk-monitoring.yml b/playbooks/setup-checkmk-monitoring.yml new file mode 100644 index 0000000..8598c04 --- /dev/null +++ b/playbooks/setup-checkmk-monitoring.yml @@ -0,0 +1,35 @@ +- name: "Setup CheckMK Monitoring" + hosts: all + vars_files: + - ../vault.yml + tasks: + - name: "Import create Host Task" + become: true + ansible.builtin.import_role: + name: checkmk-monitoring + tasks_from: create-host.yaml + + - name: "Import sign-bake-agents Task" + become: true + ansible.builtin.import_role: + name: checkmk-monitoring + tasks_from: sign-bake-agents.yaml + ignore_errors: true + + - name: "Register hosts against a remote site. Both for updates and TLS." + import_role: + name: checkmk.general.agent + tags: + - checkmk-deploy + + - name: "Wait 2 Minutes for CheckMK Agent to be ready" + ansible.builtin.pause: + minutes: 2 + tags: + - checkmk-deploy + + - name: "Import discover-host Task" + become: true + ansible.builtin.import_role: + name: checkmk-monitoring + tasks_from: discover-host.yaml diff --git a/playbooks/setup-chronyd.yml b/playbooks/setup-chronyd.yml new file mode 100644 index 0000000..69748f7 --- /dev/null +++ b/playbooks/setup-chronyd.yml @@ -0,0 +1,12 @@ +- name: "Setup chronyd" + hosts: all + tasks: + - name: Verify if system is Debian or Ubuntu + ansible.builtin.debug: + msg: "This playbook is running on a Debian or Ubuntu system." + when: ansible_os_family in ["Debian", "Ubuntu"] + + - name: Import chronyd role + ansible.builtin.include_role: + name: system + tasks_from: setup-timeserver \ No newline at end of file diff --git a/roles/checkmk-monitoring/handlers/main.yaml b/roles/checkmk-monitoring/handlers/main.yaml new file mode 100644 index 0000000..162be2c --- /dev/null +++ b/roles/checkmk-monitoring/handlers/main.yaml @@ -0,0 +1,20 @@ +- name: "Activate Changes" + checkmk.general.activation: + server_url: "{{ checkmk_server_url }}" + site: "{{ checkmk_monitoring_site }}" + automation_user: "{{ checkmk_automation_user }}" + automation_secret: "{{ checkmk_automation_pass }}" + run_once: true + delegate_to: localhost + +- name: "Sign and bake pending agent jobs" + checkmk.general.bakery: + server_url: "{{ checkmk_server_url }}" + site: "{{ checkmk_monitoring_site }}" + automation_user: "{{ checkmk_automation_user }}" + automation_secret: "{{ checkmk_automation_pass }}" + signature_key_id: 1 + signature_key_passphrase: "{{ checkmk_agent_bakery_passphrase }}" + state: "baked_signed" + delegate_to: localhost + run_once: true \ No newline at end of file diff --git a/roles/checkmk-monitoring/tasks/create-host.yaml b/roles/checkmk-monitoring/tasks/create-host.yaml new file mode 100644 index 0000000..66cc374 --- /dev/null +++ b/roles/checkmk-monitoring/tasks/create-host.yaml @@ -0,0 +1,15 @@ +- name: "Create new Host at CheckMK Server" + checkmk.general.host: + server_url: "{{ checkmk_server_url }}" + site: "{{ checkmk_monitoring_site }}" + automation_user: "{{ checkmk_automation_user }}" + automation_secret: "{{ checkmk_automation_pass }}" + name: "{{ checkmk_agent_host_name }}" + folder: "{{ checkmk_host_folder }}" + attributes: + ipv6address: "{{ ansible_host }}" + state: present + delegate_to: localhost + notify: + - Activate Changes + - Sign and bake pending agent jobs \ No newline at end of file diff --git a/roles/checkmk-monitoring/tasks/delete-host.yaml b/roles/checkmk-monitoring/tasks/delete-host.yaml new file mode 100644 index 0000000..4bae5fe --- /dev/null +++ b/roles/checkmk-monitoring/tasks/delete-host.yaml @@ -0,0 +1,28 @@ +- name: "Delete Host at CheckMK Server" + checkmk.general.host: + server_url: "{{ checkmk_server_url }}" + site: "{{ checkmk_monitoring_site }}" + automation_user: "{{ checkmk_automation_user }}" + automation_secret: "{{ checkmk_automation_pass }}" + name: "{{ backupcow__hostname }}" + folder: "{{ checkmk_host_folder }}" + attributes: + ipaddress: "{{ bmx_ipv4_public }}" + state: absent + notify: + - Activate Changes + - Sign and bake pending agent jobs + +- name: "Remove CheckMK Agent from Host" + ansible.builtin.apt: + name: "check-mk-agent" + state: absent + purge: true + when: ansible_facts['distribution'] == 'Ubuntu' or ansible_facts['distribution'] == 'Debian' + register: cmk_agent_removal + +- name: "Purge CheckMK Agent Configuration from Host" + ansible.builtin.file: + name: "/var/lib/cmk-agent" + state: absent + when: cmk_agent_removal.changed \ No newline at end of file diff --git a/roles/checkmk-monitoring/tasks/discover-host.yaml b/roles/checkmk-monitoring/tasks/discover-host.yaml new file mode 100644 index 0000000..8b7a195 --- /dev/null +++ b/roles/checkmk-monitoring/tasks/discover-host.yaml @@ -0,0 +1,10 @@ +- name: "Run CheckMK Discovery for Host" + checkmk.general.discovery: + server_url: "{{ checkmk_server_url }}" + site: "{{ checkmk_monitoring_site }}" + automation_user: "{{ checkmk_automation_user }}" + automation_secret: "{{ checkmk_automation_pass }}" + host_name: "{{ ansible_hostname }}" + state: "fix_all" + notify: + - Activate Changes \ No newline at end of file diff --git a/roles/checkmk-monitoring/tasks/sign-bake-agents.yaml b/roles/checkmk-monitoring/tasks/sign-bake-agents.yaml new file mode 100644 index 0000000..a2fc661 --- /dev/null +++ b/roles/checkmk-monitoring/tasks/sign-bake-agents.yaml @@ -0,0 +1,9 @@ +- name: "Sign and bake pending agent jobs" + checkmk.general.bakery: + server_url: "{{ checkmk_server_url }}" + site: "{{ checkmk_monitoring_site }}" + automation_user: "{{ checkmk_automation_user }}" + automation_secret: "{{ checkmk_automation_pass }}" + signature_key_id: 1 + signature_key_passphrase: "{{ checkmk_agent_bakery_passphrase }}" + state: "baked_signed" \ No newline at end of file diff --git a/roles/deploy-clamd/defaults/main.yml b/roles/deploy-clamd/defaults/main.yml new file mode 100644 index 0000000..50f5474 --- /dev/null +++ b/roles/deploy-clamd/defaults/main.yml @@ -0,0 +1 @@ +clamd_version: 1.4.2 \ No newline at end of file diff --git a/roles/deploy-clamd/handlers/main.yml b/roles/deploy-clamd/handlers/main.yml new file mode 100644 index 0000000..11f2825 --- /dev/null +++ b/roles/deploy-clamd/handlers/main.yml @@ -0,0 +1,16 @@ +- name: "Reload Systemd Daemon" + systemd_service: + daemon_reload: true + +- name: "Start Clamd Service" + systemd_service: + name: clamd + state: started + enabled: true + +- name: "Start Freshclam Service" + systemd_service: + name: freshclam + state: started + enabled: true + \ No newline at end of file diff --git a/roles/deploy-clamd/tasks/compile-clamav.yml b/roles/deploy-clamd/tasks/compile-clamav.yml new file mode 100644 index 0000000..54ee995 --- /dev/null +++ b/roles/deploy-clamd/tasks/compile-clamav.yml @@ -0,0 +1,75 @@ +- name: "Download latest ClamAV Version to Control Node" + get_url: + url: https://www.clamav.net/downloads/production/clamav-{{ clamd_version }}.tar.gz + dest: "/tmp/clamav-{{ clamd_version }}.tar.gz" + delegate_to: localhost + +- name: Copy ClamAV Tar from Control Node to Ansible Host + copy: + src: "/tmp/clamav-{{ clamd_version }}.tar.gz" + dest: "/usr/local/src/clamav-{{ clamd_version }}.tar.gz" + +- name: "Extract ClamAV Tar on Ansible Host" + unarchive: + src: "/usr/local/src/clamav-{{ clamd_version }}.tar.gz" + dest: "/usr/local/src/" + remote_src: true + +- name: "Create Build Folder in ClamAV Dir" + file: + path: "/usr/local/src/clamav-{{ clamd_version }}/build" + state: directory + +- name: "Pin Cargo Regex Syntax Version" + args: + chdir: "/usr/local/src/clamav-{{ clamd_version }}/build" + shell: | + cargo update -p regex-syntax --precise 0.8.3 + +- name: "Cmake ClamAV" + args: + chdir: "/usr/local/src/clamav-{{ clamd_version }}/build" + shell: | + cmake .. -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_INSTALL_LIBDIR=lib -D APP_CONFIG_DIRECTORY=/etc/clamav -D DATABASE_DIRECTORY=/var/lib/clamav -D ENABLE_JSON_SHARED=OFF + +- name: "Compile ClamAV" + args: + chdir: "/usr/local/src/clamav-{{ clamd_version }}/build" + shell: | + cmake --build . + +- name: "Test Compiled ClamAV" + args: + chdir: "/usr/local/src/clamav-{{ clamd_version }}/build" + shell: | + ctest . + +- name: "Install compiled ClamAV" + args: + chdir: "/usr/local/src/clamav-{{ clamd_version }}/build" + shell: | + cmake --build . --target install + +- name: "Create Freshclam Log File" + file: + path: "/var/log/freshclam.log" + state: touch + owner: clamav + group: clamav + mode: '600' + +- name: "Create ClamAV Log File" + file: + path: "/var/log/clamav.log" + state: touch + owner: clamav + group: clamav + mode: '600' + +- name: "Set ClamAV Signature Database Permission" + file: + path: "/var/lib/clamav" + state: directory + owner: clamav + group: clamav + recurse: yes diff --git a/roles/deploy-clamd/tasks/configure-clamav.yml b/roles/deploy-clamd/tasks/configure-clamav.yml new file mode 100644 index 0000000..23514e9 --- /dev/null +++ b/roles/deploy-clamd/tasks/configure-clamav.yml @@ -0,0 +1,27 @@ +- name: Deploy ClamAV Systemd Service + template: + src: templates/systemd-clamav-service.j2 + dest: /etc/systemd/system/clamd.service + notify: + - Reload Systemd Daemon + +- name: Deploy ClamAV Freshclam Service + template: + src: templates/systemd-freshclam-service.j2 + dest: /etc/systemd/system/freshclam.service + notify: + - Reload Systemd Daemon + +- name: Deploy Freshclam Config File + template: + src: templates/freshclam-config.j2 + dest: /etc/clamav/freshclam.conf + notify: + - Start Freshclam Service + +- name: Deploy ClamAV Config File + template: + src: templates/clamav-config.j2 + dest: /etc/clamav/clamd.conf + notify: + - Start Clamd Service \ No newline at end of file diff --git a/roles/deploy-clamd/tasks/install-dependencies.yml b/roles/deploy-clamd/tasks/install-dependencies.yml new file mode 100644 index 0000000..8ee3e6b --- /dev/null +++ b/roles/deploy-clamd/tasks/install-dependencies.yml @@ -0,0 +1,41 @@ +- name: "Install ClamAV Compilation Dependencies" + ansible.builtin.apt: + pkg: + - curl + - gcc + - make + - pkg-config + - python3 + - python3-pip + - python3-pytest + - valgrind + - cmake + - check + - libbz2-dev + - libcurl4-openssl-dev + - libjson-c-dev + - libmilter-dev + - libncurses5-dev + - libpcre2-dev + - libssl-dev + - libxml2-dev + - zlib1g-dev + - sudo + state: present + +- name: Check if cargo is installed already + shell: command -v cargo + register: cargo_exists + ignore_errors: true + +- name: "Install rusttoolchain for Compilation" + become: true + shell: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y + when: cargo_exists.rc != 0 + +- name: Ensure Cargo is set in Path + shell: | + source $HOME/.cargo/env + args: + executable: /bin/bash \ No newline at end of file diff --git a/roles/deploy-clamd/tasks/main.yml b/roles/deploy-clamd/tasks/main.yml new file mode 100644 index 0000000..5ea89c7 --- /dev/null +++ b/roles/deploy-clamd/tasks/main.yml @@ -0,0 +1,12 @@ +- name: Install ClamAV Dependencies + import_tasks: install-dependencies.yml + when: ansible_facts['os_family']|lower == 'debian' + +- name: Setup ClamAV Service User/Group + import_tasks: setup-clamav-user-group.yml + +- name: Compile ClamAV + import_tasks: compile-clamav.yml + +- name: Configure ClamAV + import_tasks: configure-clamav.yml \ No newline at end of file diff --git a/roles/deploy-clamd/tasks/setup-clamav-user-group.yml b/roles/deploy-clamd/tasks/setup-clamav-user-group.yml new file mode 100644 index 0000000..cc9766e --- /dev/null +++ b/roles/deploy-clamd/tasks/setup-clamav-user-group.yml @@ -0,0 +1,13 @@ +- name: "Setup ClamAV Service Group" + group: + name: clamav + state: present + +- name: "Setup ClamAV Service User" + user: + name: clamav + comment: ClamAV Service Account + shell: /bin/false + group: clamav + + diff --git a/roles/deploy-clamd/templates/clamav-config.j2 b/roles/deploy-clamd/templates/clamav-config.j2 new file mode 100644 index 0000000..40cf2f1 --- /dev/null +++ b/roles/deploy-clamd/templates/clamav-config.j2 @@ -0,0 +1,81 @@ +TCPSocket 3310 +TCPAddr {{ ansible_default_ipv6.address }} + +User clamav +ScanMail true +ScanArchive true +ArchiveBlockEncrypted false +MaxDirectoryRecursion 15 +FollowDirectorySymlinks false +FollowFileSymlinks false +ReadTimeout 180 +MaxThreads 24 +MaxConnectionQueueLength 30 +LogSyslog true +LogRotate true +LogFacility LOG_LOCAL6 +LogClean false +LogVerbose false +PreludeEnable no +PreludeAnalyzerName ClamAV +DatabaseDirectory /var/lib/clamav +OfficialDatabaseOnly false +SelfCheck 3600 +Foreground false +Debug false +ScanPE true +MaxEmbeddedPE 10M +ScanOLE2 true +ScanPDF true +ScanHTML true +MaxHTMLNormalize 10M +MaxHTMLNoTags 2M +MaxScriptNormalize 5M +MaxZipTypeRcg 1M +ScanSWF true +ExitOnOOM false +LeaveTemporaryFiles false +AlgorithmicDetection true +ScanELF true +IdleTimeout 30 +CrossFilesystems true +PhishingSignatures true +PhishingScanURLs true +PhishingAlwaysBlockSSLMismatch false +PhishingAlwaysBlockCloak false +PartitionIntersection false +DetectPUA true +ScanPartialMessages false +HeuristicScanPrecedence false +StructuredDataDetection false +CommandReadTimeout 30 +SendBufTimeout 200 +MaxQueue 100 +ExtendedDetectionInfo true +OLE2BlockMacros false +AllowAllMatchScan true +ForceToDisk false +DisableCertCheck false +DisableCache false +MaxScanTime 120000 +MaxScanSize 100M +MaxFileSize 25M +MaxRecursion 16 +MaxFiles 10000 +MaxPartitions 50 +MaxIconsPE 100 +PCREMatchLimit 10000 +PCRERecMatchLimit 5000 +PCREMaxFileSize 25M +ScanXMLDOCS true +ScanHWP3 true +MaxRecHWP3 16 +StreamMaxLength 25M +LogFile /var/log/clamav.log +LogTime true +LogFileUnlock false +LogFileMaxSize 250M +Bytecode true +BytecodeSecurity TrustSigned +BytecodeTimeout 60000 +OnAccessMaxFileSize 5M \ No newline at end of file diff --git a/roles/deploy-clamd/templates/freshclam-config.j2 b/roles/deploy-clamd/templates/freshclam-config.j2 new file mode 100644 index 0000000..1dc37ee --- /dev/null +++ b/roles/deploy-clamd/templates/freshclam-config.j2 @@ -0,0 +1,38 @@ +DatabaseOwner clamav +UpdateLogFile /var/log/freshclam.log +LogVerbose false +LogSyslog false +LogFacility LOG_LOCAL6 +LogFileMaxSize 0 +LogRotate true +LogTime true +Foreground false +Debug false +MaxAttempts 5 +DatabaseDirectory /var/lib/clamav +DNSDatabaseInfo current.cvd.clamav.net +ConnectTimeout 30 +ReceiveTimeout 0 +TestDatabases yes +ScriptedUpdates yes +CompressLocalDatabase no +Bytecode true +NotifyClamd /etc/clamav/clamd.conf +# Check for new database 24 times a day +Checks 24 +DatabaseMirror db.local.clamav.net +DatabaseMirror database.clamav.net + +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfo.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfo.ign2 +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/javascript.ndb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/spam_marketing.ndb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfohtml.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfoascii.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfoandroid.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfoold.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfopdf.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfo0hour.hdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfo.mdb +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfo.yara +DatabaseCustomURL https://www.securiteinfo.com/get/signatures/a7ef4fbe00e1d0f06492174e93ca2ae8906316d6759eb755c2afd26c5967503d548a5c9502ae78f7903aa618985a55d1284df9b7757128530d523e712bc42ce5/securiteinfo.pdb \ No newline at end of file diff --git a/roles/deploy-clamd/templates/systemd-clamav-service.j2 b/roles/deploy-clamd/templates/systemd-clamav-service.j2 new file mode 100644 index 0000000..f4a25e3 --- /dev/null +++ b/roles/deploy-clamd/templates/systemd-clamav-service.j2 @@ -0,0 +1,21 @@ +[Unit] +Description=ClamAV Daemon (clamd) +Documentation=man:clamd(8) man:clamd.conf(5) https://www.clamav.net/documents/ +After=network.target +ConditionPathExistsGlob=/var/lib/clamav/main.{c[vl]d,inc} +ConditionPathExistsGlob=/var/lib/clamav/daily.{c[vl]d,inc} + +[Service] +User=clamav +Group=clamav +ExecStart=/usr/sbin/clamd --foreground=true --config-file=/etc/clamav/clamd.conf +ExecReload=/bin/kill -USR2 $MAINPID +Restart=on-failure +TimeoutStartSec=420 +ProtectSystem=full +PrivateTmp=true +RuntimeDirectory=clamav +RuntimeDirectoryMode=0755 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/deploy-clamd/templates/systemd-freshclam-service.j2 b/roles/deploy-clamd/templates/systemd-freshclam-service.j2 new file mode 100644 index 0000000..a62d1e5 --- /dev/null +++ b/roles/deploy-clamd/templates/systemd-freshclam-service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=ClamAV Signatur-Updater (freshclam) +Documentation=man:freshclam(1) man:freshclam.conf(5) https://www.clamav.net/documents/ +Wants=network-online.target +After=network-online.target +ConditionPathExists=!/etc/cron.d/clamav-freshclam + +[Service] +User=clamav +Group=clamav +ExecStart=/usr/bin/freshclam -d --foreground=true --config-file /etc/clamav/freshclam.conf +Restart=on-failure +PrivateTmp=true + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/roles/manage-ssh-keys/defaults/main.yml b/roles/manage-ssh-keys/defaults/main.yml index a93f544..85454a6 100644 --- a/roles/manage-ssh-keys/defaults/main.yml +++ b/roles/manage-ssh-keys/defaults/main.yml @@ -5,10 +5,21 @@ authorized_keys_file: >- # Liste der erwünschten (Good) Keys good_keys: - - "ssh-rsa AAAAB3... goodkey1" - - "ssh-rsa AAAAB3... goodkey2" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCKcSu464ffJh6fcrWSajlkdGzyeP1+eStHeiFWjfvTZN1YD/05LsADLv8QwnwDbjIHpi/jO2N9mzN55O2MP4FP33Ztmex5CW1sALHynCX7/LtxmklUxbezoJPp1+evhcEQ670KfCpuWWTgGI2ChANnfb/QlON6UWERjauHoNvO33LnO2ySWxHULDlv7BuJCrmk1ZgH2DI7nGIl2KEdkvtJrUaz/fkjalzdfsD+5bsCVxEXBwF5vOAflYdgLAA9AiiHNrwmoU7ELy+WN7YYA0ikoFAUsaW3R4lzA9Cl9wGQmnF30fMChB3JOHF+fFVLFgftChKlB1A1pddaNMPULPyxNJXBXpZCw0ntLcA3UNtnBl0McVKLdVvQfyeWygqqu9OYtkWWO1KApGxss2KDabKG9C+WRhx6z06lFlPMqZK2bmaZDszd8fKI+jbVRKBq2njZmE/uRfEvHHSXqskBDefdMqIUpRN8cN05vZm+sphIaHfOX1vCy1ZDVTiThFcd/z0= root@ansible-servercow" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsWfznWCcqpgoq4awYDp2W8y62rDT8PEN0xx7818OA1B/mENiBb6jB9qojBpXuSqXKCg7WIVawtl4DSufN4tx2CCNXJPZGcYxkzYrA+bYHMgNUtDF6ps1odFFCu7D1ioVj+hSiM0coFzdgBeT4owg2S8h8kdUmwEbOECp75/3KjV/JUsHrytfJlSTN2mr+SpV3LRL19zFJ67PQXLUyC5oXUR1DZxgzCR2+bWPM7zW0xkVD3c1D+S2JRV4RCZts1Lfgoo/Fl88YMjwk1s3W38Zp/uAgIY6Boan193RWY1yqeCq6u2xAcIiAUqZrVnKesWVnXeRiPuTEESuthK3xSjxd mschild@WS-WIL-MSCHILD" + - "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAiyp00CbVXDS1h+S7SgCNWcgE6PDIxtUmXi/vMbd8Ad6IzVE9gRHeHGkEVZp8YQwMHtlBd4c1+D4T7fHpCVE0kQghXuskp/bvESTO3rD8ZZV2CFU62HD1GwAcXDezd4720bvTqS4BTwZtU/r9/O68+JUIfhF+rC48vP1O04W/W/yKcwmfC1L7JXkLqmmzO0UezIaw2VfB16n4hnkT7NjQrh8q1Egf1+UL8Rzh0Yknmp7tQzF1LGHpVwXiODRVpLtXQ6WUY/v60ucubEER0GxxFs3mu/Re279OErqMmf6vUHtJ1U4SjUUa33DCOO9g7MaZn05cm/2WOlIra2mrQeleaQ== mvogt@NUC6i5MV" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDhWL1f5L8jXm1DSQ8uT0J0LxzYumeYazvGQ3aF+GJabZadzFUbTOU0+6Ce4F/OjpSU2147/HUObdkRQoWoCFir0CdsnaVlYXORMyhd0BssEVleuMaaTkSHtp1VBEjjp3iqduOS3k5uGlCVJeBS4yn9Lp3f4rEAw8YQ0cdWn+m5CmO6WSR7dobYwlqGK7NbQBQ17GEiHbhLMSNfWW62iwivLj0nK35Mz0RmGUJiI+ngPvAr0CPajjwZtyPZeOqHYGk6clIJwsSsb7FSZ/no89cqxP2F5r41+8nsbXgXPB/BiHDd+90ODkuJLOOspqbdxwtufdq5/GezHgt4IEWBhVRd NikolasPapoutsis@NP-E590" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDPiDdYzWGQsitZLNlINovhz6SQPP55XDYWutCC0NglxtIQPtQP/cD7AnT2l8AaA0n99nIukZgAOisjYpz25lLT25TOb5oQ+FMm8vQiZwpiNIbN6JJVE+YnFITASB7fd5Si7dlzl9+2x7Gi80xLQ4zbCGhhJ4qFkafqROoe+yvYEjBHuf3NLqpUbucn9TMNDz9QNfsy4WGvVvYm9bRix9a+JH8gW50cZBrH5AUyiPodlQxmzGPp9zA+zhgqtYPJCAmfxgVphctQPOJhSPrF555XI5YfFM3KRr043I1EaxhZftkVZrVvuHFXscrsYKSCZmnR4dqNlz4giZ59crj/WaWZAfFv5Cb8Ad13eDxwdrktQOfQKOAhppyBNdNAB8Sk2jsGTs311CQwL+nBol8KLVo1vq2CH5S0QULZ/a8ETP12IjvureVILDzfSvPQoH+WaxPvAsZK8DAvZc6AOBOlCdoD0O/WBjC2IIbTSOxVvEAfLSt9Cug7HwlB6efamQPwjFU= Generated by nikla@DESKTOP-IFBGM3B" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCV4VIAiB9znz7eUTYZFxF85bhqh35pWRiFAGnrJwthapmE0yxdCJEq7pfyTIymK3c1GPF9nOCsu9RgZ7Fj7gIA7LspeJa7Il/BrLgSRW1KEHQ11k/XDibE0JTknoEVGguT6MMHh5or/iJYT3sa3uU0UJMDbZdXp66EjcxRWDrQmiyQRPODOwSQQw+ZrC+rDIZHzj99mFx/+SNfCfIG25gsPJsYDHEoTpvd4nrQZvXK7bjh5XNG4/q8hBEoVQC0AQkxTC5NbXC0qeIra4z2TWQL6QGXQRx/cHC7NrOkGjGkvHYP1wQcuOV49bkKzd6oHNKohCbHslDSbaQTuXYaNZ+7i/dCGt631a4e5g2FBQFXogS1pE6LFB0zVtatZlb5YXVhHwkvmEHCTiOSV1bIDZrdLJ7jQmZWjdt+3ShdnHa8d642MieSXklnE1h+RCxTSbIdDQrDHYKXPiyNrap8zkh4KuMP8g07DttA5wdf76YjLUofUrHH0rpOAIf53Z4SGHs= lynn@DESKTOP-U9SRBCB" + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPIPztA01mPBlbvf+AfqRA4/emj5UbYK0Gi15VI5g/CH mail@danilo-schwabe.de" + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINlJlysj2Ff/8lLgNTkNX/uJVz4uIiEtvO/s3qzUMH1j eddsa-key-mv-tinc-20230130" + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICyZYxVyFQlhn/O6XpvnQL9l9bv652pH4jrkiUuNHMsT nm-tinc-eddsa-key-20240805" + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPb3H/K8w22FIpsb+tad+T1PQjrTdry+cM/fmYiLbSDo root@ansible-servercow" # Liste der unerwünschten (Bad) Keys bad_keys: - - "ssh-rsa AAAAB3... badkey1" - - "ssh-rsa AAAAB3... badkey2" \ No newline at end of file + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCx5Gwq39Jaf9YQr0qWzCZMU0l1sPfrJE7vWyrZiQRv2IgVvkIuDl1gv+Gaf1wL69WookC0TGc4Ce2tH5xfcz2tiH72jIDf60izrf2attmPcbLnZfFgN6cPFzCIoMVMIMhROgOF9wF1MzO9WUggJBEpcxotoiPfKkmIrfYXLnnMmZ6XXs3LCcdP1wNOkh/mZ3KfwhH6/GhV/0/mjymzrO5DL/piu+89ZrLmsVU9F/VUZciG7zCv8g6Hhiy25vyOmtGL/DPHfszzlQuvRo0hjTjEdNsnv9b44zc7OtGYdrZ4SPK7v2dSLdzU9eL3+7m6zocaVrbM6YWTph9acwkKOehV root@ccp-wil-backup01" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCcqqrN2lC4lajOmiFuUqHBQ2C07YTl3w5e/FT3+ddZ5YOiONr+e8FvKkiw4he5fvGnt6/RUZgnJW+rI7jlF5qPJjdkdJ3wZNiwp4gTiebNV2hvLx3AL0aoH/5tN9m4KDTYZKfnF1JZAgsZrLNrfYJp8F8+AQk24rAQINQ3Cku0i4cgenOQBrT48/Ibv7erav7ZkUFvIPkh4B4Owzu6MUGzKNFoLypgMRXMmLN2vyaor/q4aA9xeha2CKdbJYhTwgrYMieiAyDw9dbe8rJe0BB7VXxDmX54seLsmSWhs6/6L2JNDAdpV/f4Jb2n2L0GaFlyjGpi64nwfoWng2Meou0J mo@LenovoP340-Tiny" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDEiO4yxkqnbpReZreQnQcUsJKv+QpiC/Edh7GjVJIy7O/dcudtAo82c6Zq8k3QvDZor5nkbOso7ushmOLC15OBkWQXZTcWc1z0z+/6G3UTxaFZ4vr4NF9BJnC4z+bGvLLDzU2rCucD6iPXCow443lWXNmoujMsbNJY+qqxvTNMN1872qX/s7wl1j9NX/mRnzbZI3wrzUgKnmqd4TWCQsQT51in7MLr4Tg6hCz/4NpQSfRCaWfrrIKdIyvjdLyLGyrWwtaYFAwqtLSdmtYngzQsM0tbOHrp5z4AFsggjYaXKyrDMkV1U3jTJwbfh0PbEMfki6clWjhxMuw0IsiuaJGZbJfLiyHG/+dDj7rV8jIYJw/9olDGKr9bXpQ2MlIEzgGEni+1U1ZRZwVueUO0HWtc3pOkZQkJKj3Td5NfrducEFSyY8nSJM5an4sx9dYwu4W4QIyn4vrCTIm/clOfDV0I/FB9NW5oT+r/jBmDkCjLsuAWXQ59ULukqIO9hTKntDk= denni@ws-wil-dennisewert" + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBkW4GNq7TeV3ImF5TOdh7FJVCLBzT5GTTxZPSGZFAkO sandfly-generated-key-20230102225148" + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCISq39qZUj6jCQ3/mb6AJp9FXEBYtXK01yK7xVuCR8JsSAiMFczdgSnbF5ELl0oSkxkCs5AY5yEuZcpbV7/uCWHIQIDo1PTLOoBzLYOcEr/1xcEZFRT79TVG8ILT9fVjrLkPJIQZweriGgjTBMSDk+9BBNlRfW4YOhgo7V9GW2VvchxJtCMNUi5+EWrrQQLO1sf6zCxHPZQ9vmcpWPf5LnbKH72TnteJKK8S84WT0iiVkzsjsaPlPWPlX+CHiog9jJ4hyhLq3MivCyQ9jkRDXnVYafGNFhcBYOLV5+mFcxRbKQJbNOwDHhqwWUqjmwfDkCMRdKNJ0h6o0LMI3apYHlQU+n2ncoks+z7mbN/4RRaSxTYC/OjZa3s4dvtJzDFGor8iOgcD11BbhGVBtwbqwU4Z4GJP453oV+LTIkVZgz8iAblTPgZrDs4Jk9WINjtofpmLnYnatWajdBWB3HdCr24h1lsjSZZkRtJYmHuvfRESRbStb92AnzO1QOjiEAshQHS8jsCumsiGEyqLqnpzjOvAxOFjnxUKRnK8GzoN2/AguRldU0WgYNcvDuCon0os22cLzCG0MYFF+r6TOeNkG9EqhwlkYtqD/YseVtqXR14FD77VxSEezJiMI1YXIXtTduLRyKR2kYw6QEmCJWOW28ZXwmNB9+t7xBA9n0klk8UQ== noah@Noah" \ No newline at end of file diff --git a/roles/managed-mailcow/tasks/install-mailcow-components.yml b/roles/managed-mailcow/tasks/install-mailcow-components.yml new file mode 100644 index 0000000..3a1ad41 --- /dev/null +++ b/roles/managed-mailcow/tasks/install-mailcow-components.yml @@ -0,0 +1,5 @@ +- name: "Install mailcow components" + ansible.builtin.apt: + name: "jq" + state: present + update_cache: yes diff --git a/roles/managed-mailcow/tasks/update-mailcow.yml b/roles/managed-mailcow/tasks/update-mailcow.yml index f74efcc..fb4ccdc 100644 --- a/roles/managed-mailcow/tasks/update-mailcow.yml +++ b/roles/managed-mailcow/tasks/update-mailcow.yml @@ -17,29 +17,6 @@ name: roles/system tasks_from: check-disk-utilization.yaml -- name: Check if redirect.conf exists - ansible.builtin.stat: - path: "{{ mailcow_dir_result.files[0].path }}/data/conf/nginx/redirect.conf" - register: redirect_conf - when: mailcow_conf.stat.exists - -- name: Delete redirect.conf if it exists - ansible.builtin.file: - path: "{{ mailcow_dir_result.files[0].path }}/data/conf/nginx/redirect.conf" - state: absent - when: redirect_conf.stat.exists - - name: Update mailcow - shell: "cd {{ mailcow_dir_result.files[0].path }} && git fetch && git checkout origin/master update.sh && ./update.sh --force" + shell: "cd {{ mailcow_dir_result.files[0].path }} && git fetch && git checkout origin/master update.sh && git checkout origin/master _modules && ./update.sh --force" when: local_mailcow_version.stdout != github_mailcow_ver and mailcow_conf.stat.exists and disk_space_output.stdout | bool - -- name: Update HTTP_REDIRECT in mailcow.conf if redirect.conf existed - ansible.builtin.lineinfile: - path: "{{ mailcow_dir_result.files[0].path }}/mailcow.conf" - regexp: '^HTTP_REDIRECT=' - line: 'HTTP_REDIRECT=y' - when: redirect_conf.stat.exists - -- name: Restart mailcow services - ansible.builtin.shell: "cd {{ mailcow_dir_result.files[0].path }} && docker compose up -d" - when: redirect_conf.stat.exists diff --git a/roles/os-updates/defaults/main.yml b/roles/os-updates/defaults/main.yml index 3336cfe..48662c0 100644 --- a/roles/os-updates/defaults/main.yml +++ b/roles/os-updates/defaults/main.yml @@ -1,9 +1,10 @@ # Standardwerte, die überschrieben werden können os_update_auto_upgrade: true -os_also_update_mirror: false # Can either be true or false | Use this to enable mirror changes. Useful for first runs. +os_also_update_mirror: true # Can either be true or false | Use this to enable mirror changes. Useful for first runs. os_update_mirrors: - # Role needs two mirros to use for the sources.list.j2 Template - - "http://mirror.tinc.gmbh/debian" # Enter a main mirror here (not security) - - "http://mirror.tinc.gmbh/debian-security" # Enter a security mirror here + - mirror: "http://mirror.tinc.gmbh/debian" # Enter a main mirror here (not security) + type: "main" + - mirror: "http://mirror.tinc.gmbh/debian-security" # Enter a security mirror here + type: "security" os_update_major_version: false # Can either be true or false | To toggle if systems need to be upgraded to newer codename -os_update_version_codename: "{{ ansible_distribution_release }}" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on \ No newline at end of file +os_update_version_codename: "bookworm" # Change to switch major release (e.g. bookworm or trixie) | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on \ No newline at end of file diff --git a/roles/os-updates/handlers/main.yml b/roles/os-updates/handlers/main.yml index 8295fe2..1a0d70c 100644 --- a/roles/os-updates/handlers/main.yml +++ b/roles/os-updates/handlers/main.yml @@ -2,10 +2,10 @@ apt: clean: yes autoclean: yes + autoremove: yes - name: Reboot system command: /sbin/reboot async: 1 poll: 0 - ignore_errors: true - when: reboot_required.stdout == "yes" \ No newline at end of file + ignore_errors: true \ No newline at end of file diff --git a/roles/os-updates/tasks/main.yml b/roles/os-updates/tasks/main.yml index a1a5619..868e70c 100644 --- a/roles/os-updates/tasks/main.yml +++ b/roles/os-updates/tasks/main.yml @@ -2,9 +2,5 @@ when: os_also_update_mirror|bool include_tasks: update_mirrors.yaml -- name: Upgrade to new major version if enabled - when: os_update_major_version - include_tasks: update_major_version.yaml - - name: Upgrade all packages include_tasks: upgrade_packages.yaml \ No newline at end of file diff --git a/roles/os-updates/tasks/update_major_version.yaml b/roles/os-updates/tasks/update_major_version.yaml index 0378f21..6376f12 100644 --- a/roles/os-updates/tasks/update_major_version.yaml +++ b/roles/os-updates/tasks/update_major_version.yaml @@ -1,34 +1,125 @@ +- name: Update mirrors if necessary + when: os_also_update_mirror|bool + include_tasks: update_mirrors.yaml + +# tasks/main.yml +- name: Assert target codename provided + ansible.builtin.assert: + that: + - os_update_version_codename is defined + - os_update_version_codename | length > 0 + fail_msg: "Setze die Variable 'os_update_version_codename' (z.B. 'trixie')." + +- name: Set current/target codenames + ansible.builtin.set_fact: + current_codename: "{{ ansible_distribution_release | lower }}" + target_codename: "{{ os_update_version_codename | lower }}" + +- name: Stat /etc/apt/sources.list.d + ansible.builtin.stat: + path: /etc/apt/sources.list.d + register: sources_list_d_dir + +- name: Find *.list files in /etc/apt/sources.list.d + ansible.builtin.find: + paths: /etc/apt/sources.list.d + patterns: "*.list" + file_type: file + register: apt_lists + when: sources_list_d_dir.stat.exists | default(false) + +- name: Stat /etc/apt/sources.list + ansible.builtin.stat: + path: /etc/apt/sources.list + register: sources_list_stat + +- name: Build list of APT *.list paths + ansible.builtin.set_fact: + apt_list_paths: >- + {{ + (vars.get('apt_lists', {}).get('files', []) + | map(attribute='path') | list) + }} + +- name: Build list of APT source files + ansible.builtin.set_fact: + apt_source_files: >- + {{ + apt_list_paths + + ([sources_list_stat.stat.path] if (sources_list_stat.stat.exists | default(false)) else []) + }} + +# ---------- Backups ---------- - name: Backup existing sources in /etc/apt - copy: + ansible.builtin.copy: src: "{{ item }}" dest: "{{ item }}.bak" - remote_src: yes - loop: "{{ lookup('ansible.builtin.fileglob', '/etc/apt/sources.list.d/*.list') + ['/etc/apt/sources.list'] }}" - when: item | file + remote_src: true + force: true + loop: "{{ apt_source_files }}" + loop_control: + label: "{{ item }}" -- name: Update sources.list for new major version - template: +# ---------- Update /etc/apt/sources.list ---------- +- name: Update /etc/apt/sources.list from template + ansible.builtin.template: src: sources.list.j2 dest: /etc/apt/sources.list + owner: root + group: root + mode: "0644" vars: - os_update_version_codename: "{{ new_version_codename }}" # Variable gets passed by main.yml task + target_codename: "{{ target_codename }}" -- name: Update additional repositories in /etc/apt/sources.list.d - lineinfile: +# ---------- Update additional *.list files ---------- +# Ersetzt den Codename (inkl. optionaler Suite-Suffixe wie -security/-updates) in den .d-Dateien +- name: Update codename in /etc/apt/sources.list.d/*.list (keep suffix) + ansible.builtin.replace: path: "{{ item }}" - regexp: '^(deb .* )({{ os_update_version_codename }})' - line: '\1{{ new_version_codename }}' - loop: "{{ lookup('ansible.builtin.fileglob', '/etc/apt/sources.list.d/*.list') }}" - when: item | file + regexp: '(^\s*deb(?:-src)?(?:\s+\[.*?\])?\s+\S+\s+){{ current_codename | regex_escape }}(?P-[a-z]+)?(\s+)' + replace: '\1{{ target_codename }}\g\3' + loop: "{{ apt_list_paths }}" + when: apt_list_paths | length > 0 + loop_control: + label: "{{ item }}" + +# ---- Prevent EXIM (Debian 13 only) --------- +- name: Block installation of Exim with APT Pinning + become: true + ansible.builtin.copy: + dest: /etc/apt/preferences.d/block-exim.pref + owner: root + group: root + mode: '0644' + content: | + Package: exim4* + Pin: release * + Pin-Priority: -1 + +- name: Remove existing Exim packages (purge + autoremove) + become: true + ansible.builtin.apt: + name: + - exim4 + - exim4-base + - exim4-config + - exim4-daemon-light + state: absent + purge: true + autoremove: true + register: exim_purge + +# ---------- Upgrade ---------- - name: Update apt cache - apt: - update_cache: yes + ansible.builtin.apt: + update_cache: true + cache_valid_time: 3600 - name: Perform distribution upgrade - apt: - upgrade: yes - allow_unauthenticated: yes + ansible.builtin.apt: + upgrade: dist # dist-upgrade + allow_unauthenticated: false notify: - Reboot system - apt cleanup \ No newline at end of file diff --git a/roles/os-updates/tasks/upgrade_packages.yaml b/roles/os-updates/tasks/upgrade_packages.yaml index 9fc6f38..8d8bb7d 100644 --- a/roles/os-updates/tasks/upgrade_packages.yaml +++ b/roles/os-updates/tasks/upgrade_packages.yaml @@ -11,12 +11,11 @@ register: latest_kernel changed_when: false -- name: Check if running kernel matches the latest installed kernel +- name: Check if running kernel matches the latest installed kernel and determine if reboot is required shell: uname -r register: running_kernel changed_when: false - -- name: Determine if reboot is required - set_fact: - reboot_required: "yes" + failed_when: false + notify: + - Reboot system when: running_kernel.stdout != latest_kernel.stdout diff --git a/roles/os-updates/templates/sources.list.j2 b/roles/os-updates/templates/sources.list.j2 index eda8338..3ec8cf2 100644 --- a/roles/os-updates/templates/sources.list.j2 +++ b/roles/os-updates/templates/sources.list.j2 @@ -1,5 +1,10 @@ # {{ ansible_managed }} -deb {{ os_update_mirrors[0] }} {{ os_update_version_codename }} main contrib non-free non-free-firmware -deb {{ os_update_mirrors[0] }} {{ os_update_version_codename }}-updates main contrib non-free non-free-firmware -deb {{ os_update_mirrors[0] }} {{ os_update_version_codename }}-backports main contrib non-free non-free-firmware -deb {{ os_update_mirrors[1] }} {{ os_update_version_codename }}-security main contrib non-free non-free-firmware \ No newline at end of file +{% for mirror in os_update_mirrors %} +{% if mirror.type == "main" %} +deb {{ mirror.mirror }} {{ os_update_version_codename }} main contrib non-free non-free-firmware +deb {{ mirror.mirror }} {{ os_update_version_codename }}-updates main contrib non-free non-free-firmware +deb {{ mirror.mirror }} {{ os_update_version_codename }}-backports main contrib non-free non-free-firmware +{% elif mirror.type == "security" %} +deb {{ mirror.mirror }} {{ os_update_version_codename }}-security main contrib non-free non-free-firmware +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/roles/system/defaults/main.yml b/roles/system/defaults/main.yml new file mode 100644 index 0000000..a2c3957 --- /dev/null +++ b/roles/system/defaults/main.yml @@ -0,0 +1,3 @@ +use_docker_image_mirror: true +docker_mirror_location: "SC" # or "tinc" based on your preference +docker_install_source: "official" \ No newline at end of file diff --git a/roles/system/files/motd b/roles/system/files/motd new file mode 100644 index 0000000..f8b3ec2 --- /dev/null +++ b/roles/system/files/motd @@ -0,0 +1,15 @@ + _ _ _ _ + | |_(_)_ __ ___ (_) ___ _ __ _ __ _ __ ___ __| | + | __| | '_ \ / __| _____ | |/ __| '_ \ _____ | '_ \| '__/ _ \ / _` | + | |_| | | | | (__ |_____| | | (__| |_) | |_____| | |_) | | | (_) | (_| | + \__|_|_| |_|\___| |_|\___| .__/ | .__/|_| \___/ \__,_| + |_| |_| + ----------------------------------------------------------------- + * This server is managed by tinc. Please contact the * + * support team at 'support@tinc.gmbh' for any issues. * + ----------------------------------------------------------------- + * WARNING - WARNING - WARNING - WARNING - WARNING - WARNING * + * You are accessing a secured system and your actions will * + * be logged along with identifying information. Disconnect * + * immediately if you are not an authorized user of this system. * + ----------------------------------------------------------------- \ No newline at end of file diff --git a/roles/system/handlers/main.yml b/roles/system/handlers/main.yml new file mode 100644 index 0000000..67f4b9d --- /dev/null +++ b/roles/system/handlers/main.yml @@ -0,0 +1,28 @@ +- name: Reload systemd + ansible.builtin.systemd: + daemon_reload: true + +- name: Restart SSH + systemd_service: + name: sshd + state: restarted + +- name: Restart Docker + systemd_service: + name: docker + state: restarted + +- name: Restart chronyd + ansible.builtin.systemd: + name: chronyd + state: restarted + +- name: Enable Docker + systemd_service: + name: docker + enabled: true + +- name: Start Docker + systemd_service: + name: docker + state: started \ No newline at end of file diff --git a/roles/system/tasks/install-basic-tools.yaml b/roles/system/tasks/install-basic-tools.yaml new file mode 100644 index 0000000..6b2e31b --- /dev/null +++ b/roles/system/tasks/install-basic-tools.yaml @@ -0,0 +1,16 @@ +- name: Install basic system tools + ansible.builtin.package: + name: + - git + - curl + - wget + - vim + - htop + - net-tools + - unzip + - htop + - tcpdump + - bind9-dnsutils + - gnupg + - sudo + state: present \ No newline at end of file diff --git a/roles/system/tasks/install-docker-image-mirror.yaml b/roles/system/tasks/install-docker-image-mirror.yaml new file mode 100644 index 0000000..dc38662 --- /dev/null +++ b/roles/system/tasks/install-docker-image-mirror.yaml @@ -0,0 +1,64 @@ +- name: Create directory for Docker systemd override + ansible.builtin.file: + path: /etc/systemd/system/docker.service.d + state: directory + mode: '0755' + +- name: Setup Docker image mirror (SC) + when: use_docker_image_mirror | bool and docker_mirror_location == "SC" + block: + - name: Install CA certificate for Docker image mirror + ansible.builtin.get_url: + url: http://dim.servercow.com:3128/ca.crt + dest: /usr/local/share/ca-certificates/SCOW-DIM-CA.crt + mode: '0644' + register: sc_ca_cert + + - name: Register CA certificate + ansible.builtin.command: update-ca-certificates + when: sc_ca_cert.changed + + - name: Write Docker proxy configuration (SC) + ansible.builtin.copy: + dest: /etc/systemd/system/docker.service.d/http-proxy.conf + content: | + [Service] + Environment="HTTP_PROXY=http://dim.servercow.com:3128/" + Environment="HTTPS_PROXY=http://dim.servercow.com:3128/" + owner: root + group: root + mode: '0644' + notify: + - Reload systemd + - Restart Docker + when: sc_ca_cert.changed + +- name: Setup Docker Image Mirror (tinc) + when: use_docker_image_mirror | bool and docker_mirror_location == "tinc" + block: + - name: Install CA certificate for Docker image mirror + ansible.builtin.get_url: + url: http://mirror.tinc.gmbh:3128/ca.crt + dest: /usr/local/share/ca-certificates/TINC-DIM-CA.crt + mode: '0644' + register: tinc_ca_cert + + - name: Register CA certificate + ansible.builtin.command: update-ca-certificates + when: tinc_ca_cert.changed + + + - name: Write Docker proxy configuration (tinc) + ansible.builtin.copy: + dest: /etc/systemd/system/docker.service.d/http-proxy.conf + content: | + [Service] + Environment="HTTP_PROXY=http://mirror.tinc.gmbh:3128/" + Environment="HTTPS_PROXY=http://mirror.tinc.gmbh:3128/" + owner: root + group: root + mode: '0644' + notify: + - Reload systemd + - Restart Docker + when: tinc_ca_cert.changed \ No newline at end of file diff --git a/roles/system/tasks/install-docker.yaml b/roles/system/tasks/install-docker.yaml new file mode 100644 index 0000000..7fe0952 --- /dev/null +++ b/roles/system/tasks/install-docker.yaml @@ -0,0 +1,76 @@ +- name: Install Docker from official repo + when: docker_install_source == "official" + block: + - name: Ensure Docker GPG key is dearmored and installed + ansible.builtin.get_url: + url: https://download.docker.com/linux/debian/gpg + dest: /tmp/docker.gpg + mode: '0644' + + - name: Convert Docker GPG key to binary format (dearmor) + ansible.builtin.command: + cmd: gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg /tmp/docker.gpg + args: + creates: /etc/apt/trusted.gpg.d/docker.gpg + + - name: Remove temporary Docker GPG key + ansible.builtin.file: + path: /tmp/docker.gpg + state: absent + + - name: Add Docker APT repository (official) + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/docker.list + content: | + deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable + mode: '0644' + register: docker_repo + +- name: Install Docker from tinc mirror + when: docker_install_source == "tinc" + block: + + - name: Ensure Docker GPG key is dearmored and installed + ansible.builtin.get_url: + url: https://mirror.tinc.gmbh/docker/debian/gpg + dest: /tmp/docker.gpg + mode: '0644' + + - name: Convert Docker GPG key to binary format (dearmor) + ansible.builtin.command: + cmd: gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg /tmp/docker.gpg + args: + creates: /etc/apt/trusted.gpg.d/docker.gpg + + - name: Remove temporary Docker GPG key + ansible.builtin.file: + path: /tmp/docker.gpg + state: absent + + - name: Add Docker APT repository (tinc) + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/docker.list + content: | + deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://mirror.tinc.gmbh/docker/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable + mode: '0644' + register: docker_repo + +- name: Update APT cache + ansible.builtin.apt: + update_cache: yes + when: docker_repo.changed + +- name: Install Docker packages from mirror + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-compose-plugin + - docker-buildx-plugin + - docker-ce-rootless-extras + state: present + notify: + - Enable Docker + - Start Docker + when: docker_repo.changed \ No newline at end of file diff --git a/roles/system/tasks/install-motd.yaml b/roles/system/tasks/install-motd.yaml new file mode 100644 index 0000000..e68e605 --- /dev/null +++ b/roles/system/tasks/install-motd.yaml @@ -0,0 +1,7 @@ +- name: Install custom MOTD + copy: + src: motd + dest: /etc/motd + owner: root + group: root + mode: '0644' \ No newline at end of file diff --git a/roles/system/tasks/setup-timeserver.yaml b/roles/system/tasks/setup-timeserver.yaml new file mode 100644 index 0000000..db49a14 --- /dev/null +++ b/roles/system/tasks/setup-timeserver.yaml @@ -0,0 +1,26 @@ +- name: Purge systemd-timesyncd + ansible.builtin.apt: + name: systemd-timesyncd + state: absent + purge: true + +- name: Setup Chrony + ansible.builtin.apt: + name: chrony + state: present + update_cache: yes + +- name: Configure Chrony + ansible.builtin.copy: + dest: /etc/chrony/chrony.conf + content: | + server ntp.as208016.net iburst + pool de.pool.ntp.org iburst + driftfile /var/lib/chrony/drift + makestep 1.0 3 + rtcsync + owner: root + group: root + mode: '0644' + notify: + - Restart chronyd \ No newline at end of file diff --git a/roles/system/tasks/special-admin-create.yaml b/roles/system/tasks/special-admin-create.yaml new file mode 100644 index 0000000..d45c8c9 --- /dev/null +++ b/roles/system/tasks/special-admin-create.yaml @@ -0,0 +1,52 @@ +--- + - name: User "{{ admin_user }}" anlegen + ansible.builtin.user: + name: "{{ admin_user }}" + shell: /bin/bash + state: present + register: admin_user_result + + - name: .ssh‑Verzeichnis anlegen + ansible.builtin.file: + path: "/home/{{ admin_user }}/.ssh" + state: directory + owner: "{{ admin_user }}" + group: "{{ admin_user }}" + mode: "0700" + when: admin_user_result.changed + + - name: Public‑Keys von URL holen + ansible.builtin.uri: + url: "{{ admin_ssh_pub_key_url }}" + return_content: yes + delegate_to: localhost + register: fetched_keys + + - name: Liste der einzelnen Keys erstellen + ansible.builtin.set_fact: + key_list: "{{ fetched_keys.content.splitlines() }}" + + - name: authorized_keys anlegen (falls nicht vorhanden) + ansible.builtin.file: + path: "/home/{{ admin_user }}/.ssh/authorized_keys" + state: touch + owner: "{{ admin_user }}" + group: "{{ admin_user }}" + mode: "0600" + + - name: Jeden Key einzeln mit authorized_key hinzufügen + ansible.builtin.authorized_key: + user: "{{ admin_user }}" + key: "{{ item | trim }}" + state: present + loop: "{{ key_list }}" + when: item | trim != "" + + - name: Passwordless‑sudo für alle Befehle konfigurieren + ansible.builtin.copy: + dest: "/etc/sudoers.d/{{ admin_user }}" + content: | + {{ admin_user }} ALL=(ALL) NOPASSWD: ALL + owner: root + group: root + mode: "0440" \ No newline at end of file diff --git a/roles/system/tasks/ssh-hardening.yaml b/roles/system/tasks/ssh-hardening.yaml new file mode 100644 index 0000000..582771c --- /dev/null +++ b/roles/system/tasks/ssh-hardening.yaml @@ -0,0 +1,36 @@ +- name: Public‑Keys von URL holen + ansible.builtin.uri: + url: "{{ ssh_pub_key_url }}" + return_content: yes + delegate_to: localhost + register: fetched_keys + +- name: Liste der einzelnen Keys erstellen + ansible.builtin.set_fact: + key_list: "{{ fetched_keys.content.splitlines() }}" + +- name: authorized_keys anlegen (falls nicht vorhanden) + ansible.builtin.file: + path: "/root/.ssh/authorized_keys" + state: touch + owner: "root" + group: "root" + mode: "0600" + +- name: Jeden Key einzeln mit authorized_key hinzufügen + ansible.builtin.authorized_key: + user: "root" + key: "{{ item | trim }}" + state: present + loop: "{{ key_list }}" + when: item | trim != "" + +- name: Harden SSH configuration + ansible.builtin.template: + src: sshd_config.j2 + dest: /etc/ssh/sshd_config + owner: root + group: root + mode: '0644' + notify: + - Restart SSH \ No newline at end of file diff --git a/roles/system/templates/sshd_config.j2 b/roles/system/templates/sshd_config.j2 new file mode 100644 index 0000000..95c6091 --- /dev/null +++ b/roles/system/templates/sshd_config.j2 @@ -0,0 +1,44 @@ +Include /etc/ssh/sshd_config.d/*.conf + +Port 22 +AddressFamily any +ListenAddress 0.0.0.0 +ListenAddress :: + +SyslogFacility AUTH +LogLevel INFO + +# Authentication: +LoginGraceTime 2m +PermitRootLogin without-password +MaxAuthTries 6 + +PubkeyAuthentication yes + +# To disable tunneled clear text passwords, change to no here! +PasswordAuthentication no +PermitEmptyPasswords no + +# Change to yes to enable challenge-response passwords (beware issues with +# some PAM modules and threads) +KbdInteractiveAuthentication no + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the KbdInteractiveAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via KbdInteractiveAuthentication may bypass +# the setting of "PermitRootLogin prohibit-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and KbdInteractiveAuthentication to 'no'. +UsePAM yes + +X11Forwarding yes +PrintMotd no + +# Allow client to pass locale environment variables +AcceptEnv LANG LC_* + +# override default of no subsystems +Subsystem sftp /usr/lib/openssh/sftp-server \ No newline at end of file diff --git a/vault.yml b/vault.yml new file mode 100644 index 0000000..018a9ff --- /dev/null +++ b/vault.yml @@ -0,0 +1,12 @@ +$ANSIBLE_VAULT;1.1;AES256 +32313665396633336165656332313162356665623066313165393464666138623230333666313135 +3833623133643564323530336531363531623139376636350a653037623861383664623432333961 +39633864343631376562343839386637386634333264623231636333663230366134323061356639 +6336663761396632660a623433356566373534373266366335393463666562343035393138346663 +63396664303837323336396334643663653734666438666364643139386166633938663739303330 +39373230616662383263626136663839396662356636663938666135643063363065636133316235 +64393962396534393264613534633136353635313564303435313334646533306161346562353566 +66383239343932393130626563613437336666623765616439613963306438663665366464326632 +37326438386539633930616331303933666537643337303437313234626563363562326361373039 +31616661343633303663326165306232306639653035323963363733653538363232333832303833 +363165663966363066623762343766393130