From e0b0f33c0341fa545b7f60eecd8501c0dc9ef6e1 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 26 May 2026 13:36:06 +0200 Subject: [PATCH 1/8] Removed ppm-specific stuff Converting this repository to an ansible collection so we can re-use the roles everywhere --- README.md | 7 ------- all.yml | 5 ----- ansible.cfg | 9 --------- group_vars/all/applications.yml | 33 --------------------------------- group_vars/all/firewall.yml | 7 ------- group_vars/all/ppm.yml | 1 - group_vars/all/rootuser.yml | 3 --- group_vars/all/zabbix.yml | 2 -- inventory | 3 --- run | 3 --- 10 files changed, 73 deletions(-) delete mode 100644 README.md delete mode 100644 all.yml delete mode 100644 ansible.cfg delete mode 100644 group_vars/all/applications.yml delete mode 100644 group_vars/all/firewall.yml delete mode 100644 group_vars/all/ppm.yml delete mode 100644 group_vars/all/rootuser.yml delete mode 100644 group_vars/all/zabbix.yml delete mode 100644 inventory delete mode 100755 run diff --git a/README.md b/README.md deleted file mode 100644 index 00877d8..0000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -This is how I set up ppm.pfoe.be - -This repository is currently created to serve -as an inspiration for creating your own ansible playbook to set up ppm - -At this moment it is not intended to be used as is/it is a work in progress - diff --git a/all.yml b/all.yml deleted file mode 100644 index 1519f04..0000000 --- a/all.yml +++ /dev/null @@ -1,5 +0,0 @@ -- name: Perform ppm server ansible playbook - hosts: all - roles: - - baseline - - ppm diff --git a/ansible.cfg b/ansible.cfg deleted file mode 100644 index 21d28df..0000000 --- a/ansible.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[defaults] -inventory=inventory -retry_files_enabled = False -remote_user = root -deperaction_warnings = True -display_skipped_hosts = True - -result_format=yaml - diff --git a/group_vars/all/applications.yml b/group_vars/all/applications.yml deleted file mode 100644 index 3df2f28..0000000 --- a/group_vars/all/applications.yml +++ /dev/null @@ -1,33 +0,0 @@ -ppm_apps: - - on_server: ppm.pfoe.be - user: git - chicken_egg_appdefinition: ../forgejo/ - appconfig: - restic: - url: "{{ lookup('file', 'passwords/ppm-forgejo-url') }}" - password: "{{ lookup('file', 'passwords/ppm-forgejo-password') }}" - backupname: "{{ lookup('file', 'passwords/ppm-forgejo-name') }}" - appinfo: - url: https://ppm.pfoe.be/ppm/forgejo.git - config: - publicurl: ppm.pfoe.be - - - on_server: ppm.pfoe.be - user: nginx - chicken_egg_appdefinition: ../nginx/ - appconfig: - appinfo: - url: https://ppm.pfoe.be/ppm/nginx.git - code: - type: localfiles - directory: nginx - - - on_server: ppm.pfoe.be - user: runner - chicken_egg_appdefinition: ../forgejo-runner/ - appconfig: - appinfo: - url: https://ppm.pfoe.be/ppm/forgejo-runner.git - code: - type: localfiles - directory: forgejo-runner diff --git a/group_vars/all/firewall.yml b/group_vars/all/firewall.yml deleted file mode 100644 index b2a76b1..0000000 --- a/group_vars/all/firewall.yml +++ /dev/null @@ -1,7 +0,0 @@ -# I prefer not to share the list of admins in a public repo, so refer to passwords... -# The format for the ssh ranges is as follows: -# - name: The name that is in a comment in the generated file. Not used anywhere else -# type: ipv4 # or ipv6 -# range: 10.10.10.10/32 # The range, MUST be a valid range, not an ip address, ie there must be a / and the netmask - -firewall_ssh_ranges: "{{ lookup('file', 'passwords/firewall_ssh_ranges.yml') | from_yaml }}" diff --git a/group_vars/all/ppm.yml b/group_vars/all/ppm.yml deleted file mode 100644 index b540407..0000000 --- a/group_vars/all/ppm.yml +++ /dev/null @@ -1 +0,0 @@ -ppm_binary: "{{ lookup('pipe', 'pwd') }}/../ppm/out/ppm" diff --git a/group_vars/all/rootuser.yml b/group_vars/all/rootuser.yml deleted file mode 100644 index 5fa38f4..0000000 --- a/group_vars/all/rootuser.yml +++ /dev/null @@ -1,3 +0,0 @@ -root_password: "{{ lookup('file', 'passwords/root_password_hashed') }}" -# ssh keys are public, but I prefer not to share the list of admins in a public repo -root_sshkeys: "{{ lookup('file', 'passwords/root_sshkeys.yml') | from_yaml }}" diff --git a/group_vars/all/zabbix.yml b/group_vars/all/zabbix.yml deleted file mode 100644 index b61ffa4..0000000 --- a/group_vars/all/zabbix.yml +++ /dev/null @@ -1,2 +0,0 @@ -zabbix_server: "{{ lookup('file', 'passwords/zabbix_server') }}" -zabbix_psk: "{{ lookup('file', 'passwords/zabbix_psk') }}" diff --git a/inventory b/inventory deleted file mode 100644 index 9af821e..0000000 --- a/inventory +++ /dev/null @@ -1,3 +0,0 @@ -[ppmserver] -ppm.pfoe.be - diff --git a/run b/run deleted file mode 100755 index e26716e..0000000 --- a/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -ansible-playbook --diff all.yml "$@" From be2b2a7ca73f5902bb1b18dc447f5e23ed260808 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 26 May 2026 14:34:23 +0200 Subject: [PATCH 2/8] added extra handy packages --- roles/baseline/tasks/packages.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/baseline/tasks/packages.yml b/roles/baseline/tasks/packages.yml index 88dfd11..198a101 100644 --- a/roles/baseline/tasks/packages.yml +++ b/roles/baseline/tasks/packages.yml @@ -19,6 +19,7 @@ ansible.builtin.apt: pkg: - apt-dater + - man - mosh - mc - vim @@ -36,6 +37,9 @@ - iftop - htop - ncdu + - acl + - sudo + - ntpsec-ntpdate - name: Firewall for mosh ansible.builtin.template: From 13d2513d872d8d1042de715f48f7d5a496d93f82 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 26 May 2026 14:34:48 +0200 Subject: [PATCH 3/8] use correct permissions for templatefiles --- roles/ppm/tasks/firewall.yml | 2 +- roles/ppm/tasks/zabbix.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/ppm/tasks/firewall.yml b/roles/ppm/tasks/firewall.yml index 2b58d7b..b4a1419 100644 --- a/roles/ppm/tasks/firewall.yml +++ b/roles/ppm/tasks/firewall.yml @@ -3,7 +3,7 @@ dest: /home/.ppmfirewalltemplate group: root owner: root - mode: "0755" + mode: "0644" src: ppmfirewall - name: Render firewall diff --git a/roles/ppm/tasks/zabbix.yml b/roles/ppm/tasks/zabbix.yml index ad254bd..f2030ee 100644 --- a/roles/ppm/tasks/zabbix.yml +++ b/roles/ppm/tasks/zabbix.yml @@ -3,7 +3,7 @@ dest: /home/.zabbixagenttemplate group: root owner: root - mode: "0755" + mode: "0644" src: ppmzabbixagent - name: Render zabbix template From 1bd7ae2913b108a8929f1f66bec6f4e869d1dcdf Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 30 May 2026 19:28:55 +0200 Subject: [PATCH 4/8] typofix --- roles/baseline/tasks/packages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/baseline/tasks/packages.yml b/roles/baseline/tasks/packages.yml index 198a101..5d2cb57 100644 --- a/roles/baseline/tasks/packages.yml +++ b/roles/baseline/tasks/packages.yml @@ -5,7 +5,7 @@ # Even if we "changed it", it's merely a cache, so ignore changed_when: false -- name: Update system packages to lates +- name: Update system packages to latest ansible.builtin.apt: upgrade: dist From 0cdef8be5b91e3a6ea437554f03b8fb1379bfee8 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 30 May 2026 19:29:39 +0200 Subject: [PATCH 5/8] only set root pass/ssh keys if vars are set --- roles/baseline/tasks/rootuser.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/baseline/tasks/rootuser.yml b/roles/baseline/tasks/rootuser.yml index 854a42c..5bd0ee3 100644 --- a/roles/baseline/tasks/rootuser.yml +++ b/roles/baseline/tasks/rootuser.yml @@ -2,6 +2,7 @@ ansible.builtin.user: name: root password: "{{ root_password }}" + when: root_password is defined - name: Ensure ssh directory for root ansible.builtin.file: @@ -10,6 +11,7 @@ owner: root group: root mode: "0700" + when: root_sshkeys is defined - name: Set authorized keys for root ansible.builtin.copy: @@ -18,6 +20,7 @@ owner: root group: root mode: "0600" + when: root_sshkeys is defined - name: Only allow root ssh ansible.builtin.lineinfile: @@ -25,3 +28,4 @@ line: "PermitRootLogin prohibit-password" regexp: "^PermitRootLogin " notify: Restart sshd + when: root_sshkeys is defined From dccb45168c24f785413ac7fcc84fae21d5402460 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 30 May 2026 19:29:58 +0200 Subject: [PATCH 6/8] firewall: restart failtoban if it exists --- roles/baseline/templates/firewall.j2 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/roles/baseline/templates/firewall.j2 b/roles/baseline/templates/firewall.j2 index 039cc3f..22110ff 100644 --- a/roles/baseline/templates/firewall.j2 +++ b/roles/baseline/templates/firewall.j2 @@ -75,4 +75,11 @@ ip6tables -A INPUT -j REJECT iptables -A FORWARD -j REJECT ip6tables -A FORWARD -j REJECT +# Now *if* fail2ban has been installed, we would have destroyed it's setup. +# Restart it +if [ -e /etc/fail2ban/fail2ban.conf ] +then + systemctl restart fail2ban || true +fi + # This file is managed by ansible, do not modify! From 03d9493e7afbeb7fd892413a7e6ab4a034336b38 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 30 May 2026 19:30:12 +0200 Subject: [PATCH 7/8] support closed ssh range --- roles/baseline/templates/firewall.j2 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/roles/baseline/templates/firewall.j2 b/roles/baseline/templates/firewall.j2 index 22110ff..a224308 100644 --- a/roles/baseline/templates/firewall.j2 +++ b/roles/baseline/templates/firewall.j2 @@ -20,11 +20,16 @@ iptables -A INPUT -m limit --limit 1/s --limit-burst 2 -p icmp --icmp-type echo- iptables -A INPUT -p icmp --icmp-type echo-request -j DROP iptables -A INPUT -p icmp -j ACCEPT +{% if firewall_ssh_ranges is defined %} {% for range in firewall_ssh_ranges %} {%if range.type=="ipv4" %} iptables -A INPUT -p tcp --dport 22 -s {{range.range}} -j ACCEPT # {{range.name}} {%endif%} {%endfor%} +{% else %} +# This server has an open ssh policy +iptables -A INPUT -p tcp --dport 22 -j ACCEPT +{% endif %} iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A OUTPUT -m state --state INVALID -j DROP @@ -48,11 +53,16 @@ ip6tables -A INPUT -m limit --limit 1/s --limit-burst 2 -p icmpv6 --icmpv6-type ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j DROP ip6tables -A INPUT -p icmpv6 -j ACCEPT +{% if firewall_ssh_ranges is defined %} {% for range in firewall_ssh_ranges %} {%if range.type=="ipv6" %} ip6tables -A INPUT -p tcp --dport 22 -s {{range.range}} -j ACCEPT # {{range.name}} {%endif%} {%endfor%} +{% else %} +# This server has an open ssh policy +ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT +{% endif %} ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT ip6tables -A OUTPUT -m state --state INVALID -j DROP From c36f52e4205fe5f8e3e4475c802126670065ba73 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 30 May 2026 19:30:32 +0200 Subject: [PATCH 8/8] support updating the app if the source is updated --- roles/ppm/tasks/copyappdef.yml | 5 +++ roles/ppm/tasks/oneapp.yml | 4 +++ roles/ppm/tasks/updateappdef.yml | 58 ++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 roles/ppm/tasks/updateappdef.yml diff --git a/roles/ppm/tasks/copyappdef.yml b/roles/ppm/tasks/copyappdef.yml index 695f5ab..d851ed5 100644 --- a/roles/ppm/tasks/copyappdef.yml +++ b/roles/ppm/tasks/copyappdef.yml @@ -20,6 +20,11 @@ delegate_to: localhost become: false +- name: delete appdefinition directory + ansible.builtin.file: + path: "{{ ppm_app_user.home }}/appdefinition" + state: absent + - name: Create directory ansible.builtin.file: path: "{{ ppm_app_user.home }}/appdefinition" diff --git a/roles/ppm/tasks/oneapp.yml b/roles/ppm/tasks/oneapp.yml index ccfa54c..e148794 100644 --- a/roles/ppm/tasks/oneapp.yml +++ b/roles/ppm/tasks/oneapp.yml @@ -53,6 +53,10 @@ ansible.builtin.include_tasks: copyappdef.yml when: ppm_app.chicken_egg_appdefinition is defined and not appdefinition.stat.exists +- name: "Update appdefinition ({{ ppm_app.user }})" + ansible.builtin.include_tasks: updateappdef.yml + when: ppm_app.chicken_egg_appdefinition is defined + - name: "Set up extra files for {{ ppm_app.user }}" ansible.builtin.copy: src: "{{ item.from }}" diff --git a/roles/ppm/tasks/updateappdef.yml b/roles/ppm/tasks/updateappdef.yml new file mode 100644 index 0000000..5e88330 --- /dev/null +++ b/roles/ppm/tasks/updateappdef.yml @@ -0,0 +1,58 @@ +- name: Check local working tree for uncommitted changes + command: git status --porcelain + args: + chdir: "{{ ppm_app.chicken_egg_appdefinition }}" + register: local_status + changed_when: false + delegate_to: localhost + +- name: Get local HEAD hash + command: git rev-parse HEAD + args: + chdir: "{{ ppm_app.chicken_egg_appdefinition }}" + register: local_hash + changed_when: false + delegate_to: localhost + + +- name: Check remote working tree for uncommitted changes + command: git status --porcelain + args: + chdir: "{{ ppm_app_user.home }}/appdefinition" + register: remote_status + changed_when: false + become: true + become_user: "{{ ppm_app_user.name }}" + +- name: Get remote HEAD hash + command: git rev-parse HEAD + args: + chdir: "{{ ppm_app_user.home }}/appdefinition" + register: remote_hash + changed_when: false + become: true + become_user: "{{ ppm_app_user.name }}" + + +- name: Set helper facts + set_fact: + local_dirty: "{{ (local_status.stdout | default('')) != '' }}" + local_hash: "{{ local_hash.stdout }}" + remote_dirty: "{{ (remote_status.stdout | default('')) != '' }}" + remote_hash: "{{ remote_hash.stdout }}" + +- name: Debug when remote is dirty (ignore remote dirty for sync decision) + debug: + msg: "Remote repository has uncommitted changes; ignoring for sync." + changed_when: true + when: remote_dirty + +- name: Debug when local is dirty + debug: + msg: "Local repository has uncommitted changes; unconditional - non-idempotent sync." + changed_when: true + when: local_dirty and not remote_dirty + +- name: Include copyappdef.yml when local dirty, hash retrieval failed, or hashes differ + include_tasks: copyappdef.yml + when: not remote_dirty and (local_hash!=remote_hash or local_dirty)