From fef5c737269dcb340d7fbff3b1216f033eb1dd56 Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Sun, 18 May 2025 15:50:18 +0200 Subject: [PATCH] feat(fwknopd): add Ansible role for fwknopd management with necessary tasks and configurations --- .../workflows/ansible-apply-hosts-changes.yml | 53 ------- .github/workflows/ansible-apply-playbook.yml | 45 ------ .github/workflows/terraform-k8sapps-apply.yml | 2 - ansible/host_vars/prod-01.alexpires.me.yml | 1 + ansible/roles/README.md | 134 ++++++++++++++++++ .../roles/cis/molecule/default/molecule.yml | 2 +- ansible/roles/fwknopd/defaults/main.yml | 3 + ansible/roles/fwknopd/meta/main.yml | 39 +++++ .../fwknopd/molecule/default/converge.yml | 8 ++ .../fwknopd/molecule/default/molecule.yml | 23 +++ .../fwknopd/molecule/default/prepare.yml | 30 ++++ ansible/roles/fwknopd/tasks/main.yml | 25 ++++ .../roles/fwknopd/templates/access.conf.j2 | 6 + 13 files changed, 270 insertions(+), 101 deletions(-) delete mode 100644 .github/workflows/ansible-apply-hosts-changes.yml delete mode 100644 .github/workflows/ansible-apply-playbook.yml create mode 100644 ansible/roles/README.md create mode 100644 ansible/roles/fwknopd/defaults/main.yml create mode 100644 ansible/roles/fwknopd/meta/main.yml create mode 100644 ansible/roles/fwknopd/molecule/default/converge.yml create mode 100644 ansible/roles/fwknopd/molecule/default/molecule.yml create mode 100644 ansible/roles/fwknopd/molecule/default/prepare.yml create mode 100644 ansible/roles/fwknopd/tasks/main.yml create mode 100644 ansible/roles/fwknopd/templates/access.conf.j2 diff --git a/.github/workflows/ansible-apply-hosts-changes.yml b/.github/workflows/ansible-apply-hosts-changes.yml deleted file mode 100644 index 191e64d..0000000 --- a/.github/workflows/ansible-apply-hosts-changes.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Ansible Apply because of host_vars change -on: - push: - branches: - - main - paths: - - ansible/host_vars/*.alexpires.me.yml - - ansible/host_vars/*.a13labs.me.yml - - ansible/host_vars/*.a13labs.pt.yml -jobs: - ansible-apply: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup environment - id: setup_env - uses: ./.github/actions/setup-env - - - name: Setup Ansible environment - uses: ./.github/actions/setup-ansible-env - with: - project-id: ${{ secrets.BW_PROJECT_ID }} - organization-id: ${{ secrets.BW_ORGANIZATION_ID }} - access-token: ${{ secrets.BW_ACCESS_TOKEN }} - ansible-user: ${{ secrets.ANSIBLE_USER }} - trusted-hosts: ${{ secrets.TRUSTED_HOSTS }} - - - name: Apply the playbook that triggered the workflow - env: - BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} - BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} - BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} - ANSIBLE_USER: ${{ secrets.ANSIBLE_USER }} - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - CHANGED_FILES: ${{ steps.setup_env.outputs.CHANGED_FILES }} - run: | - cd ansible - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_fail2ban.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_geoip.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_duo_security.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_encryption.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_microk8s.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_gitea.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_nextcloud.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_websites.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_m3uproxy.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_monitoring.yml - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_rustdesk.yml diff --git a/.github/workflows/ansible-apply-playbook.yml b/.github/workflows/ansible-apply-playbook.yml deleted file mode 100644 index 6bddc0b..0000000 --- a/.github/workflows/ansible-apply-playbook.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Ansible Apply Playbook that Triggered the Workflow -on: - push: - branches: - - main - paths: - - ansible/playbook_*.yml - - '!ansible/playbook_websites.yml' - - '!ansible/playbook_hardening*.yml' -jobs: - ansible-apply: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup environment - id: setup_env - uses: ./.github/actions/setup-env - - - name: Setup Ansible environment - uses: ./.github/actions/setup-ansible-env - with: - project-id: ${{ secrets.BW_PROJECT_ID }} - organization-id: ${{ secrets.BW_ORGANIZATION_ID }} - access-token: ${{ secrets.BW_ACCESS_TOKEN }} - ansible-user: ${{ secrets.ANSIBLE_USER }} - trusted-hosts: ${{ secrets.TRUSTED_HOSTS }} - - - name: Apply the playbook that triggered the workflow - env: - BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }} - BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }} - BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }} - ANSIBLE_USER: ${{ secrets.ANSIBLE_USER }} - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - CHANGED_FILES: ${{ steps.setup_env.outputs.CHANGED_FILES }} - run: | - cd ansible - for PLAYBOOK in $(echo $CHANGED_FILES | grep -oP 'playbook_\K\w+'); do - sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_$PLAYBOOK.yml - done diff --git a/.github/workflows/terraform-k8sapps-apply.yml b/.github/workflows/terraform-k8sapps-apply.yml index bcc0e2a..ec91101 100644 --- a/.github/workflows/terraform-k8sapps-apply.yml +++ b/.github/workflows/terraform-k8sapps-apply.yml @@ -1,8 +1,6 @@ name: OpenTofu K8S Apps apply on: - schedule: - - cron: "0 2 * * 0" push: branches: - main diff --git a/ansible/host_vars/prod-01.alexpires.me.yml b/ansible/host_vars/prod-01.alexpires.me.yml index 4eb6346..1a6a0c3 100644 --- a/ansible/host_vars/prod-01.alexpires.me.yml +++ b/ansible/host_vars/prod-01.alexpires.me.yml @@ -14,6 +14,7 @@ login_users: comment: "Managed by Ansible" sudoer: true pubkey: "{{ lookup('file', 'keys/operator.pub') }}" + password_expiration: false - username: git comment: "Managed by Ansible" shell: "/usr/local/bin/gitea-shell" diff --git a/ansible/roles/README.md b/ansible/roles/README.md new file mode 100644 index 0000000..dd8f56a --- /dev/null +++ b/ansible/roles/README.md @@ -0,0 +1,134 @@ +# Ansible Role Development & Testing with Molecule (Podman) + +This guide explains how to create an Ansible role and test it locally using [Molecule](https://molecule.readthedocs.io/) with the Podman driver. + +--- + +## 1. Prerequisites + +- [Ansible](https://docs.ansible.com/) +- [Molecule](https://molecule.readthedocs.io/) +- [Podman](https://podman.io/) +- [Python](https://www.python.org/) (with `pip`) + +Install Molecule and Podman driver: +```sh +pip install molecule molecule-podman +``` + +--- + +## 2. Create a New Role + +Navigate to your roles directory and create a new role: +```sh +cd ansible/roles +ansible-galaxy init myrole +cd myrole +``` + +--- + +## 3. Initialize Molecule with Podman + +```sh +molecule init scenario default -d podman +``` + +--- + +## 4. Edit Molecule Configuration + +Edit `molecule/default/molecule.yml` to set your platform and image, for example: +```yaml +--- +dependency: + name: galaxy +driver: + name: podman +platforms: + - name: instance + image: ubuntu:20.04 + privileged: true +provisioner: + name: ansible + options: + vvv: true + env: + ANSIBLE_ROLES_PATH: ../../../ +verifier: + name: ansible + +``` + +--- + +## 5. Write Your Role Tasks + +Edit `tasks/main.yml` to add your automation logic. + +--- + +## 6. Configure Molecule to Use Your Role + +Edit `molecule/default/converge.yml`: +```yaml +--- +- name: Converge + hosts: all + gather_facts: false + tasks: + - name: Include role + ansible.builtin.include_role: + name: myrole +``` + +--- + +## 6. Configure preparation steps (required for python and sudo) + +```yaml +--- +--- +- name: Prepare + hosts: all + gather_facts: false + tasks: + - name: Update cache # noqa no-changed-when + ansible.builtin.raw: apt update + + - name: Install required packages # noqa no-changed-when + ansible.builtin.raw: apt install -y python3 sudo + +### Insert here other preparation steps +```` + +--- + +## 8. Run Molecule Tests + +From the root of your role directory, run: +```sh +molecule test +``` + +This will: +- Build the container +- Apply your role +- Run verification steps +- Destroy the container + +--- + +## 8. Notes + +- **Systemd:** Most Podman containers do not support `systemd` by default. Use `when: ansible_service_mgr == "systemd"` to skip service tasks in containers. +- **Role Path:** Always run Molecule commands from the root of your role directory. + +--- + +## References + +- [Molecule Documentation](https://molecule.readthedocs.io/) +- [Podman Documentation](https://podman.io/) +- [Ansible Role Best Practices](https://docs.ansible.com/ansible/latest/dev_guide/developing_roles.html) \ No newline at end of file diff --git a/ansible/roles/cis/molecule/default/molecule.yml b/ansible/roles/cis/molecule/default/molecule.yml index 55c3d6a..dd7f982 100644 --- a/ansible/roles/cis/molecule/default/molecule.yml +++ b/ansible/roles/cis/molecule/default/molecule.yml @@ -6,7 +6,7 @@ driver: name: podman platforms: - name: instance - image: ubuntu:20.04 + image: nmusatti/ubuntu2204-pys-systemd:latest pre_build_image: true privileged: true provisioner: diff --git a/ansible/roles/fwknopd/defaults/main.yml b/ansible/roles/fwknopd/defaults/main.yml new file mode 100644 index 0000000..b888589 --- /dev/null +++ b/ansible/roles/fwknopd/defaults/main.yml @@ -0,0 +1,3 @@ +fwknopd_keys_dir: /etc/fwknop +fwknopd_key_base64: "" +fwknopd_hmac_key_base64: "" diff --git a/ansible/roles/fwknopd/meta/main.yml b/ansible/roles/fwknopd/meta/main.yml new file mode 100644 index 0000000..b3edde2 --- /dev/null +++ b/ansible/roles/fwknopd/meta/main.yml @@ -0,0 +1,39 @@ +--- +galaxy_info: + author: Alexandre Pires + description: Manage fwknopd on Linux + company: A13Labs + role_name: fwknopd + namespace: a13labs + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: MIT + + min_ansible_version: "2.1" + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + galaxy_tags: + [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: + [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. diff --git a/ansible/roles/fwknopd/molecule/default/converge.yml b/ansible/roles/fwknopd/molecule/default/converge.yml new file mode 100644 index 0000000..e63d4b1 --- /dev/null +++ b/ansible/roles/fwknopd/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + gather_facts: false + tasks: + - name: Include role fwknopd + ansible.builtin.include_role: + name: fwknopd diff --git a/ansible/roles/fwknopd/molecule/default/molecule.yml b/ansible/roles/fwknopd/molecule/default/molecule.yml new file mode 100644 index 0000000..7a73456 --- /dev/null +++ b/ansible/roles/fwknopd/molecule/default/molecule.yml @@ -0,0 +1,23 @@ +--- +dependency: + name: galaxy +driver: + name: podman +platforms: + - name: instance + image: nmusatti/ubuntu2204-pys-systemd:latest + pre_build_image: true + privileged: true + tmpfs: + - /run + - /tmp + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw +provisioner: + name: ansible + options: + vvv: true + env: + ANSIBLE_ROLES_PATH: ../../../ +verifier: + name: ansible diff --git a/ansible/roles/fwknopd/molecule/default/prepare.yml b/ansible/roles/fwknopd/molecule/default/prepare.yml new file mode 100644 index 0000000..3209971 --- /dev/null +++ b/ansible/roles/fwknopd/molecule/default/prepare.yml @@ -0,0 +1,30 @@ +--- +- name: Prepare + hosts: all + gather_facts: false + tasks: + - name: Update cache # noqa no-changed-when + ansible.builtin.raw: apt update + + - name: Install required packages # noqa no-changed-when + ansible.builtin.raw: apt install -y python3 sudo + + - name: Install required packages # noqa no-changed-when + ansible.builtin.shell: | + set -o pipefail + apt install -y systemd + find /etc/systemd/system/*.wants /lib/systemd/system/multi-user.target.wants /lib/systemd/system/local-fs.target.wants /lib/systemd/system/sockets.target.wants -type f -name '*initctl*' -delete + find /lib/systemd/system/sysinit.target.wants -type f ! -name '*systemd-tmpfiles-setup*' -delete + find /lib/systemd -type f -name systemd-update-utmp-runlevel.service -delete + rm -vf /usr/share/systemd/tmp.mount + sed -ri '/^IPAddressDeny/d' /lib/systemd/system/systemd-journald.service + for MATCH in plymouth-start.service plymouth-quit-wait.service syslog.socket syslog.service display-manager.service systemd-sysusers.service tmp.mount systemd-udevd.service; do \ + grep -rn --binary-files=without-match ${MATCH} /lib/systemd/ | cut -d: -f1 | xargs -r sed -ri 's/(.*=.*)'${MATCH}'(.*)/\1\2/'; \ + done + systemctl disable ondemand.service + systemctl set-default multi-user.target + become: true + args: + executable: /bin/bash + environment: + DEBIAN_FRONTEND: noninteractive diff --git a/ansible/roles/fwknopd/tasks/main.yml b/ansible/roles/fwknopd/tasks/main.yml new file mode 100644 index 0000000..2d0ea58 --- /dev/null +++ b/ansible/roles/fwknopd/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- name: Install fwknop + ansible.builtin.package: + name: fwknop-server + state: present + update_cache: true + +- name: Enable and start fwknopd + ansible.builtin.systemd: + name: fwknopd + enabled: true + state: started + +- name: Generate fwknop key pair + ansible.builtin.command: fwknop --key-gen + args: + creates: "{{ fwknopd_keys_dir }}/access.conf" + +- name: Copy access.conf + ansible.builtin.template: + src: access.conf.j2 + dest: "{{ fwknopd_keys_dir }}/access.conf" + owner: root + group: root + mode: '0600' diff --git a/ansible/roles/fwknopd/templates/access.conf.j2 b/ansible/roles/fwknopd/templates/access.conf.j2 new file mode 100644 index 0000000..0bef04c --- /dev/null +++ b/ansible/roles/fwknopd/templates/access.conf.j2 @@ -0,0 +1,6 @@ +SOURCE ANY +KEY_BASE64 {{ fwknopd_key_base64 }} +HMAC_KEY_BASE64 {{ fwknopd_hmac_key_base64 }} +ALLOW_IP ANY +OPEN_PORTS tcp/22 +FW_ACCESS_TIMEOUT 30 \ No newline at end of file