Changeset - c10934519e18
[Not reviewed]
! ! !
Branko Majic (branko) - 16 days ago 2024-09-03 15:39:51
branko@majic.rs
MAR-218: Switch to using fully-qualified collection names for all tasks:

- Ensures there is no ambiguity when invoking a module.
62 files changed with 556 insertions and 556 deletions:
0 comments (0 inline, 0 general)
roles/backup/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Assemble Duply include patterns
 
  assemble:
 
  ansible.builtin.assemble:
 
    dest: "/etc/duply/main/include"
 
    src: "/etc/duply/main/patterns"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
    backup: true
roles/backup/molecule/default/prepare.yml
Show inline comments
 
@@ -4,13 +4,13 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
roles/backup/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Configure backup patterns
 
  template:
 
  ansible.builtin.template:
 
    src: "backup_patterns.j2"
 
    dest: "/etc/duply/main/patterns/{{ backup_patterns_filename }}"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  notify:
 
    - Assemble Duply include patterns
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/backup_client/handlers/main.yml
Show inline comments
 
@@ -4,30 +4,30 @@
 
#        seems to disappear in middle of operation).
 
- name: Remove current keyring  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: "rm -rf /etc/duply/main/gnupg"
 
  ansible.builtin.command: "rm -rf /etc/duply/main/gnupg"
 

	
 
- name: Create keyring directory
 
  file:
 
  ansible.builtin.file:
 
    path: "/etc/duply/main/gnupg"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0700"
 

	
 
- name: Import private keys  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: "gpg --no-tty --homedir /etc/duply/main/gnupg --import /etc/duply/main/private_keys.asc"
 
  ansible.builtin.command: "gpg --no-tty --homedir /etc/duply/main/gnupg --import /etc/duply/main/private_keys.asc"
 

	
 
- name: Import public keys  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: "gpg --no-tty --homedir /etc/duply/main/gnupg --import /etc/duply/main/public_keys.asc"
 
  ansible.builtin.command: "gpg --no-tty --homedir /etc/duply/main/gnupg --import /etc/duply/main/public_keys.asc"
 
  when: backup_additional_encryption_keys | length > 0
roles/backup_client/molecule/default/converge.yml
Show inline comments
 
@@ -10,12 +10,12 @@
 
- name: Converge, test fixtures
 
  hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Deploy pre-backup script
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/10-test-pre-backup.sh
 
        dest: /etc/duply/main/pre.d/10-test-pre-backup.sh
 
        owner: root
 
        group: root
 
        mode: "0700"
roles/backup_client/molecule/default/prepare.yml
Show inline comments
 
@@ -4,27 +4,27 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
- name: Prepare, helpers
 
  hosts: backup-server
 
  become: true
 
  tasks:
 

	
 
    - name: Deploy SSH server keys
 
      copy:
 
      ansible.builtin.copy:
 
        content: "{{ lookup('file', item.key) + '\n' }}"
 
        dest: "{{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0600"
 
      with_dict:
 
@@ -32,88 +32,88 @@
 
        tests/data/ssh/server_ed25519: /etc/ssh/ssh_host_ed25519_key
 
        tests/data/ssh/server_ecdsa: /etc/ssh/ssh_host_ecdsa_key
 
      notify:
 
        - Restart ssh
 

	
 
    - name: Drop the outdated public keys
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - /etc/ssh/ssh_host_rsa_key.pub
 
        - /etc/ssh/ssh_host_ed25519_key.pub
 
        - /etc/ssh/ssh_host_ecdsa_key.pub
 

	
 
    - name: Force the use of internal-sftp subsystem for SFTP
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/ssh/sshd_config
 
        regexp: "^Subsystem.*sftp"
 
        line: "Subsystem sftp internal-sftp"
 
        state: present
 

	
 
    - name: Deploy custom SSH server configuration that chroots users
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/backup_server-sshd-chroot_backup_users.conf"
 
        dest: "/etc/ssh/sshd_config.d/chroot_backup_users.conf"
 
        owner: root
 
        group: root
 
        mode: "0600"
 
      notify:
 
        - Restart ssh
 

	
 
    - name: Set-up backup group that will contain all backup users
 
      group:
 
      ansible.builtin.group:
 
        name: "backup-users"
 

	
 
    - name: Set-up backup user groups
 
      group:
 
      ansible.builtin.group:
 
        name: "{{ item.name }}"
 
      with_items: "{{ backup_users }}"
 

	
 
    - name: Set-up backup users
 
      user:
 
      ansible.builtin.user:
 
        name: "{{ item.name }}"
 
        group: "{{ item.name }}"
 
        groups:
 
          - "backup-users"
 
      with_items: "{{ backup_users }}"
 

	
 
    - name: Set-up authorised keys
 
      authorized_key:
 
      ansible.posix.authorized_key:
 
        user: "{{ item.name }}"
 
        key: "{{ item.key }}"
 
      with_items: "{{ backup_users }}"
 

	
 
    - name: Set-up port forwarding
 
      command: "iptables -t nat -A PREROUTING -p tcp -m tcp --dport '{{ item }}' -j REDIRECT --to-ports 22"
 
      ansible.builtin.command: "iptables -t nat -A PREROUTING -p tcp -m tcp --dport '{{ item }}' -j REDIRECT --to-ports 22"
 
      changed_when: false
 
      with_items:
 
        - 2222
 
        - 3333
 

	
 
    - name: Change ownership of home directories for SFTP chroot to work
 
      file:
 
      ansible.builtin.file:
 
        path: "/home/{{ item.name }}"
 
        state: directory
 
        owner: root
 
        group: root
 
        mode: "0755"
 
      with_items: "{{ backup_users }}"
 

	
 
    - name: Set-up duplicity backup directories
 
      file:
 
      ansible.builtin.file:
 
        path: "~{{ item.name }}/duplicity"
 
        state: directory
 
        owner: root
 
        group: backup-users
 
        mode: "0770"
 
      with_items: "{{ backup_users }}"
 

	
 
  handlers:
 
    - name: Restart ssh
 
      service:
 
      ansible.builtin.service:
 
        name: ssh
 
        state: restarted
 

	
 
  vars:
 
    backup_users:
 
      - name: bak-param-mandatory-bookworm
roles/backup_client/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install backup software
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - duplicity
 
      - duply
 
    state: present
 

	
 
- name: Set-up Duply directories
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0700"
 
  with_items:
 
@@ -21,123 +21,123 @@
 
    - "/etc/duply/main/gnupg"
 
    - "/etc/duply/main/ssh"
 
    - "/var/cache/duply"
 
    - "/var/cache/duply/main"
 

	
 
- name: Deploy GnuPG private keys
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ backup_encryption_key }}"
 
    dest: "/etc/duply/main/private_keys.asc"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  notify:
 
    - Remove current keyring
 
    - Create keyring directory
 
    - Import private keys
 
    - Import public keys
 

	
 
- name: Deploy GnuPG public keys
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ backup_additional_encryption_keys | join('\n') }}"
 
    dest: "/etc/duply/main/public_keys.asc"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  notify:
 
    - Remove current keyring
 
    - Create keyring directory
 
    - Import private keys
 
    - Import public keys
 

	
 
- name: Extract encryption key identifier (Duplicty requires key ID in hexadecimal format)
 
  shell: "set -o pipefail && gpg --no-tty --list-packets /etc/duply/main/private_keys.asc | grep keyid: |
 
  ansible.builtin.shell: "set -o pipefail && gpg --no-tty --list-packets /etc/duply/main/private_keys.asc | grep keyid: |
 
    head -n1 | sed -e 's/.*: //'"
 
  args:
 
    executable: /bin/bash
 
  register: backup_encryption_key_id
 
  changed_when: false
 
  failed_when: not backup_encryption_key_id.stdout
 

	
 
- name: Extract additional encryption keys identifiers (Duplicty requires key ID in hexadecimal format)
 
  shell: "set -o pipefail &&  gpg --no-tty --list-packets /etc/duply/main/public_keys.asc | grep keyid: |
 
  ansible.builtin.shell: "set -o pipefail &&  gpg --no-tty --list-packets /etc/duply/main/public_keys.asc | grep keyid: |
 
    sed -e 's/.*: //' | sort -u | tr '\n' ',' | sed -e 's/,$//'"
 
  args:
 
    executable: /bin/bash
 
  when: backup_additional_encryption_keys | length > 0
 
  register: backup_additional_encryption_keys_ids
 
  changed_when: false
 
  failed_when: not backup_additional_encryption_keys_ids.stdout
 

	
 
- name: Deploy private SSH key for logging-in into backup server
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ backup_ssh_key }}"
 
    dest: "/etc/duply/main/ssh/identity"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  no_log: true
 

	
 
- name: Deploy custom known_hosts for backup purposes
 
  template:
 
  ansible.builtin.template:
 
    src: "known_hosts.j2"
 
    dest: "/etc/duply/main/ssh/known_hosts"
 
    owner: root
 
    group: root
 
    mode: "0600"
 

	
 
- name: Deploy Duply configuration file
 
  template:
 
  ansible.builtin.template:
 
    src: "duply_main_conf.j2"
 
    dest: "/etc/duply/main/conf"
 
    owner: root
 
    group: root
 
    mode: "0600"
 

	
 
- name: Deploy base exclude pattern (exclude all by default)
 
  copy:
 
  ansible.builtin.copy:
 
    content: "- **"
 
    dest: "/etc/duply/main/exclude"
 
    owner: root
 
    group: root
 
    mode: "0600"
 

	
 
- name: Set-up directory for storing pre-backup scripts
 
  file:
 
  ansible.builtin.file:
 
    path: "/etc/duply/main/pre.d/"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0700"
 

	
 
- name: Set-up script for running all pre-backup scripts
 
  copy:
 
  ansible.builtin.copy:
 
    src: "duply_pre"
 
    dest: "/etc/duply/main/pre"
 
    owner: root
 
    group: root
 
    mode: "0700"
 

	
 
- name: Deploy crontab entry for running backups
 
  cron:
 
  ansible.builtin.cron:
 
    name: backup
 
    cron_file: backup
 
    hour: "2"
 
    minute: "0"
 
    job: "/usr/bin/duply main pre_and_bkp && /usr/bin/duply main post_and_purge --force"
 
    state: present
 
    user: root
 

	
 
- name: Ensure the file with include patterns exists (but do not overwrite)
 
  copy:
 
  ansible.builtin.copy:
 
    content: ""
 
    dest: /etc/duply/main/include
 
    force: false
 
    group: root
 
    owner: root
 
    mode: "0600"
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/backup_server/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Restart backup SSH server
 
  service:
 
  ansible.builtin.service:
 
    name: ssh-backup
 
    state: restarted
roles/backup_server/molecule/default/prepare.yml
Show inline comments
 
@@ -3,13 +3,13 @@
 
- name: Prepare, test fixtures
 
  hosts: localhost
 
  connection: local
 
  tasks:
 

	
 
    - name: Fix SSH client file permissions locally, otherwise we get error from SSH
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        mode: g=,o=
 
      with_items:
 
        - tests/data/ssh/client1
 
        - tests/data/ssh/client2
 

	
 
@@ -17,12 +17,12 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
roles/backup_server/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install backup software
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - duplicity
 
      - duply
 
    state: present
 

	
 
- name: Create directory for storing backups
 
  file:
 
  ansible.builtin.file:
 
    path: "/srv/backups"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0751"
 

	
 
- name: Create backup client groups
 
  group:
 
  ansible.builtin.group:
 
    name: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    gid: "{{ item.uid | default(omit) }}"
 
    system: true
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Create backup client users
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    group: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    groups: "backup"
 
    uid: "{{ item.uid | default(omit) }}"
 
    system: true
 
    createhome: false
 
    state: present
 
    home: "/srv/backups/{{ item.server }}"
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Create home directories for backup client users
 
  file:
 
  ansible.builtin.file:
 
    path: "/srv/backups/{{ item.server }}"
 
    state: directory
 
    owner: root
 
    group: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    mode: "0750"
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Create duplicity directories for backup client users
 
  file:
 
  ansible.builtin.file:
 
    path: "/srv/backups/{{ item.server }}/duplicity"
 
    state: directory
 
    owner: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    group: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    mode: "0770"
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Create SSH directory for backup client users
 
  file:
 
  ansible.builtin.file:
 
    path: "/srv/backups/{{ item.server }}/.ssh"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0751"
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Populate authorized keys for backup client users
 
  authorized_key:
 
  ansible.posix.authorized_key:
 
    user: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    key: "{{ item.public_key }}"
 
    manage_dir: false
 
    state: present
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Set-up authorized_keys file permissions for backup client users
 
  file:
 
  ansible.builtin.file:
 
    path: "/srv/backups/{{ item.server }}/.ssh/authorized_keys"
 
    state: file
 
    owner: root
 
    group: "{{ item.server | replace('.', '_') | regex_replace('^', 'bak-') }}"
 
    mode: "0640"
 
  with_items: "{{ backup_clients }}"
 

	
 
- name: Deny the backup group login via regular SSH
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/ssh/sshd_config"
 
    state: present
 
    line: "DenyGroups backup"
 
  notify:
 
    - Restart SSH
 

	
 
- name: Set-up directory for the backup OpenSSH server instance
 
  file:
 
  ansible.builtin.file:
 
    path: "/etc/ssh-backup/"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0700"
 

	
 
- name: Deploy configuration file for the backup OpenSSH server instance service
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ssh-backup.default"
 
    dest: "/etc/default/ssh-backup"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart backup SSH server
 

	
 
- name: Deploy configuration file for the backup OpenSSH server instance
 
  copy:
 
  ansible.builtin.copy:
 
    src: "backup-sshd_config"
 
    dest: "/etc/ssh-backup/sshd_config"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  notify:
 
    - Restart backup SSH server
 

	
 
- name: Deploy the private keys for backup OpenSSH server instance
 
  template:
 
  ansible.builtin.template:
 
    src: "ssh_host_key.j2"
 
    dest: "/etc/ssh-backup/ssh_host_{{ item.key }}_key"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  with_dict: "{{ backup_host_ssh_private_keys }}"
 
  notify:
 
    - Restart backup SSH server
 
  no_log: true
 

	
 
- name: Deploy backup OpenSSH server systemd service file
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ssh-backup.service"
 
    dest: "/etc/systemd/system/ssh-backup.service"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Reload systemd
 
    - Restart backup SSH server
 

	
 
- name: Start and enable OpenSSH backup service
 
  service:
 
  ansible.builtin.service:
 
    name: "ssh-backup"
 
    state: started
 
    enabled: true
 

	
 
- name: Deploy firewall configuration for backup server
 
  template:
 
  ansible.builtin.template:
 
    src: "ferm_backup.conf.j2"
 
    dest: "/etc/ferm/conf.d/40-backup.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/bootstrap/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Dummy handler to suppress Ansible warnings
 
  debug:
 
  ansible.builtin.debug:
 
    msg: "This is just a dummy task to suppress the Ansible warning about an empty include."
roles/bootstrap/molecule/default/prepare.yml
Show inline comments
 
@@ -4,35 +4,35 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
# Put Ansible key into root's authorized_keys to test its removal.
 
- name: Prepare, text fixtures
 
  hosts: parameters-mandatory
 
  become: true
 
  tasks:
 

	
 
    - name: Deploy authorized_keys to mimic set-up via preseed file
 
      authorized_key:
 
      ansible.posix.authorized_key:
 
        user: root
 
        key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
 

	
 
# Put Ansible key into root's authorized_keys to test its removal.
 
- name: Prepare, text fixtures
 
  hosts: parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Deploy authorized_keys to mimic set-up via preseed file
 
      authorized_key:
 
      ansible.posix.authorized_key:
 
        user: root
 
        key: "{{ lookup('file', 'tests/data/ansible_key.pub') }}"
roles/bootstrap/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install sudo
 
  apt:
 
  ansible.builtin.apt:
 
    name: sudo
 
    state: present
 

	
 
- name: Set-up the Ansible group
 
  group:
 
  ansible.builtin.group:
 
    name: ansible
 
    system: true
 

	
 
- name: Set-up the Ansible user
 
  user:
 
  ansible.builtin.user:
 
    name: ansible
 
    system: true
 
    group: ansible
 
    shell: /bin/bash
 

	
 
- name: Set-up authorized key for the Ansible user
 
  authorized_key:
 
  ansible.posix.authorized_key:
 
    user: ansible
 
    key: "{{ ansible_key }}"
 

	
 
- name: Set-up password-less sudo for the ansible user
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ansible_sudo"
 
    dest: "/etc/sudoers.d/ansible"
 
    mode: "0640"
 
    owner: root
 
    group: root
 

	
 
- name: Revoke rights for Ansible user to log-in as root to server via ssh
 
  authorized_key:
 
  ansible.posix.authorized_key:
 
    user: root
 
    key: "{{ ansible_key }}"
 
    state: absent
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/common/handlers/main.yml
Show inline comments
 
@@ -2,34 +2,34 @@
 

	
 
- name: Update PAM configuration  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: "/usr/sbin/pam-auth-update --package"
 
  ansible.builtin.command: "/usr/sbin/pam-auth-update --package"
 

	
 
- name: Restart SSH
 
  service:
 
  ansible.builtin.service:
 
    name: ssh
 
    state: restarted
 

	
 
- name: Update CA certificate cache  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: "/usr/sbin/update-ca-certificates --fresh"
 
  ansible.builtin.command: "/usr/sbin/update-ca-certificates --fresh"
 

	
 
- name: Restart ferm
 
  service:
 
  ansible.builtin.service:
 
    name: ferm
 
    state: restarted
 

	
 
- name: Reload systemd
 
  systemd:
 
  ansible.builtin.systemd:
 
    daemon_reload: true
 

	
 
- name: Restart NTP server
 
  service:
 
  ansible.builtin.service:
 
    name: ntpsec
 
    state: restarted
 
  when: ntp_pools | length > 0
roles/common/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/common/molecule/default/converge.yml
Show inline comments
 
@@ -9,25 +9,25 @@
 
- name: Converge, test fixtures
 
  hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up directories for testing pip requirements upgrade checks script
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: directory
 
        owner: root
 
        group: pipreqcheck
 
        mode: "0750"
 
      with_items:
 
        - "/tmp/pip_check_requirements_upgrades"
 
        - "/tmp/pip_check_requirements_upgrades/with_updates"
 
        - "/tmp/pip_check_requirements_upgrades/without_updates"
 

	
 
    - name: Deploy files for testing pip requirements upgrade checks script
 
      copy:
 
      ansible.builtin.copy:
 
        src: "{{ item }}"
 
        dest: "/tmp/{{ item }}"
 
        owner: root
 
        group: pipreqcheck
 
        mode: "0640"
 
        directory_mode: "0750"
 
@@ -35,26 +35,26 @@
 
        - "pip_check_requirements_upgrades/with_updates/requirements.in"
 
        - "pip_check_requirements_upgrades/with_updates/requirements.txt"
 
        - "pip_check_requirements_upgrades/without_updates/requirements.in"
 
        - "pip_check_requirements_upgrades/without_updates/requirements.txt"
 

	
 
    - name: Install web server for testing connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: nginx
 
        state: present
 

	
 
    - name: Deploy firewall configuration file for the web server
 
      copy:
 
      ansible.builtin.copy:
 
        src: ferm_http.conf
 
        dest: /etc/ferm/conf.d/99-http.conf
 
        owner: root
 
        group: root
 
        mode: "0640"
 
      notify:
 
        - Restart ferm
 

	
 
  handlers:
 

	
 
    - name: Restart ferm
 
      service:
 
      ansible.builtin.service:
 
        name: ferm
 
        state: restarted
roles/common/molecule/default/prepare.yml
Show inline comments
 
@@ -4,70 +4,70 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init --ca-hierarchy-depth 2"
 
      ansible.builtin.command: "gimmecert init --ca-hierarchy-depth 2"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Install net-tools for running Testinfra host.socket tests
 
      apt:
 
      ansible.builtin.apt:
 
        name: net-tools
 
        state: present
 

	
 
    - name: Remove the ss utility (see https://github.com/philpep/testinfra/pull/320)
 
      file:
 
      ansible.builtin.file:
 
        path: "/bin/ss"
 
        state: absent
 

	
 
- name: Prepare, helpers
 
  hosts: helper
 
  become: true
 
  tasks:
 

	
 
    - name: Install apt-cacher-ng
 
      apt:
 
      ansible.builtin.apt:
 
        name: apt-cacher-ng
 
        state: present
 

	
 
- name: Prepare, helpers
 
  hosts: client
 
  become: true
 
  tasks:
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: nmap
 
        state: present
 

	
 
    - name: Set-up /etc/hosts with entries for all servers
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -81,26 +81,26 @@
 
- name: Prepare, test fixtures
 
  hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up /etc/hosts with entries for all servers
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
        state: present
 
      with_dict:
 
        192.168.56.3: client1
 
        192.168.56.4: client2
 

	
 
    - name: Load legacy iptables to test their removal
 
      modprobe:
 
      community.general.modprobe:
 
        name: "{{ item }}"
 
        state: present
 
      with_items:
 
        - iptable_filter
 
        - iptable_nat
 
        - iptable_mangle
 
@@ -112,55 +112,55 @@
 
        - ip6table_security
 
        - ip6table_raw
 

	
 
    - name: Create some custom legacy iptables chains for testing their removal (max chain name length is 29)  # noqa no-changed-when
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 
      command: "iptables-legacy -t '{{ item }}' -N '{{ (ansible_date_time.iso8601_micro | to_uuid)[:28] }}'"
 
      ansible.builtin.command: "iptables-legacy -t '{{ item }}' -N '{{ (ansible_date_time.iso8601_micro | to_uuid)[:28] }}'"
 
      with_items:
 
        - filter
 
        - nat
 
        - mangle
 
        - security
 
        - raw
 

	
 
    - name: Create some custom legacy ip6tables chains for testing their removal (max chain name length is 29)  # noqa no-changed-when
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 
      command: "ip6tables-legacy -t '{{ item }}' -N '{{ (ansible_date_time.iso8601_micro | to_uuid)[:28] }}'"
 
      ansible.builtin.command: "ip6tables-legacy -t '{{ item }}' -N '{{ (ansible_date_time.iso8601_micro | to_uuid)[:28] }}'"
 
      with_items:
 
        - filter
 
        - nat
 
        - mangle
 
        - security
 
        - raw
 

	
 
    - name: Create deprecated directory for storing requirements files created using Python 3 (pip requirements upgrade checks)
 
      file:
 
      ansible.builtin.file:
 
        path: "/etc/pip_check_requirements_upgrades-py3"
 
        state: directory
 
        owner: root
 
        group: root
 
        mode: "0750"
 

	
 
    - name: Create deprecated directory for Python 3 virtual environment (pip requirements upgrade checks)
 
      file:
 
      ansible.builtin.file:
 
        path: "/var/lib/pipreqcheck/virtualenv-py3/"
 
        state: directory
 
        owner: root
 
        group: root
 
        mode: "0750"
 

	
 
    - name: Create deprecated cronjob file for Python 3 (pip requirements upgrade checks)
 
      file:
 
      ansible.builtin.file:
 
        path: "/etc/cron.d/check_pip_requirements-py3"
 
        state: touch
 
        owner: root
 
        group: root
 
        mode: "0644"
 

	
 
    - name: Install the deprecated/obsolete NTP-related packages
 
      apt:
 
      ansible.builtin.apt:
 
        name:
 
          - ntp
 
          - ntpdate
 
        state: present
roles/common/tasks/main.yml
Show inline comments
 
---
 

	
 
# Deprecation
 
# ===========
 

	
 
- name: Drop deprecated directories and files
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: absent
 
  with_items:
 
    - "/etc/pip_check_requirements_upgrades-py3"
 
    - "/var/lib/pipreqcheck/virtualenv-py3"
 
    - "/etc/cron.d/check_pip_requirements-py3"
 

	
 
- name: Drop deprecated packages
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - ntp
 
      - ntpdate
 
    state: absent
 
    purge: true
 

	
 
# Main implementation
 
# ===================
 

	
 
- name: Enable use of proxy for retrieving system packages via apt
 
  template:
 
  ansible.builtin.template:
 
    src: "apt_proxy.j2"
 
    dest: "/etc/apt/apt.conf.d/00proxy"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  when: apt_proxy is defined
 

	
 
- name: Disable use of proxy for retrieving system packages via apt
 
  file:
 
  ansible.builtin.file:
 
    path: "/etc/apt/apt.conf.d/00proxy"
 
    state: absent
 
  when: apt_proxy is undefined
 

	
 
- name: Deploy pam-auth-update configuration file for enabling pam_umask
 
  copy:
 
  ansible.builtin.copy:
 
    src: "pam_umask"
 
    dest: "/usr/share/pam-configs/umask"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  register: pam_umask
 
@@ -52,154 +52,154 @@
 
- name: Update PAM configuration  # noqa no-handler
 
  # [no-handler] Tasks that run when changed should likely be handlers
 
  #   In order to have consistent behaviour during the first and
 
  #   subsequent playbook runs, make sure the PAM configuration is
 
  #   updated immediatelly. This way any files created by commands etc
 
  #   should end-up with correct permissions straight away.
 
  command: "/usr/sbin/pam-auth-update --package"
 
  ansible.builtin.command: "/usr/sbin/pam-auth-update --package"
 
  when: pam_umask.changed
 
  changed_when: true  # Always results in change due to task logic.
 

	
 
- name: Set login UMASK
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/login.defs"
 
    state: present
 
    backrefs: true
 
    regexp: '^UMASK(\s+)'
 
    line: 'UMASK\g<1>027'
 

	
 
- name: Set home directory mask
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/adduser.conf"
 
    state: present
 
    backrefs: true
 
    regexp: '^\s*#?\s*DIR_MODE='
 
    line: 'DIR_MODE=0750'
 

	
 
- name: Deploy bash profile configuration for fancier prompts
 
  template:
 
  ansible.builtin.template:
 
    src: "bash_prompt.sh.j2"
 
    dest: "/etc/profile.d/bash_prompt.sh"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Deploy profile configuration that allows for user-specific profile.d files
 
  copy:
 
  ansible.builtin.copy:
 
    src: "user_profile_d.sh"
 
    dest: "/etc/profile.d/z99-user_profile_d.sh"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Replace default and skeleton bashrc
 
  copy:
 
  ansible.builtin.copy:
 
    src: "{{ item.key }}"
 
    dest: "{{ item.value }}"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  with_dict:
 
    bashrc: "/etc/bash.bashrc"
 
    skel_bashrc: "/etc/skel/.bashrc"
 

	
 
- name: Calculate stock checksum for bashrc root account
 
  stat:
 
  ansible.builtin.stat:
 
    path: "/root/.bashrc"
 
  register: root_bashrc_stat
 

	
 
- name: Replace stock bashrc for root account with skeleton one
 
  copy:
 
  ansible.builtin.copy:
 
    src: "skel_bashrc"
 
    dest: "/root/.bashrc"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  # Checksums: bookworm
 
  when: |
 
    root_bashrc_stat.stat.checksum == "1a422a148ad225aa5ba33f8dafd2b7cfcdbd701f"
 

	
 
- name: Install sudo
 
  apt:
 
  ansible.builtin.apt:
 
    name: sudo
 
    state: present
 

	
 
- name: Install ssl-cert package
 
  apt:
 
  ansible.builtin.apt:
 
    name: ssl-cert
 
    state: present
 

	
 
- name: Install common packages
 
  apt:
 
  ansible.builtin.apt:
 
    name: "{{ common_packages }}"
 
    state: "present"
 

	
 
- name: Disable electric-indent-mode for Emacs by default for all users
 
  copy:
 
  ansible.builtin.copy:
 
    src: "01disable-electric-indent-mode.el"
 
    dest: "/etc/emacs/site-start.d/01disable-electric-indent-mode.el"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  when: "['emacs24', 'emacs24-nox', 'emacs25', 'emacs25-nox', 'emacs', 'emacs-nox'] | intersect(common_packages) | length > 0"
 

	
 
- name: Set-up operating system groups
 
  group:
 
  ansible.builtin.group:
 
    name: "{{ item.name }}"
 
    gid: "{{ item.gid | default(omit) }}"
 
    state: present
 
  with_items: "{{ os_groups }}"
 

	
 
- name: Set-up operating system user groups
 
  group:
 
  ansible.builtin.group:
 
    name: "{{ item.name }}"
 
    gid: "{{ item.uid | default(omit) }}"
 
    state: present
 
  with_items: "{{ os_users }}"
 

	
 
- name: Set-up operating system users
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ item.name }}"
 
    uid: "{{ item.uid | default(omit) }}"
 
    group: "{{ item.name }}"
 
    groups: "{{ ','.join(item.additional_groups | default([])) }}"
 
    append: true
 
    shell: /bin/bash
 
    ansible.builtin.shell: /bin/bash
 
    state: present
 
    password: "{{ item.password | default('!') }}"
 
    update_password: on_create
 
  with_items: "{{ os_users }}"
 

	
 
- name: Set-up authorised keys
 
  authorized_key:
 
  ansible.posix.authorized_key:
 
    user: "{{ item.0.name }}"
 
    key: "{{ item.1 }}"
 
  with_subelements:
 
    - "{{ os_users | selectattr('authorized_keys', 'defined') | list }}"
 
    - authorized_keys
 

	
 
- name: Disable remote logins for root
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/ssh/sshd_config"
 
    state: present
 
    regexp: "^PermitRootLogin"
 
    line: "PermitRootLogin no"
 
  notify:
 
    - Restart SSH
 

	
 
- name: Disable remote login authentication via password
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/ssh/sshd_config"
 
    state: present
 
    regexp: "^PasswordAuthentication"
 
    line: "PasswordAuthentication no"
 
  notify:
 
    - Restart SSH
 

	
 
- name: Deploy CA certificates
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ item.value }}"
 
    dest: "/usr/local/share/ca-certificates/{{ item.key }}.crt"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  with_dict: "{{ ca_certificates }}"
 
@@ -207,334 +207,334 @@
 

	
 
- name: Update CA certificate cache  # noqa no-handler
 
  # [no-handler] Tasks that run when changed should likely be handlers
 
  #   CA certificate cache must be updated immediatelly in order for
 
  #   applications depending on deployed CA certificates can use them to
 
  #   validate server/client certificates.
 
  command: "/usr/sbin/update-ca-certificates --fresh"
 
  ansible.builtin.command: "/usr/sbin/update-ca-certificates --fresh"
 
  when: deploy_ca_certificates_result.changed
 
  changed_when: true  # Always results in change due to task logic.
 

	
 
- name: Set-up file diversions for custom files that overrride package-provided ones
 
  command: "dpkg-divert --divert '{{ item }}.original' --rename '{{ item }}'"
 
  ansible.builtin.command: "dpkg-divert --divert '{{ item }}.original' --rename '{{ item }}'"
 
  register: "dpkg_divert"
 
  changed_when: "'Adding' in dpkg_divert.stdout"
 
  with_items:
 
    - "/usr/sbin/ferm"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Deploy the patched ferm binary that disables use of legacy iptables
 
  copy:
 
  ansible.builtin.copy:
 
    src: ferm_binary
 
    dest: /usr/sbin/ferm
 
    owner: root
 
    group: root
 
    mode: "0755"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Install ferm (for firewall management)
 
  apt:
 
  ansible.builtin.apt:
 
    name: ferm
 
    state: present
 

	
 
- name: Configure ferm init script coniguration file
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ferm_default"
 
    dest: "/etc/default/ferm"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Create directory for storing ferm configuration files
 
  file:
 
  ansible.builtin.file:
 
    dest: "/etc/ferm/conf.d/"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0750"
 

	
 
- name: Deploy main ferm configuration file
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ferm.conf"
 
    dest: "/etc/ferm/ferm.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Verify maintenance_allowed_sources parameter
 
  fail:
 
  ansible.builtin.fail:
 
    msg: "Items in maintenance_allowed_sources must IPv4/IPv6 addresses or subnets: {{ item }}"
 
  when: "not (item is ansible.utils.ipv4_address or item is ansible.utils.ipv6_address)"
 
  with_items: "{{ maintenance_allowed_sources }}"
 

	
 
- name: Deploy ferm base rules
 
  template:
 
  ansible.builtin.template:
 
    src: "00-base.conf.j2"
 
    dest: "/etc/ferm/conf.d/00-base.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Enable and start ferm
 
  service:
 
  ansible.builtin.service:
 
    name: ferm
 
    state: started
 
    enabled: true
 

	
 
- name: Deploy script for flushing legacy iptables rules
 
  copy:
 
  ansible.builtin.copy:
 
    src: "legacy_iptables_rules.sh"
 
    dest: "/usr/local/sbin/drop_legacy_iptables_rules.sh"
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Drop legacy iptables rules
 
  command: "/usr/local/sbin/drop_legacy_iptables_rules.sh remove"
 
  ansible.builtin.command: "/usr/local/sbin/drop_legacy_iptables_rules.sh remove"
 
  register: legacy_iptables_rules
 
  changed_when: "'Removed legacy iptables for families' in legacy_iptables_rules.stdout"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Deploy script for validating server certificates
 
  copy:
 
  ansible.builtin.copy:
 
    src: "check_certificate.sh"
 
    dest: "/usr/local/bin/check_certificate.sh"
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Set-up directory for holding configuration for certificate validation script
 
  file:
 
  ansible.builtin.file:
 
    path: "/etc/check_certificate"
 
    state: "directory"
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Deploy crontab entry for checking certificates
 
  cron:
 
  ansible.builtin.cron:
 
    name: "check_certificate"
 
    cron_file: "check_certificate"
 
    hour: "0"
 
    minute: "0"
 
    job: "/usr/local/bin/check_certificate.sh -q expiration"
 
    state: present
 
    user: nobody
 

	
 
- name: Install apticron (for checking available upgrades)
 
  apt:
 
  ansible.builtin.apt:
 
    name: apticron
 
    state: present
 

	
 
# It would be too much hassle to detect changed state, so just ignore it.
 
- name: Preventively run apticron to avoid issues with locking
 
  command: /usr/sbin/apticron --cron
 
  ansible.builtin.command: /usr/sbin/apticron --cron
 
  changed_when: false
 

	
 
# Implementation for checking pip requirements files via via pip-tools.
 
- name: Install packages required for running pip requirements checks
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - python3-setuptools
 
      - virtualenv
 
    state: present
 

	
 
- name: Create dedicated group for user running pip requirements checks
 
  group:
 
  ansible.builtin.group:
 
    name: "pipreqcheck"
 
    gid: "{{ pipreqcheck_gid | default(omit) }}"
 
    state: present
 

	
 
- name: Create user for running pip requirements checks
 
  user:
 
  ansible.builtin.user:
 
    name: "pipreqcheck"
 
    uid: "{{ pipreqcheck_uid | default(omit) }}"
 
    group: "pipreqcheck"
 
    home: "/var/lib/pipreqcheck"
 
    state: present
 

	
 
- name: Retrieve system Python interpreter version
 
  command:
 
  ansible.builtin.command:
 
    argv:
 
      - "/usr/bin/python3"
 
      - "-c"
 
      - "import sys; print(sys.version.split(' ')[0])"
 
  changed_when: false
 
  register: python_interpreter_version
 

	
 
- name: Retrieve virtual environment Python interpreter version (if initialised)
 
  command:
 
  ansible.builtin.command:
 
    argv:
 
      - "/var/lib/pipreqcheck/virtualenv/bin/python"
 
      - "-c"
 
      - "import sys; print(sys.version.split(' ')[0])"
 
  become: true
 
  become_user: "pipreqcheck"
 
  # Virtual environment perhaps does not exist.
 
  failed_when: false
 
  changed_when: false
 
  register: virtualenv_python_version
 

	
 
- name: Retrieve virtual environment prompt
 
  command:
 
  ansible.builtin.command:
 
    argv:
 
      - "bash"
 
      - "-c"
 
      - "source '/var/lib/pipreqcheck/virtualenv/bin/activate'; printenv PS1"
 
  become: true
 
  become_user: "pipreqcheck"
 
  failed_when: false
 
  changed_when: false
 
  register: current_virtualenv_prompt
 

	
 
- name: Remove virtual environment in case of mismatches
 
  file:
 
  ansible.builtin.file:
 
    path: "/var/lib/pipreqcheck/virtualenv"
 
    state: absent
 
  when: |
 
    virtualenv_python_version.rc != 0 or
 
    virtualenv_python_version.stdout.strip() != python_interpreter_version.stdout.strip() or
 
    current_virtualenv_prompt.stdout != "(pipreqcheck) "
 

	
 
- name: Create directory for Python virtual environment used for installing/running pip-tools
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: directory
 
    owner: pipreqcheck
 
    group: pipreqcheck
 
    mode: "0750"
 
  with_items:
 
    - "/var/lib/pipreqcheck"
 
    - "/var/lib/pipreqcheck/virtualenv"
 

	
 
- name: Create Python virtual environment used for installing/running pip-tools
 
  command: "/usr/bin/virtualenv --python '{{ item.python_path }}' --prompt '{{ item.virtualenv_prompt }}' '{{ item.virtualenv_path }}'"
 
  ansible.builtin.command: "/usr/bin/virtualenv --python '{{ item.python_path }}' --prompt '{{ item.virtualenv_prompt }}' '{{ item.virtualenv_path }}'"
 
  args:
 
    creates: "{{ item.creates }}"
 
  become: true
 
  become_user: "pipreqcheck"
 
  with_items:
 
    - name: pipreqcheck
 
      virtualenv_path: "/var/lib/pipreqcheck/virtualenv"
 
      virtualenv_prompt: "pipreqcheck"
 
      python_path: "/usr/bin/python3"
 
      creates: "/var/lib/pipreqcheck/virtualenv/bin/python3"
 

	
 
- name: Create directory for storing pip requirements files
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: "directory"
 
    owner: root
 
    group: pipreqcheck
 
    mode: "0750"
 
  with_items:
 
    - "/etc/pip_check_requirements_upgrades"
 

	
 
- name: Set-up directory for storing pip requirements file for pip-tools virtual environment itself
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: "directory"
 
    owner: root
 
    group: pipreqcheck
 
    mode: "0750"
 
  with_items:
 
    - "/etc/pip_check_requirements_upgrades/pipreqcheck"
 

	
 
- name: Deploy .in file for pip requirements in pip-tools virtual environment
 
  template:
 
  ansible.builtin.template:
 
    src: "pipreqcheck_requirements.in.j2"
 
    dest: "{{ item.path }}"
 
    owner: root
 
    group: pipreqcheck
 
    mode: "0640"
 
  with_items:
 
    - path: "/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.in"
 
      requirements: "{{ pip_check_requirements_in }}"
 

	
 
- name: Deploy requirements file for pipreqcheck virtual environment
 
  template:
 
  ansible.builtin.template:
 
    src: "pipreqcheck_requirements.txt.j2"
 
    dest: "{{ item.file }}"
 
    owner: root
 
    group: pipreqcheck
 
    mode: "0640"
 
  with_items:
 
    - file: "/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 
      requirements: "{{ pip_check_requirements }}"
 

	
 
- name: Install requirements in the pipreqcheck virtual environment
 
  pip:
 
  ansible.builtin.pip:
 
    requirements: "{{ item.requirements }}"
 
    virtualenv: "{{ item.virtualenv }}"
 
  become: true
 
  become_user: pipreqcheck
 
  with_items:
 
    - virtualenv: "~pipreqcheck/virtualenv"
 
      requirements: "/etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 

	
 
- name: Synchronise pip-tools virtual environment via deployed requirements file
 
  shell: "source ~pipreqcheck/virtualenv/bin/activate && pip-sync /etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 
  ansible.builtin.shell: "source ~pipreqcheck/virtualenv/bin/activate && pip-sync /etc/pip_check_requirements_upgrades/pipreqcheck/requirements.txt"
 
  args:
 
    executable: /bin/bash
 
  become: true
 
  become_user: "pipreqcheck"
 
  register: pipreqcheck_pip_sync
 
  changed_when: "pipreqcheck_pip_sync.stdout != 'Everything up-to-date'"
 

	
 
- name: Deploy script for checking available upgrades
 
  copy:
 
  ansible.builtin.copy:
 
    src: "pip_check_requirements_upgrades.sh"
 
    dest: "/usr/local/bin/pip_check_requirements_upgrades.sh"
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Deploy crontab entry for checking pip requirements
 
  copy:
 
  ansible.builtin.copy:
 
    src: "cron_check_pip_requirements"
 
    dest: "/etc/cron.d/check_pip_requirements"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Install NTP packages
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - ntpsec
 
      - ntpsec-ntpdate
 
    state: present
 
  when: ntp_pools | length > 0
 

	
 
- name: Remove NTP packages
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - ntpsec
 
      - ntpsec-ntpdate
 
    state: absent
 
    purge: true
 
  when: ntp_pools | length == 0
 

	
 
- name: Deploy NTP configuration
 
  template:
 
  ansible.builtin.template:
 
    src: "ntp.conf.j2"
 
    dest: "/etc/ntpsec/ntp.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  when: ntp_pools | length > 0
 
  notify:
 
    - Restart NTP server
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/database/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Dummy handler to suppress Ansible warnings
 
  debug:
 
  ansible.builtin.debug:
 
    msg: "This is just a dummy task to suppress the Ansible warning about an empty include."
roles/database/molecule/default/prepare.yml
Show inline comments
 
@@ -4,17 +4,17 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
- name: Prepare, helpers
 
  hosts: backup-server
 
  become: true
roles/database/tasks/backup.yml
Show inline comments
 
---
 

	
 
- name: Create directory for storing MariaDB database dumps
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0700"
 
  with_items:
 
    - "/srv/backup"
 
    - "/srv/backup/mariadb"
 

	
 
- name: Deploy script for creating database backup dumps
 
  template:
 
  ansible.builtin.template:
 
    src: "dump_db.sh.j2"
 
    dest: "/etc/duply/main/pre.d/dump_{{ db_name }}.sh"
 
    owner: root
 
    group: root
 
    mode: "0700"
roles/database/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: "Create database {{ db_name }}"
 
  mysql_db:
 
  community.mysql.mysql_db:
 
    name: "{{ db_name }}"
 
    state: present
 
    login_unix_socket: "/var/run/mysqld/mysqld.sock"
 

	
 
- name: "Create database user {{ db_name }}"
 
  mysql_user:
 
  community.mysql.mysql_user:
 
    name: "{{ db_name }}"
 
    password: "{{ db_password }}"
 
    priv: "{{ db_name }}.*:ALL"
 
    state: present
 
    login_unix_socket: "/var/run/mysqld/mysqld.sock"
 

	
 
- name: Enable backup
 
  include_tasks: backup.yml
 
  ansible.builtin.include_tasks: backup.yml
 
  when: enable_backup
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/database_server/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Restart MariaDB
 
  service:
 
  ansible.builtin.service:
 
    name: mysql
 
    state: restarted
roles/database_server/molecule/default/prepare.yml
Show inline comments
 
@@ -4,13 +4,13 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
roles/database_server/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install MariaDB
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - mariadb-client
 
      - mariadb-server
 
      - python3-pymysql
 
    state: present
 

	
 
- name: Enable and start MariaDB
 
  service:
 
  ansible.builtin.service:
 
    name: mysql
 
    state: started
 
    enabled: true
 

	
 
- name: Set UTF-8 encoding as default for MariaDB
 
  template:
 
  ansible.builtin.template:
 
    src: "utf8.cnf.j2"
 
    dest: "/etc/mysql/mariadb.conf.d/90-utf8.cnf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  register: mariadb_utf8_configuration
 

	
 
- name: Restart MariaDB in order to use UTF-8 as default character set  # noqa no-handler
 
  # [no-handler] Tasks that run when changed should likely be handlers
 
  #   UTF-8 configuration must be applied immediatelly in order to ensure that
 
  #   subsequent tasks that create databases will end-up with correct (UTF-8)
 
  #   encoding. Otherwise they will be created using default latin1.
 
  service:
 
  ansible.builtin.service:
 
    name: mysql
 
    state: restarted
 
  when: mariadb_utf8_configuration.changed
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/ldap_client/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Dummy handler to suppress Ansible warnings
 
  debug:
 
  ansible.builtin.debug:
 
    msg: "This is just a dummy task to suppress the Ansible warning about an empty include."
roles/ldap_client/molecule/default/prepare.yml
Show inline comments
 
@@ -4,13 +4,13 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
roles/ldap_client/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install OpenLDAP client tools
 
  apt:
 
  ansible.builtin.apt:
 
    name: ldap-utils
 
    state: present
 

	
 
- name: Set-up LDAP client configuration directory
 
  file:
 
  ansible.builtin.file:
 
    path: /etc/ldap/
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Deploy LDAP client configuration file
 
  template:
 
  ansible.builtin.template:
 
    src: ldap.conf.j2
 
    dest: /etc/ldap/ldap.conf
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/ldap_server/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Restart slapd
 
  service:
 
  ansible.builtin.service:
 
    name: slapd
 
    state: restarted
roles/ldap_server/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/ldap_server/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
@@ -26,65 +26,65 @@
 
        - name: parameters-mandatory-bookworm_ldap
 
          fqdn: parameters-mandatory
 
        - name: parameters-optional-bookworm_ldap
 
          fqdn: parameters-optional
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /etc/ssl/certs/testca.cert.pem
 
        owner: root
 
        group: root
 
        mode: "0644"
 

	
 
    - name: Remove the ss utility (see https://github.com/philpep/testinfra/pull/320)
 
      file:
 
      ansible.builtin.file:
 
        path: "/bin/ss"
 
        state: absent
 

	
 
    - name: Install tools for testing
 
      apt:
 
      ansible.builtin.apt:
 
        name:
 
          - net-tools
 
          - nmap
 
          - gnutls-bin
 
        state: present
 

	
 
- name: Prepare, helpers
 
  hosts: client
 
  become: true
 
  tasks:
 

	
 
    - name: Install tool for teting TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Set-up /etc/hosts with entries for all servers
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -96,13 +96,13 @@
 
- name: Prepare, test fixtures
 
  hosts: parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -113,13 +113,13 @@
 
- name: Prepare, test fixtures
 
  hosts: parameters-mandatory
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
roles/ldap_server/tasks/backup.yml
Show inline comments
 
---
 

	
 
- name: Create directory for storing LDAP database dumps
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0700"
 
  with_items:
 
    - "/srv/backup"
 

	
 
- name: Deploy script for creating LDAP database backup dumps
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ldapdump.sh"
 
    dest: "/etc/duply/main/pre.d/ldapdump.sh"
 
    owner: root
 
    group: root
 
    mode: "0700"
roles/ldap_server/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Set domain for slapd
 
  debconf:
 
  ansible.builtin.debconf:
 
    name: slapd
 
    question: slapd/domain
 
    vtype: string
 
    value: "{{ ldap_server_domain }}"
 

	
 
- name: Set organisation for slapd
 
  debconf:
 
  ansible.builtin.debconf:
 
    name: slapd
 
    question: shared/organization
 
    vtype: string
 
    value: "{{ ldap_server_organization }}"
 

	
 
- name: Install slapd
 
  apt:
 
  ansible.builtin.apt:
 
    name: slapd
 
    state: present
 

	
 
- name: Allow OpenLDAP user to traverse the directory with TLS private keys
 
  user:
 
  ansible.builtin.user:
 
    name: openldap
 
    append: true
 
    groups: ssl-cert
 
  register: openldap_in_ssl_cert
 

	
 
- name: Restart slapd if group membership has changed (apply immediatelly)  # noqa no-handler
 
  # [no-handler] Tasks that run when changed should likely be handlers
 
  #   In order to be able to change LDAP server TLS configuration, it must be
 
  #   able to read both the private key and certificate. Therefore we need to
 
  #   immediatelly restart (since configuration is done live on the server.
 
  service:
 
  ansible.builtin.service:
 
    name: slapd
 
    state: restarted
 
  when: openldap_in_ssl_cert.changed
 

	
 
- name: Install Python LDAP bindings
 
  apt:
 
  ansible.builtin.apt:
 
    name: python3-pyldap
 
    state: present
 

	
 
- name: Set-up LDAP server to listen on legacy SSL port
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: /etc/default/slapd
 
    state: present
 
    backrefs: true
 
    regexp: '^SLAPD_SERVICES=.*'
 
    line: 'SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"'
 
  notify:
 
    - Restart slapd
 

	
 
- name: Enable and start slapd service
 
  service:
 
  ansible.builtin.service:
 
    name: slapd
 
    state: started
 
    enabled: true
 

	
 
- name: Change log level for slapd
 
  ldap_attr:
 
    dn: cn=config
 
    state: exact
 
    name: olcLogLevel
 
    values: "{{ ldap_server_log_level }}"
 

	
 
- name: Test if LDAP misc schema has been applied
 
  command: "ldapsearch -H ldapi:/// -Q -LLL -A -Y EXTERNAL -b cn=schema,cn=config -s one '(cn={*}misc)' cn"
 
  ansible.builtin.command: "ldapsearch -H ldapi:/// -Q -LLL -A -Y EXTERNAL -b cn=schema,cn=config -s one '(cn={*}misc)' cn"
 
  register: ldap_misc_schema_present
 
  changed_when: false
 

	
 
- name: Deploy LDAP misc schema
 
  command: "ldapadd -H ldapi:/// -Q -Y EXTERNAL -f /etc/ldap/schema/misc.ldif"
 
  ansible.builtin.command: "ldapadd -H ldapi:/// -Q -Y EXTERNAL -f /etc/ldap/schema/misc.ldif"
 
  when: not ldap_misc_schema_present.stdout
 
  changed_when: true  # Always results in change due to task logic.
 

	
 
# Technically, the only thing this does is pick the size of DH
 
# parameters to use, with GnuTLS (against which slapd is linked
 
# against under Debian) picking a matching DH parameter from RFC-7919
 
# (https://www.ietf.org/rfc/rfc7919.txt).
 
- name: Generate the LDAP server Diffie-Hellman parameter
 
  openssl_dhparam:
 
  community.crypto.openssl_dhparam:
 
    owner: root
 
    group: openldap
 
    mode: "0640"
 
    path: "/etc/ssl/private/{{ ansible_fqdn }}_ldap.dh.pem"
 
    size: 2048
 
  notify:
 
    - Restart slapd
 

	
 
- name: Deploy LDAP TLS private key
 
  template:
 
  ansible.builtin.template:
 
    src: "ldap_tls_key.j2"
 
    dest: "/etc/ssl/private/{{ ansible_fqdn }}_ldap.key"
 
    mode: "0640"
 
    owner: root
 
    group: openldap
 
  notify:
 
    - Restart slapd
 

	
 
- name: Deploy LDAP TLS certificate
 
  template:
 
  ansible.builtin.template:
 
    src: "ldap_tls_cert.j2"
 
    dest: "/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem"
 
    mode: "0644"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart slapd
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy:
 
  ansible.builtin.copy:
 
    content: "/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem"
 
    dest: "/etc/check_certificate/{{ ansible_fqdn }}_ldap.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
@@ -190,13 +190,13 @@
 
    dn: "cn=module{0},cn=config"
 
    state: present
 
    name: olcModuleLoad
 
    values: "{1}memberof"
 

	
 
- name: Enable the memberof overlay for database
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config"
 
    objectClass:
 
      - olcConfig
 
      - olcMemberOf
 
      - olcOverlayConfig
 
    attributes:
 
@@ -208,49 +208,49 @@
 
- name: Apply database permissions
 
  m_ldap_permissions:
 
    filter: "(olcSuffix={{ ldap_server_int_basedn }})"
 
    rules: "{{ ldap_permissions }}"
 

	
 
- name: Drop the admin entry corresponding to olcRootDN for database from directory
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "cn=admin,{{ ldap_server_int_basedn }}"
 
    state: absent
 

	
 
- name: Create basic LDAP directory structure
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "ou={{ item }},{{ ldap_server_int_basedn }}"
 
    objectClass:
 
      - organizationalUnit
 
    attributes:
 
      ou: "{{ item }}"
 
  with_items:
 
    - people
 
    - groups
 
    - services
 

	
 
- name: Create the entry that will contain mail service information
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "ou=mail,ou=services,{{ ldap_server_int_basedn }}"
 
    objectClass:
 
      - organizationalUnit
 
    attributes:
 
      ou: mail
 

	
 
- name: Create LDAP directory structure for mail service
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "ou={{ item }},ou=mail,ou=services,{{ ldap_server_int_basedn }}"
 
    objectClass:
 
      - organizationalUnit
 
    attributes:
 
      ou: "{{ item }}"
 
  with_items:
 
    - domains
 
    - aliases
 

	
 
- name: Create or remove login entries for services
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "cn={{ item.name }},ou=services,{{ ldap_server_int_basedn }}"
 
    objectClass:
 
      - applicationProcess
 
      - simpleSecurityObject
 
    attributes:
 
      cn: "{{ item.name }}"
 
@@ -265,54 +265,54 @@
 
    values: "{{ item.password }}"
 
    state: exact
 
  with_items: "{{ ldap_server_consumers }}"
 
  when: "item.state | default('present') == 'present'"
 

	
 
- name: Create or remove user-supplied groups
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "cn={{ item.name }},ou=groups,{{ ldap_server_int_basedn }}"
 
    objectClass:
 
      - groupOfUniqueNames
 
    attributes:
 
      cn: "{{ item.name }}"
 
      uniqueMember: "cn=NONE"
 
    state: "{{ item.state | default('present') }}"
 
  with_items: "{{ ldap_server_groups }}"
 

	
 
- name: Create user-supplied LDAP entries
 
  ldap_entry:
 
  community.general.ldap_entry:
 
    dn: "{{ item.dn }}"
 
    objectClass: "{{ item.attributes.objectClass }}"
 
    attributes: "{{ item.attributes }}"
 
    state: "{{ item.state | default('present') }}"
 
  with_items: "{{ ldap_entries }}"
 

	
 
- name: Deploy firewall configuration for LDAP
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ferm_ldap.conf"
 
    dest: "/etc/ferm/conf.d/10-ldap.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
# @TODO: This whole thing could be dropped if newer version of Ansible
 
#        was in use (where community collection has the ldap_search
 
#        module.
 
- name: Deploy temporary file with LDAP admin password
 
  template:
 
  ansible.builtin.template:
 
    src: "ldap_admin_password.j2"
 
    dest: "/root/.ldap_admin_password"
 
    owner: root
 
    group: root
 
    mode: "0400"
 
  changed_when: false
 

	
 
- name: Test if LDAP admin password needs to be changed
 
  command: "ldapwhoami -H ldapi:/// -D 'cn=admin,{{ ldap_server_int_basedn }}' -x -y /root/.ldap_admin_password"
 
  ansible.builtin.command: "ldapwhoami -H ldapi:/// -D 'cn=admin,{{ ldap_server_int_basedn }}' -x -y /root/.ldap_admin_password"
 
  register: ldap_admin_password_check
 
  changed_when: ldap_admin_password_check.rc != 0
 
  failed_when: false
 

	
 
- name: Update LDAP admin password
 
  ldap_attr:
 
@@ -320,20 +320,20 @@
 
    name: olcRootPW
 
    values: "{{ ldap_admin_password | ldap_password_hash }}"
 
    state: exact
 
  when: ldap_admin_password_check.rc != 0
 

	
 
- name: Remove temporary file with LDAP admin password
 
  file:
 
  ansible.builtin.file:
 
    path: "/root/.ldap_admin_password"
 
    state: absent
 
  changed_when: false
 

	
 
- name: Enable backup
 
  include_tasks: backup.yml
 
  ansible.builtin.include_tasks: backup.yml
 
  when: enable_backup
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/mail_forwarder/handlers/main.yml
Show inline comments
 
@@ -2,12 +2,12 @@
 

	
 
- name: Rebuild mail aliases  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: "/usr/bin/newaliases"
 
  ansible.builtin.command: "/usr/bin/newaliases"
 

	
 
- name: Restart Postfix
 
  service:
 
  ansible.builtin.service:
 
    name: postfix
 
    state: restarted
roles/mail_forwarder/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/mail_forwarder/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
@@ -24,34 +24,34 @@
 
          - "{{ item.fqdn }}"
 
      with_items:
 
        - name: mail-server_smtp
 
          fqdn: mail-server
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -61,33 +61,33 @@
 
        192.168.56.12: "client1"
 
        192.168.56.21: "parameters-mandatory-bookworm"
 
        192.168.56.22: "parameters-optional-bookworm"
 
        192.168.56.23: "parameters-no-incoming-bookworm"
 

	
 
    - name: Install tools for testing
 
      apt:
 
      ansible.builtin.apt:
 
        name: gnutls-bin
 
        state: present
 

	
 
- name: Prepare, helpers
 
  hosts: clients
 
  become: true
 
  tasks:
 

	
 
    - name: Install SWAKS for testing SMTP capability
 
      apt:
 
      ansible.builtin.apt:
 
        name: swaks
 
        state: present
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /usr/local/share/ca-certificates/testca.crt
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
@@ -95,94 +95,94 @@
 

	
 
  handlers:
 

	
 
    - name: Update CA certificate cache  # noqa no-changed-when
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 
      command: /usr/sbin/update-ca-certificates --fresh
 
      ansible.builtin.command: /usr/sbin/update-ca-certificates --fresh
 

	
 
- name: Prepare, helpers
 
  hosts: mail-servers
 
  become: true
 
  tasks:
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /usr/local/share/ca-certificates/testca.crt
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
        - Update CA certificate cache
 

	
 
    - name: Deploy SMTP private key and certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/x509/server/{{ item }}"
 
        dest: "/etc/ssl/{{ item }}"
 
        owner: root
 
        group: root
 
        mode: "0600"
 
      with_items:
 
        - mail-server_smtp.cert.pem
 
        - mail-server_smtp.key.pem
 

	
 
    - name: Install Postfix
 
      apt:
 
      ansible.builtin.apt:
 
        name: "postfix"
 
        state: present
 

	
 
    - name: Purge Exim configuration
 
      apt:
 
      ansible.builtin.apt:
 
        name: "exim4*"
 
        state: absent
 
        purge: true
 

	
 
    - name: Deploy Postfix configuration
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/main.cf
 
        dest: /etc/postfix/main.cf
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
        - Restart Postfix
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Install SWAKS for testing SMTP capability
 
      apt:
 
      ansible.builtin.apt:
 
        name: swaks
 
        state: present
 

	
 
    - name: Set-up port forwarding
 
      command: "iptables -t nat -A PREROUTING -p tcp -m tcp --dport 27 -j REDIRECT --to-ports 25"
 
      ansible.builtin.command: "iptables -t nat -A PREROUTING -p tcp -m tcp --dport 27 -j REDIRECT --to-ports 25"
 
      changed_when: false
 

	
 
  handlers:
 

	
 
    - name: Update CA certificate cache  # noqa no-changed-when
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 
      command: /usr/sbin/update-ca-certificates --fresh
 
      ansible.builtin.command: /usr/sbin/update-ca-certificates --fresh
 

	
 
    - name: Restart Postfix
 
      service:
 
      ansible.builtin.service:
 
        name: postfix
 
        state: restarted
 

	
 
- name: Prepare, test fixtures
 
  hosts: parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Create additional group for testing local aliases
 
      group:
 
      ansible.builtin.group:
 
        name: testuser
 

	
 
    - name: Create additional user for testing local aliases
 
      user:
 
      ansible.builtin.user:
 
        name: testuser
 
        group: testuser
roles/mail_forwarder/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install Postfix
 
  apt:
 
  ansible.builtin.apt:
 
    name: postfix
 
    state: present
 

	
 
- name: Install procmail
 
  apt:
 
  ansible.builtin.apt:
 
    name: procmail
 
    state: present
 

	
 
- name: Purge Exim configuration
 
  apt:
 
  ansible.builtin.apt:
 
    name: "exim4*"
 
    state: absent
 
    purge: true
 

	
 
- name: Deploy the SMTP relay TLS truststore
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ smtp_relay_truststore }}"
 
    dest: "/etc/ssl/certs/smtp_relay_truststore.pem"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Generate the SMTP server Diffie-Hellman parameter
 
  openssl_dhparam:
 
  community.crypto.openssl_dhparam:
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    path: "/etc/ssl/private/{{ ansible_fqdn }}_smtp.dh.pem"
 
    size: 2048
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Configure visible mail name of the system
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ inventory_hostname }}"
 
    dest: "/etc/mailname"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Deploy Postfix main configuration
 
  template:
 
  ansible.builtin.template:
 
    src: "main.cf.j2"
 
    dest: "/etc/postfix/main.cf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Set-up local mail aliases
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/aliases"
 
    line: "{{ item.key }}: {{ item.value }}"
 
    regexp: "^{{ item.key }}"
 
    state: present
 
  with_dict: "{{ local_mail_aliases }}"
 
  notify:
 
    - Rebuild mail aliases
 

	
 
- name: Enable and start postfix service
 
  service:
 
  ansible.builtin.service:
 
    name: postfix
 
    state: started
 
    enabled: true
 

	
 
- name: Retrieve IPv4 addresses of SMTP relay host
 
  shell: "getent ahostsv4 '{{ smtp_relay_host }}' | awk '{ print $1 }' | sort -u"  # noqa risky-shell-pipe
 
  ansible.builtin.shell: "getent ahostsv4 '{{ smtp_relay_host }}' | awk '{ print $1 }' | sort -u"  # noqa risky-shell-pipe
 
  # [risky-shell-pipe] Shells that use pipes should set the pipefail option
 
  #   The getent ahostsv4 command has non-zero exit code if the
 
  #   supplies name cannot be resolved. However, that is a valid
 
  #   use-case for extracting this information. It effectively means
 
  #   that no IPv4 firewall rules will be deployed for allowing
 
  #   incoming connections from the SMTP relay host.
 
  changed_when: false
 
  register: smtp_relay_host_ipv4
 

	
 
- name: Retrieve IPv6 addresses of SMTP relay host
 
  shell: "getent ahostsv6 '{{ smtp_relay_host }}' | awk '{ print $1 }' | grep -v '^::ffff:' | sort -u"  # noqa risky-shell-pipe
 
  ansible.builtin.shell: "getent ahostsv6 '{{ smtp_relay_host }}' | awk '{ print $1 }' | grep -v '^::ffff:' | sort -u"  # noqa risky-shell-pipe
 
  # [risky-shell-pipe] Shells that use pipes should set the pipefail option
 
  #   The getent ahostsv6 command has non-zero exit code if the
 
  #   supplies name cannot be resolved. However, that is a valid
 
  #   use-case for extracting this information. It effectively means
 
  #   that no IPv6 firewall rules will be deployed for allowing
 
  #   incoming connections from the SMTP relay host.
 
  changed_when: false
 
  register: smtp_relay_host_ipv6
 

	
 
- name: Normalise the SMTP relay host IPv4 addresses variable
 
  set_fact:
 
  ansible.builtin.set_fact:
 
    smtp_relay_host_ipv4: "{{ smtp_relay_host_ipv4.stdout_lines | reject('equalto', '') | list }}"
 
  when: "smtp_relay_host | length != 0"
 

	
 
- name: Normalise the SMTP relay host IPv6 addresses variable
 
  set_fact:
 
  ansible.builtin.set_fact:
 
    smtp_relay_host_ipv6: "{{ smtp_relay_host_ipv6.stdout_lines | reject('equalto', '') | list }}"
 
  when: "smtp_relay_host | length != 0"
 

	
 
- name: Deploy firewall configuration for mail forwader
 
  template:
 
  ansible.builtin.template:
 
    src: "ferm_mail.conf.j2"
 
    dest: "/etc/ferm/conf.d/20-mail.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Install SWAKS
 
  apt:
 
  ansible.builtin.apt:
 
    name: swaks
 
    state: present
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/mail_server/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Restart Postfix
 
  service:
 
  ansible.builtin.service:
 
    name: postfix
 
    state: restarted
 

	
 
- name: Restart Dovecot
 
  service:
 
  ansible.builtin.service:
 
    name: dovecot
 
    state: restarted
 

	
 
- name: Restart ClamAV Milter
 
  service:
 
  ansible.builtin.service:
 
    name: clamav-milter
 
    state: restarted
 

	
 
- name: Rebuild mail aliases  # noqa no-changed-when
 
  # [no-changed-when] Commands should not change things if nothing needs doing
 
  #   This task is invoked only if user is very specific about requiring to
 
  #   run the handlers manually as a way to bring the system to consistency
 
  #   after interrupted runs.
 
  command: /usr/bin/newaliases
 
  ansible.builtin.command: /usr/bin/newaliases
roles/mail_server/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/mail_server/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
@@ -36,157 +36,157 @@
 
        - name: parameters-optional-bookworm_imap
 
          fqdn: parameters-optional-bookworm
 
        - name: parameters-optional-bookworm_smtp
 
          fqdn: parameters-optional-bookworm
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Install tools for testing
 
      apt:
 
      ansible.builtin.apt:
 
        name:
 
          - gnutls-bin
 
          - nmap
 
        state: present
 

	
 
- name: Prepare, helpers, local ClamAV database mirror (avoid upstream rate limits)
 
  hosts: clamav-database
 
  become: true
 
  tasks:
 

	
 
    - name: Install system packages for hosting the ClamAV database
 
      apt:
 
      ansible.builtin.apt:
 
        name:
 
          - nginx
 
          - virtualenv
 
        state: present
 

	
 
    - name: Set-up directory for ClamAV database sync tool virtual environment
 
      file:
 
      ansible.builtin.file:
 
        path: /var/lib/cvdupdate
 
        state: directory
 
        owner: vagrant
 
        group: vagrant
 
        mode: "0755"
 

	
 
    - name: Create virtual environment for running ClamAV database sync tool
 
      become: true
 
      become_user: vagrant
 
      command:
 
      ansible.builtin.command:
 
        cmd: "/usr/bin/virtualenv --python /usr/bin/python3 --prompt '(cvdupdate) ' /var/lib/cvdupdate"
 
        creates: "/var/lib/cvdupdate"
 

	
 
    - name: Deploy pip requirements file for running the ClamAV database sync tool
 
      copy:
 
      ansible.builtin.copy:
 
        src: cvdupdate-requirements.txt
 
        dest: /var/lib/cvdupdate/requirements.txt
 
        owner: vagrant
 
        group: vagrant
 
        mode: "0644"
 

	
 
    - name: Install requirements in the pipreqcheck virtual environment
 
      become: true
 
      become_user: vagrant
 
      pip:
 
      ansible.builtin.pip:
 
        requirements: /var/lib/cvdupdate/requirements.txt
 
        virtualenv: /var/lib/cvdupdate
 

	
 
    - name: Allow traversal of Vagrant directory by the http server user
 
      file:
 
      ansible.builtin.file:
 
        path: /vagrant/
 
        mode: "0711"
 

	
 
    - name: Create directory for storing ClamAV database files
 
      file:
 
      ansible.builtin.file:
 
        path: /vagrant/clamav-database
 
        state: directory
 
        owner: vagrant
 
        group: vagrant
 
        mode: "0755"
 

	
 
    - name: Configure default location for storing ClamAV database files  # noqa no-changed-when
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare step.
 
      become: true
 
      become_user: vagrant
 
      command: "/var/lib/cvdupdate/bin/cvd config set --dbdir /vagrant/clamav-database/"
 
      ansible.builtin.command: "/var/lib/cvdupdate/bin/cvd config set --dbdir /vagrant/clamav-database/"
 

	
 
    - name: Download/update the ClamAV database files  # noqa no-changed-when
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 
      become: true
 
      become_user: vagrant
 
      command: "/var/lib/cvdupdate/bin/cvd update"
 
      ansible.builtin.command: "/var/lib/cvdupdate/bin/cvd update"
 

	
 
    - name: Allow all users to read ClamAV database files
 
      file:
 
      ansible.builtin.file:
 
        path: "/vagrant/clamav-database/"
 
        mode: "g=u-w,o=u-w"
 
        recurse: true
 

	
 
    - name: Deploy nginx TLS private key
 
      copy:
 
      ansible.builtin.copy:
 
        dest: "/etc/ssl/private/nginx_https.key"
 
        content: "{{ clamav_database_http_server_tls_key }}"
 
        mode: "0640"
 
        owner: root
 
        group: root
 
      notify:
 
        - Restart nginx
 

	
 
    - name: Deploy nginx TLS certificate
 
      copy:
 
      ansible.builtin.copy:
 
        dest: "/etc/ssl/certs/nginx_https.pem"
 
        content: "{{ clamav_database_http_server_tls_certificate }}"
 
        mode: "0644"
 
        owner: root
 
        group: root
 
      notify:
 
        - Restart nginx
 

	
 
    - name: Deploy nginx configuration for serving the ClamAV database files
 
      copy:
 
      ansible.builtin.copy:
 
        src: clamav-database-nginx.conf
 
        dest: /etc/nginx/sites-available/default
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
        - Restart nginx
 

	
 
  handlers:
 

	
 
    - name: Restart nginx
 
      service:
 
      ansible.builtin.service:
 
        name: nginx
 
        state: restarted
 

	
 
- name: Prepare, test fixtures
 
  hosts: bookworm
 
  become: true
 
  tasks:
 

	
 
    - name: Enable TLSv1.0+ in global OpenSSL configuration file in order to be able to test the web_server_tls_protocols parameter
 
      blockinfile:
 
      ansible.builtin.blockinfile:
 
        path: "/etc/ssl/openssl.cnf"
 
        block: |
 
          [openssl_init]
 
          ssl_conf = ssl_sect
 

	
 
          [ssl_sect]
 
@@ -198,13 +198,13 @@
 
        owner: root
 
        group: root
 
        mode: "0644"
 
        state: present
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -221,39 +221,39 @@
 
- name: Prepare, helpers
 
  hosts: client
 
  become: true
 
  tasks:
 

	
 
    - name: Install tool for testing SMTP capability
 
      apt:
 
      ansible.builtin.apt:
 
        name: swaks
 
        state: present
 

	
 
    - name: Install tool for testing IMAP
 
      block:
 

	
 
        - name: Install required system packages
 
          apt:
 
          ansible.builtin.apt:
 
            name: python3-venv
 
            state: present
 

	
 
        - name: Set-up dedicated Python virtual environment for running the tool
 
          command: "python3 -m venv /opt/imap-cli"
 
          ansible.builtin.command: "python3 -m venv /opt/imap-cli"
 
          args:
 
            creates: /opt/imap-cli/bin/python
 

	
 
        - name: Install IMAP CLI
 
          pip:
 
          ansible.builtin.pip:
 
            name:
 
              - Imap-CLI==0.7
 
              - six
 
            state: present
 
            virtualenv: /opt/imap-cli
 

	
 
        - name: Set-up symlinks for running the tool
 
          file:
 
          ansible.builtin.file:
 
            src: "/opt/imap-cli/bin/{{ item }}"
 
            dest: "/usr/local/bin/{{ item }}"
 
            owner: root
 
            group: root
 
            state: link
 
          with_items:
 
@@ -267,83 +267,83 @@
 
            - imap-cli-status
 
            - imap-cli-search
 
            - imap-cli-read
 
            - imap-cli-list
 

	
 
    - name: Install tool for testing SIEVE
 
      apt:
 
      ansible.builtin.apt:
 
        name: sieve-connect
 
        state: present
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Deploy IMAP CLI configuration
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/{{ item }}"
 
        dest: "/home/vagrant/{{ item }}"
 
        owner: vagrant
 
        group: vagrant
 
        mode: "0600"
 
      with_items:
 
        - imapcli-parameters-mandatory-john_doe.conf
 
        - imapcli-parameters-mandatory-jane_doe.conf
 
        - imapcli-parameters-optional-john_doe.conf
 
        - imapcli-parameters-optional-jane_doe.conf
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /usr/local/share/ca-certificates/testca.crt
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
        - Update CA certificate cache
 

	
 
    - name: Install and configure Postfix for testing mail sending from managed servers
 
      block:
 

	
 
        - name: Install Postfix
 
          apt:
 
          ansible.builtin.apt:
 
            name: postfix
 
            state: present
 

	
 
        - name: Purge Exim
 
          apt:
 
          ansible.builtin.apt:
 
            name: "exim4*"
 
            state: absent
 
            purge: true
 

	
 
        - name: Configure Postfix
 
          template:
 
          ansible.builtin.template:
 
            src: "helper_smtp_main.cf.j2"
 
            dest: "/etc/postfix/main.cf"
 
            owner: root
 
            group: root
 
            mode: "0644"
 
          notify:
 
            - Restart Postfix
 

	
 
        - name: Enable Postfix service
 
          service:
 
          ansible.builtin.service:
 
            name: postfix
 
            state: started
 
            enabled: true
 

	
 
  handlers:
 

	
 
    - name: Update CA certificate cache  # noqa no-changed-when
 
      command: /usr/sbin/update-ca-certificates --fresh
 
      ansible.builtin.command: /usr/sbin/update-ca-certificates --fresh
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 

	
 
    - name: Restart Postfix
 
      service:
 
      ansible.builtin.service:
 
        name: postfix
 
        state: restarted
 

	
 
- name: Prepare, helpers
 
  hosts: ldap-server
 
  become: true
 
@@ -354,13 +354,13 @@
 
- name: Prepare, test fixtures
 
  hosts: ldap-server
 
  become: true
 
  tasks:
 

	
 
    - name: Create LDAP accounts for testing
 
      ldap_entry:
 
      community.general.ldap_entry:
 
        dn: "{{ item.dn }}"
 
        objectClass: "{{ item.objectClass }}"
 
        attributes: "{{ item.attributes }}"
 
      with_items:
 

	
 
        # Users.
 
@@ -433,13 +433,13 @@
 
- name: Prepare, test fixtures
 
  hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Create group for user used for local mail delivery testing
 
      group:
 
      ansible.builtin.group:
 
        name: localuser
 

	
 
    - name: Create user for local mail delivery testing
 
      user:
 
      ansible.builtin.user:
 
        name: localuser
 
        group: localuser
roles/mail_server/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install rsync
 
  apt:
 
  ansible.builtin.apt:
 
    name: rsync
 
    state: present
 

	
 
- name: Install Dovecot packages
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - dovecot-imapd
 
      - dovecot-ldap
 
      - dovecot-sieve
 
      - dovecot-managesieved
 
    state: present
 

	
 
- name: Install Postfix packages
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - postfix
 
      - postfix-ldap
 
    state: present
 

	
 
- name: Purge Exim configuration
 
  apt:
 
  ansible.builtin.apt:
 
    name: "exim4*"
 
    state: absent
 
    purge: true
 

	
 
- name: Allow Postfix user to traverse the directory with TLS private keys
 
  user:
 
  ansible.builtin.user:
 
    name: postfix
 
    append: true
 
    groups: ssl-cert
 

	
 
- name: Allow Dovecot user to traverse the directory with TLS private keys
 
  user:
 
  ansible.builtin.user:
 
    name: dovecot
 
    append: true
 
    groups: ssl-cert
 

	
 
- name: Deploy SMTP TLS private key
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/private/{{ ansible_fqdn }}_smtp.key"
 
    content: "{{ smtp_tls_key }}"
 
    mode: "0640"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Deploy SMTP TLS certificate
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/certs/{{ ansible_fqdn }}_smtp.pem"
 
    content: "{{ smtp_tls_certificate }}"
 
    mode: "0644"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Generate the SMTP server Diffie-Hellman parameter
 
  openssl_dhparam:
 
  community.crypto.openssl_dhparam:
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    path: "/etc/ssl/private/{{ ansible_fqdn }}_smtp.dh.pem"
 
    size: 2048
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Deploy IMAP TLS private key
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/private/{{ ansible_fqdn }}_imap.key"
 
    content: "{{ imap_tls_key }}"
 
    mode: "0640"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Deploy IMAP TLS certificate
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/certs/{{ ansible_fqdn }}_imap.pem"
 
    content: "{{ imap_tls_certificate }}"
 
    mode: "0644"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Generate the IMAP server Diffie-Hellman parameter
 
  openssl_dhparam:
 
  community.crypto.openssl_dhparam:
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    path: "/etc/ssl/private/{{ ansible_fqdn }}_imap.dh.pem"
 
    size: 2048
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Deploy configuration files for checking certificate validity via cron
 
  copy:
 
  ansible.builtin.copy:
 
    content: "/etc/ssl/certs/{{ ansible_fqdn }}_{{ item }}.pem"
 
    dest: "/etc/check_certificate/{{ ansible_fqdn }}_{{ item }}.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  with_items:
 
    - smtp
 
    - imap
 

	
 
- name: Install SWAKS
 
  apt:
 
  ansible.builtin.apt:
 
    name: swaks
 
    state: present
 

	
 
- name: Install milter packages
 
  apt:
 
  ansible.builtin.apt:
 
    name: clamav-milter
 
    state: present
 

	
 
- name: Configure ClamAV Milter
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/clamav/clamav-milter.conf"
 
    src: "clamav-milter.conf"
 
    mode: "0644"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart ClamAV Milter
 

	
 
- name: Set-up privileges for directories within Postfix chroot
 
  file:
 
  ansible.builtin.file:
 
    dest: "{{ item }}"
 
    mode: "0755"
 
    state: directory
 
    owner: root
 
    group: root
 
  with_items:
 
    - /var/spool/postfix/var
 
    - /var/spool/postfix/var/run
 

	
 
- name: Set-up privileges for directories within Postfix chroot
 
  file:
 
  ansible.builtin.file:
 
    dest: "{{ item }}"
 
    state: directory
 
    owner: clamav
 
    group: clamav
 
    mode: "0755"
 
  with_items:
 
    - /var/spool/postfix/var/run/clamav
 

	
 
- name: Deploy the LDAP TLS truststore in default location
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ mail_ldap_tls_truststore }}"
 
    dest: "/etc/ssl/certs/mail_ldap_tls_truststore.pem"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Deploy the LDAP TLS truststore in Postfix chroot
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ mail_ldap_tls_truststore }}"
 
    dest: "/var/spool/postfix/etc/ssl/certs/mail_ldap_tls_truststore.pem"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Configure visible mail name of the system
 
  copy:
 
  ansible.builtin.copy:
 
    content: "{{ inventory_hostname }}"
 
    dest: "/etc/mailname"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Deploy Postfix configurations files for LDAP look-ups
 
  template:
 
  ansible.builtin.template:
 
    src: "{{ item }}.cf.j2"
 
    dest: "/etc/postfix/{{ item }}.cf"
 
    owner: root
 
    group: postfix
 
    mode: "0640"
 
  with_items:
 
@@ -191,141 +191,141 @@
 
    - ldap-virtual-mailbox-domains
 
    - ldap-virtual-mailbox-maps
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Deploy Postfix main configuration
 
  template:
 
  ansible.builtin.template:
 
    src: "main.cf.j2"
 
    dest: "/etc/postfix/main.cf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Set-up local mail aliases
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/aliases"
 
    line: "{{ item.key }}: {{ item.value }}"
 
    regexp: "^{{ item.key }}"
 
    state: present
 
  with_dict: "{{ local_mail_aliases }}"
 
  notify:
 
    - Rebuild mail aliases
 

	
 
- name: Create mail owner group
 
  group:
 
  ansible.builtin.group:
 
    name: "{{ mail_user }}"
 
    gid: "{{ mail_user_gid | default(omit) }}"
 
    state: present
 

	
 
- name: Create mail owner user
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ mail_user }}"
 
    uid: "{{ mail_user_uid | default(omit) }}"
 
    group: "{{ mail_user }}"
 
    home: "/var/{{ mail_user }}"
 
    state: present
 

	
 
- name: Disable Dovecot system authentication
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/dovecot/conf.d/10-auth.conf"
 
    line: "!include auth-system.conf.ext"
 
    state: absent
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Deploy Dovecot configuration file with overrides
 
  template:
 
  ansible.builtin.template:
 
    src: "99-local.conf.j2"
 
    dest: "/etc/dovecot/conf.d/99-local.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Deploy Dovecot configuration file for LDAP look-ups
 
  template:
 
  ansible.builtin.template:
 
    src: "dovecot-ldap.conf.ext.j2"
 
    dest: "/etc/dovecot/dovecot-ldap.conf.ext"
 
    owner: root
 
    group: root
 
    mode: "0600"
 
  notify:
 
    - Restart Dovecot
 

	
 
- name: Deploy Postifx master process configuration
 
  template:
 
  ansible.builtin.template:
 
    src: "master.cf.j2"
 
    dest: "/etc/postfix/master.cf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Postfix
 

	
 
- name: Enable and start ClamAV database update service (freshclam)
 
  service:
 
  ansible.builtin.service:
 
    name: clamav-freshclam
 
    state: started
 
    enabled: true
 

	
 
- name: Check availability of ClamAV database files
 
  stat:
 
  ansible.builtin.stat:
 
    path: "{{ item }}"
 
  with_items:
 
    - /var/lib/clamav/bytecode.cld
 
    - /var/lib/clamav/daily.cld
 
    - /var/lib/clamav/main.cld
 
  register: clamav_db_files
 

	
 
- name: Wait for ClamAV database to be available (up to 10 minutes)
 
  when: not item.stat.exists
 
  with_items: "{{ clamav_db_files.results }}"
 
  wait_for:
 
  ansible.builtin.wait_for:
 
    path: "{{ item.item | replace('.cld', '.cvd') }}"
 
    timeout: 600
 

	
 
- name: Enable and start ClamAV daemon and milter services
 
  service:
 
  ansible.builtin.service:
 
    name: "{{ item }}"
 
    state: started
 
    enabled: true
 
  with_items:
 
    - clamav-daemon
 
    - clamav-milter
 

	
 
# It may take ClamAV a while to read all the necessary database files etc.
 
- name: Wait for ClamAV to become available (up to 5 minutes)
 
  wait_for:
 
  ansible.builtin.wait_for:
 
    path: "/var/run/clamav/clamd.ctl"
 
    timeout: 300
 

	
 
- name: Enable and start Postfix service
 
  service:
 
  ansible.builtin.service:
 
    name: postfix
 
    state: started
 
    enabled: true
 

	
 
- name: Enable and start Dovecot service
 
  service:
 
  ansible.builtin.service:
 
    name: dovecot
 
    state: started
 
    enabled: true
 

	
 
- name: Deploy firewall configuration for mail server
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ferm_mail.conf"
 
    dest: "/etc/ferm/conf.d/20-mail.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/php_website/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Dummy handler to suppress Ansible warnings
 
  debug:
 
  ansible.builtin.debug:
 
    msg: "This is just a dummy task to suppress the Ansible warning about an empty include."
roles/php_website/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/php_website/molecule/default/converge.yml
Show inline comments
 
@@ -54,41 +54,41 @@
 
- name: Converge, application
 
  hosts: all
 
  become: true
 
  tasks:
 
    # parameters-mandatory application
 
    - name: Set-up directory where PHP files are hosted at
 
      file:
 
      ansible.builtin.file:
 
        path: /var/www/parameters-mandatory/htdocs
 
        state: directory
 
        owner: admin-parameters-mandatory
 
        group: web-parameters-mandatory
 
        mode: "0750"
 

	
 
    - name: Deploy a couple of PHP pages for testing purposes
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/php/mandatory/{{ item }}"
 
        dest: "/var/www/parameters-mandatory/htdocs/{{ item }}"
 
        owner: admin-parameters-mandatory
 
        group: web-parameters-mandatory
 
        mode: "0640"
 
      with_items:
 
        - index.php
 
        - index.php3
 

	
 
    # parameters-optional application
 
    - name: Set-up directory where PHP files are hosted at
 
      file:
 
      ansible.builtin.file:
 
        path: /var/www/parameters-optional.local/htdocs
 
        state: directory
 
        owner: admin-parameters-optional_local
 
        group: web-parameters-optional_local
 
        mode: "0750"
 

	
 
    - name: Deploy a couple of PHP pages for testing purposes
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/php/optional/{{ item }}"
 
        dest: "/var/www/parameters-optional.local/htdocs/{{ item }}"
 
        owner: admin-parameters-optional_local
 
        group: web-parameters-optional_local
 
        mode: "0640"
 
      with_items:
roles/php_website/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
@@ -28,95 +28,95 @@
 
        - name: parameters-optional_https
 
          fqdn: parameters-optional.local
 
        - name: php-website_https
 
          fqdn: php-website
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      become: true
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Set-up /etc/hosts entries
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        dest: /etc/hosts
 
        line: "{{ ansible_eth0.ipv4.address }} parameters-mandatory parameters-optional.local php-website"
 

	
 
    - name: Install curl for testing redirects and webpage content
 
      apt:
 
      ansible.builtin.apt:
 
        name: curl
 
        state: present
 

	
 
    - name: Install swaks for testing mail forwarding
 
      apt:
 
      ansible.builtin.apt:
 
        name: swaks
 
        state: present
 

	
 
    - name: Install Postfix for testing mail forwarding (Exim4 not covered)
 
      apt:
 
      ansible.builtin.apt:
 
        name: postfix
 
        state: present
 

	
 
    - name: Install procmail for consistency with mail_server and mail_forwarder roles
 
      apt:
 
      ansible.builtin.apt:
 
        name: procmail
 
        state: present
 

	
 
    - name: Update Postfix configuration
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/postfix/main.cf
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.value }}"
 
        state: present
 
      with_dict:
 
        myhostname: "myhostname = {{ inventory_hostname }}"
 
        mailbox_command: 'mailbox_command = procmail -a "$EXTENSION"'
 
      notify:
 
        - Restart Postfix
 

	
 
    - name: Direct all mails from the root account to vagrant
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/aliases
 
        regexp: "^root"
 
        line: "root: vagrant"
 
        state: present
 
      notify:
 
        - Generate aliases database
 

	
 
    - name: Set-up group for an additional user
 
      group:
 
      ansible.builtin.group:
 
        name: user
 
        state: present
 

	
 
    - name: Set-up additional user for testing mail delivery
 
      user:
 
      ansible.builtin.user:
 
        name: user
 
        group: user
 
        shell: /bin/bash
 

	
 
  handlers:
 

	
 
    - name: Restart Postfix
 
      service:
 
      ansible.builtin.service:
 
        name: postfix
 
        state: restarted
 

	
 
    - name: Generate aliases database  # noqa no-changed-when
 
      command: "/usr/bin/newaliases"
 
      ansible.builtin.command: "/usr/bin/newaliases"
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
roles/php_website/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Create PHP website group
 
  group:
 
  ansible.builtin.group:
 
    name: "{{ user }}"
 
    gid: "{{ uid | default(omit) }}"
 
    state: present
 

	
 
- name: Create PHP website admin user
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ admin }}"
 
    uid: "{{ admin_uid | default(omit) }}"
 
    group: "{{ user }}"
 
    shell: /bin/bash
 
    ansible.builtin.shell: /bin/bash
 
    createhome: true
 
    home: "{{ home }}"
 
    state: present
 

	
 
- name: Set-up directory for storing user profile configuration files
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ home }}/.profile.d"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "0750"
 

	
 
- name: Create PHP website user
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ user }}"
 
    uid: "{{ uid | default(omit) }}"
 
    group: "{{ user }}"
 
    comment: "umask=0007"
 
    system: true
 
    createhome: false
 
    state: present
 
    home: "{{ home }}"
 
    # This is a workaround for a rather stupid bug that Debian seems
 
    # uninterested to backport -
 
    # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=865762
 
    shell: /bin/sh
 
    ansible.builtin.shell: /bin/sh
 

	
 
- name: Add nginx user to website group
 
  user:
 
  ansible.builtin.user:
 
    name: "www-data"
 
    groups: "{{ user }}"
 
    append: "yes"
 
  notify:
 
    - Restart nginx
 

	
 
# Ownership set to root so Postfix would not check if correct user owns the
 
# file.
 
- name: Set-up forwarding for mails delivered to local application user/admin
 
  template:
 
  ansible.builtin.template:
 
    src: "forward.j2"
 
    dest: "{{ home }}/.forward"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: "0640"
 

	
 
- name: Install extra packages for website
 
  apt:
 
  ansible.builtin.apt:
 
    name: "{{ packages }}"
 
    state: present
 

	
 
- name: Deploy PHP FPM configuration file for website
 
  template:
 
  ansible.builtin.template:
 
    src: "fpm_site.conf.j2"
 
    dest: "{{ php_fpm_pool_directory }}/{{ fqdn }}.conf"
 
    validate: "{{ php_fpm_binary }} -t -y %s"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart PHP-FPM
 

	
 
- name: Deploy nginx TLS private key for website
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/private/{{ fqdn }}_https.key"
 
    content: "{{ https_tls_key }}"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy nginx TLS certificate for website
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/certs/{{ fqdn }}_https.pem"
 
    content: "{{ https_tls_certificate }}"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy:
 
  ansible.builtin.copy:
 
    content: "/etc/ssl/certs/{{ fqdn }}_https.pem"
 
    dest: "/etc/check_certificate/{{ fqdn }}_https.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Deploy nginx configuration file for website
 
  template:
 
  ansible.builtin.template:
 
    src: "nginx_site.j2"
 
    dest: "/etc/nginx/sites-available/{{ fqdn }}"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    validate: "/usr/local/bin/nginx_verify_site.sh -n '{{ fqdn }}' %s"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Enable website
 
  file:
 
  ansible.builtin.file:
 
    src: "/etc/nginx/sites-available/{{ fqdn }}"
 
    dest: "/etc/nginx/sites-enabled/{{ fqdn }}"
 
    state: link
 
  notify:
 
    - Restart nginx
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/preseed/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Dummy handler to suppress Ansible warnings
 
  debug:
 
  ansible.builtin.debug:
 
    msg: "This is just a dummy task to suppress the Ansible warning about an empty include."
roles/preseed/molecule/default/prepare.yml
Show inline comments
 
@@ -4,13 +4,13 @@
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
roles/preseed/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Create directory for storing preseed configurations
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ preseed_directory }}"
 
    mode: "0750"
 
    state: directory
 

	
 
- name: Create preseed configuration file
 
  template:
 
  ansible.builtin.template:
 
    src: "preseed.cfg.j2"
 
    dest: "{{ preseed_directory }}/{{ item }}.cfg"
 
    mode: "0640"
 
  when: item != "localhost"
 
  with_items: "{{ groups['all'] }}"
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/web_server/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Reload systemd
 
  systemd:
 
  ansible.builtin.systemd:
 
    daemon_reload: true
 

	
 
- name: Restart nginx
 
  service:
 
  ansible.builtin.service:
 
    name: nginx
 
    state: restarted
 

	
 
- name: Restart PHP-FPM
 
  service:
 
  ansible.builtin.service:
 
    name: "{{ php_fpm_service_name }}"
 
    state: restarted
roles/web_server/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/web_server/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
@@ -26,46 +26,46 @@
 
        - name: parameters-mandatory-bookworm_https
 
          fqdn: parameters-mandatory-bookworm
 
        - name: parameters-optional-bookworm_https
 
          fqdn: parameters-optional-bookworm
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Install tools for testing
 
      apt:
 
      ansible.builtin.apt:
 
        name:
 
          - gnutls-bin
 
          - nmap
 
        state: present
 

	
 
- name: Prepare, test fixtures
 
  hosts: bookworm
 
  become: true
 
  tasks:
 

	
 
    - name: Enable TLSv1.0+ in global OpenSSL configuration file in order to be able to test the web_server_tls_protocols parameter
 
      blockinfile:
 
      ansible.builtin.blockinfile:
 
        path: "/etc/ssl/openssl.cnf"
 
        block: |
 
          [openssl_init]
 
          ssl_conf = ssl_sect
 

	
 
          [ssl_sect]
 
@@ -82,13 +82,13 @@
 
- name: Prepare, test fixtures
 
  hosts: all
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -96,41 +96,41 @@
 
      with_dict:
 
        192.168.56.11: "client"
 
        192.168.56.21: "parameters-mandatory-bookworm"
 
        192.168.56.22: "parameters-optional-bookworm"
 

	
 
    - name: Install curl for testing redirects and webpage content
 
      apt:
 
      ansible.builtin.apt:
 
        name: curl
 
        state: present
 

	
 
- name: Prepare, helpers
 
  hosts: client
 
  become: true
 
  tasks:
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Install console-based web browser for interactive testing
 
      apt:
 
      ansible.builtin.apt:
 
        name: lynx
 
        state: present
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /usr/local/share/ca-certificates/testca.crt
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
        - Update CA certificate cache
 

	
 
  handlers:
 

	
 
    - name: Update CA certificate cache  # noqa no-changed-when
 
      command: /usr/sbin/update-ca-certificates --fresh
 
      ansible.builtin.command: /usr/sbin/update-ca-certificates --fresh
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
roles/web_server/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Install nginx
 
  apt:
 
  ansible.builtin.apt:
 
    name: nginx
 
    state: present
 

	
 
- name: Allow nginx user to traverse the directory with TLS private keys
 
  user:
 
  ansible.builtin.user:
 
    name: www-data
 
    append: true
 
    groups: ssl-cert
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy nginx TLS private key
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/private/{{ ansible_fqdn }}_https.key"
 
    content: "{{ default_https_tls_key }}"
 
    mode: "0640"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy nginx TLS certificate
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/certs/{{ ansible_fqdn }}_https.pem"
 
    content: "{{ default_https_tls_certificate }}"
 
    mode: "0644"
 
    owner: root
 
    group: root
 
  notify:
 
    - Restart nginx
 

	
 
- name: Generate the HTTPS server Diffie-Hellman parameter
 
  openssl_dhparam:
 
  community.crypto.openssl_dhparam:
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    path: "/etc/ssl/private/{{ ansible_fqdn }}_https.dh.pem"
 
    size: 2048
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy:
 
  ansible.builtin.copy:
 
    content: "/etc/ssl/certs/{{ ansible_fqdn }}_https.pem"
 
    dest: "/etc/check_certificate/{{ ansible_fqdn }}_https.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Remove TLS protocol configuration from the main configuration file
 
  lineinfile:
 
  ansible.builtin.lineinfile:
 
    dest: "/etc/nginx/nginx.conf"
 
    backrefs: true
 
    regexp: "^\\s*ssl_protocols"
 
    state: absent
 
  notify:
 
    - Restart nginx
 

	
 
- name: Harden TLS by allowing only TLSv1.2 and PFS ciphers
 
  template:
 
  ansible.builtin.template:
 
    dest: "/etc/nginx/conf.d/tls.conf"
 
    src: "tls.conf.j2"
 
    owner: "root"
 
    group: "root"
 
    mode: "0644"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy script for verification of nginx vhost configurations
 
  copy:
 
  ansible.builtin.copy:
 
    src: "nginx_verify_site.sh"
 
    dest: "/usr/local/bin/nginx_verify_site.sh"
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Deploy default vhost configuration
 
  template:
 
  ansible.builtin.template:
 
    src: "nginx-default.j2"
 
    dest: "/etc/nginx/sites-available/default"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    validate: "/usr/local/bin/nginx_verify_site.sh -n default %s"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Enable default website
 
  file:
 
  ansible.builtin.file:
 
    src: "/etc/nginx/sites-available/default"
 
    dest: "/etc/nginx/sites-enabled/default"
 
    state: link
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy firewall configuration for web server
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ferm_http.conf"
 
    dest: "/etc/ferm/conf.d/30-web.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Remove the default Debian html files
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ item }}"
 
    state: absent
 
  with_items:
 
    - /var/www/html/index.nginx-debian.html
 
    - /var/www/html/
 

	
 
- name: Create directory for storing the default website page
 
  file:
 
  ansible.builtin.file:
 
    path: "/var/www/default/"
 
    state: directory
 
    owner: root
 
    group: www-data
 
    mode: "0750"
 

	
 
- name: Deploy the default index.html
 
  template:
 
  ansible.builtin.template:
 
    src: "index.html.j2"
 
    dest: /var/www/default/index.html
 
    owner: root
 
    group: www-data
 
    mode: "0640"
 

	
 
- name: Enable nginx service
 
  service:
 
  ansible.builtin.service:
 
    name: nginx
 
    enabled: true
 
    state: started
 

	
 
- name: Install base packages for Python web applications
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - python3-setuptools
 
      - virtualenv
 
      - virtualenvwrapper
 
    state: present
 

	
 
- name: Install base packages for PHP web applications
 
  apt:
 
  ansible.builtin.apt:
 
    name: "{{ php_fpm_package_name }}"
 
    state: present
 

	
 
- name: Create directories for storing per-site socket files
 
  file:
 
  ansible.builtin.file:
 
    path: "/run/{{ item }}"
 
    state: directory
 
    owner: root
 
    group: www-data
 
    mode: "0750"
 
  with_items:
 
    - wsgi
 
    - php
 

	
 
- name: Create directories for storing per-site socket files on boot
 
  copy:
 
  ansible.builtin.copy:
 
    content: "d /run/{{ item.socket_dir }}/ 0750 root www-data - -"
 
    dest: "/etc/tmpfiles.d/{{ item.tmpfiles_d }}"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  with_items:
 
    - socket_dir: wsgi
 
      tmpfiles_d: "wsgi.conf"
 
    - socket_dir: php
 
      tmpfiles_d: "{{ php_fpm_service_name }}.conf"
 

	
 
- name: Create directory for storing PHP-FPM service configuration overrides
 
  file:
 
  ansible.builtin.file:
 
    path: "/etc/systemd/system/{{ php_fpm_service_name }}.service.d/"
 
    state: directory
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Configure PHP-FPM service to run with umask 0007
 
  copy:
 
  ansible.builtin.copy:
 
    src: "php_fpm_umask.conf"
 
    dest: "/etc/systemd/system/{{ php_fpm_service_name }}.service.d/umask.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Reload systemd
 
    - Restart PHP-FPM
 

	
 
- name: Enable service used for running PHP web applications
 
  service:
 
  ansible.builtin.service:
 
    name: "{{ php_fpm_service_name }}"
 
    enabled: true
 
    state: started
 

	
 
- name: Read timezone on server
 
  slurp:
 
  ansible.builtin.slurp:
 
    src: "/etc/timezone"
 
  register: server_timezone
 

	
 
- name: Configure timezone for PHP
 
  template:
 
  ansible.builtin.template:
 
    src: "php_timezone.ini.j2"
 
    dest: "{{ item }}/30-timezone.ini"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  with_items:
 
    - "{{ php_base_config_dir }}/cli/conf.d/"
 
    - "{{ php_base_config_dir }}/fpm/conf.d/"
 
  notify:
 
    - Restart PHP-FPM
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/wsgi_website/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Restart WSGI services
 
  service:
 
  ansible.builtin.service:
 
    name: "{{ item }}"
 
    state: restarted
 
  with_items: "{{ wsgi_services_to_restart }}"
roles/wsgi_website/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/wsgi_website/molecule/default/converge.yml
Show inline comments
 
@@ -94,129 +94,129 @@
 
- name: Converge, application
 
  hosts: wsgi-website
 
  become: true
 
  tasks:
 
    # parameters-mandatory application
 
    - name: Set-up directories where application files are hosted at
 
      file:
 
      ansible.builtin.file:
 
        path: "/var/www/parameters-mandatory/{{ item }}"
 
        state: directory
 
        owner: admin-parameters-mandatory
 
        group: web-parameters-mandatory
 
        mode: "02750"
 
      with_items:
 
        - htdocs/static
 
        - htdocs/media
 
        - code
 
    - name: Deploy WSGI application
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/python/wsgi/testapp.py"
 
        dest: "/var/www/parameters-mandatory/code/testapp.py"
 
        owner: admin-parameters-mandatory
 
        group: web-parameters-mandatory
 
        mode: "0640"
 
      notify:
 
        - Restart parameters-mandatory
 
    - name: Deploy a static file
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/static_file.txt"
 
        dest: "/var/www/parameters-mandatory/htdocs/static/static_file.txt"
 
        owner: admin-parameters-mandatory
 
        group: web-parameters-mandatory
 
        mode: "0640"
 
    - name: Deploy a media file
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/media_file.txt"
 
        dest: "/var/www/parameters-mandatory/htdocs/media/media_file.txt"
 
        owner: admin-parameters-mandatory
 
        group: web-parameters-mandatory
 
        mode: "0640"
 

	
 
    # parameters-optional application
 
    - name: Set-up directories where application files are hosted at
 
      file:
 
      ansible.builtin.file:
 
        path: "/var/www/parameters-optional.local/{{ item }}"
 
        state: directory
 
        owner: admin-parameters-optional_local
 
        group: web-parameters-optional_local
 
        mode: "02750"
 
      with_items:
 
        - htdocs/static
 
        - htdocs/media
 
        - code
 
    - name: Deploy WSGI application
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/python/wsgi/testapp.py"
 
        dest: "/var/www/parameters-optional.local/code/testapp.py"
 
        owner: admin-parameters-optional_local
 
        group: web-parameters-optional_local
 
        mode: "0640"
 
      notify:
 
        - Restart parameters-optional.local
 
    - name: Deploy a static file
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/static_file.txt"
 
        dest: "/var/www/parameters-optional.local/htdocs/static/static_file.txt"
 
        owner: admin-parameters-optional_local
 
        group: web-parameters-optional_local
 
        mode: "0640"
 
    - name: Deploy a media file
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/media_file.txt"
 
        dest: "/var/www/parameters-optional.local/htdocs/media/media_file.txt"
 
        owner: admin-parameters-optional_local
 
        group: web-parameters-optional_local
 
        mode: "0640"
 

	
 
    # parameters-paste-req application
 
    - name: Set-up directories where application files are hosted at
 
      file:
 
      ansible.builtin.file:
 
        path: "/var/www/parameters-paste-req/{{ item }}"
 
        state: directory
 
        owner: admin-parameters-paste-req
 
        group: web-parameters-paste-req
 
        mode: "02750"
 
      with_items:
 
        - htdocs/static
 
        - htdocs/media
 
        - code
 
    - name: Deploy WSGI application
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/python/paste/{{ item }}"
 
        dest: "/var/www/parameters-paste-req/code/{{ item }}"
 
        owner: admin-parameters-paste-req
 
        group: web-parameters-paste-req
 
        mode: "0640"
 
      with_items:
 
        - config.ini
 
        - testapp.py
 
        - wsgi.py
 
      notify:
 
        - Restart parameters-paste-req
 
    - name: Deploy a static file
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/static_file.txt"
 
        dest: "/var/www/parameters-paste-req/htdocs/static/static_file.txt"
 
        owner: admin-parameters-paste-req
 
        group: web-parameters-paste-req
 
        mode: "0640"
 
    - name: Deploy a media file
 
      copy:
 
      ansible.builtin.copy:
 
        src: "tests/data/media_file.txt"
 
        dest: "/var/www/parameters-paste-req/htdocs/media/media_file.txt"
 
        owner: admin-parameters-paste-req
 
        group: web-parameters-paste-req
 
        mode: "0640"
 

	
 
  handlers:
 
    - name: Restart parameters-mandatory
 
      service:
 
      ansible.builtin.service:
 
        name: parameters-mandatory
 
        state: restarted
 
    - name: Restart parameters-optional.local
 
      service:
 
      ansible.builtin.service:
 
        name: parameters-optional.local
 
        state: restarted
 
    - name: Restart parameters-paste-req
 
      service:
 
      ansible.builtin.service:
 
        name: parameters-paste-req
 
        state: restarted
roles/wsgi_website/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
@@ -30,109 +30,109 @@
 
        - name: parameters-paste-req_https
 
          fqdn: parameters-paste-req
 
        - name: wsgi-website_https
 
          fqdn: wsgi-website
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Remove the ss utility (see https://github.com/philpep/testinfra/pull/320)
 
      file:
 
      ansible.builtin.file:
 
        path: "/bin/ss"
 
        state: absent
 

	
 
- name: Prepare, test fixtures
 
  hosts: wsgi-website
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up /etc/hosts entries
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        dest: /etc/hosts
 
        line: "{{ ansible_eth0.ipv4.address }} parameters-mandatory parameters-optional.local parameters-paste-req wsgi-website"
 

	
 
    - name: Install curl for testing redirects and webpage content
 
      apt:
 
      ansible.builtin.apt:
 
        name: curl
 
        state: present
 

	
 
    - name: Install swaks for testing mail forwarding
 
      apt:
 
      ansible.builtin.apt:
 
        name: swaks
 
        state: present
 

	
 
    - name: Install net-tools for testing sockets
 
      apt:
 
      ansible.builtin.apt:
 
        name: net-tools
 
        state: present
 

	
 
    - name: Install Postfix for testing mail forwarding (Exim4 not covered)
 
      apt:
 
      ansible.builtin.apt:
 
        name: postfix
 
        state: present
 

	
 
    - name: Install procmail for consistency with mail_server and mail_forwarder roles
 
      apt:
 
      ansible.builtin.apt:
 
        name: procmail
 
        state: present
 

	
 
    - name: Update Postfix configuration
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/postfix/main.cf
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.value }}"
 
        state: present
 
      with_dict:
 
        myhostname: "myhostname = {{ inventory_hostname }}"
 
        mailbox_command: 'mailbox_command = procmail -a "$EXTENSION"'
 
      notify:
 
        - Restart Postfix
 

	
 
    - name: Direct all mails from the root account to vagrant
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/aliases
 
        regexp: "^root"
 
        line: "root: vagrant"
 
        state: present
 
      notify:
 
        - Generate aliases database
 

	
 
    - name: Set-up group for an additional user
 
      group:
 
      ansible.builtin.group:
 
        name: user
 
        state: present
 

	
 
    - name: Set-up additional user for testing mail delivery
 
      user:
 
      ansible.builtin.user:
 
        name: user
 
        group: user
 
        shell: /bin/bash
 

	
 
  handlers:
 

	
 
    - name: Restart Postfix
 
      service:
 
      ansible.builtin.service:
 
        name: postfix
 
        state: restarted
 

	
 
    - name: Generate aliases database  # noqa no-changed-when
 
      command: "/usr/bin/newaliases"
 
      ansible.builtin.command: "/usr/bin/newaliases"
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
roles/wsgi_website/tasks/main.yml
Show inline comments
 
---
 

	
 
- name: Create WSGI website group
 
  group:
 
  ansible.builtin.group:
 
    name: "{{ user }}"
 
    gid: "{{ uid | default(omit) }}"
 
    state: present
 

	
 
- name: Create WSGI website admin user
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ admin }}"
 
    uid: "{{ admin_uid | default(omit) }}"
 
    group: "{{ user }}"
 
    shell: /bin/bash
 
    ansible.builtin.shell: /bin/bash
 
    createhome: true
 
    home: "{{ home }}"
 
    state: present
 

	
 
- name: Set-up directory for storing user profile configuration files
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ home }}/.profile.d"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "0750"
 

	
 
- name: Deploy profile configuration file for auto-activating the virtual environment
 
  copy:
 
  ansible.builtin.copy:
 
    src: "profile_virtualenv.sh"
 
    dest: "{{ home }}/.profile.d/virtualenv.sh"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: "0640"
 

	
 
- name: Deploy profile configuration file for setting environment variables
 
  template:
 
  ansible.builtin.template:
 
    src: "environment.sh.j2"
 
    dest: "{{ home }}/.profile.d/environment.sh"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: "0640"
 

	
 
- name: Create WSGI website user
 
  user:
 
  ansible.builtin.user:
 
    name: "{{ user }}"
 
    uid: "{{ uid | default(omit) }}"
 
    group: "{{ user }}"
 
    comment: "umask=0007"
 
    system: true
 
    createhome: false
 
    state: present
 
    home: "{{ home }}"
 
    # This is a workaround for a rather stupid bug that Debian seems
 
    # uninterested to backport -
 
    # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=865762
 
    shell: /bin/sh
 
    ansible.builtin.shell: /bin/sh
 

	
 
- name: Add nginx user to website group
 
  user:
 
  ansible.builtin.user:
 
    name: www-data
 
    groups: "{{ user }}"
 
    append: true
 
  notify:
 
    - Restart nginx
 

	
 
# Ownership set to root so Postfix would not check if correct user owns the
 
# file.
 
- name: Set-up forwarding for mails delivered to local application user/admin
 
  template:
 
  ansible.builtin.template:
 
    src: "forward.j2"
 
    dest: "{{ home }}/.forward"
 
    owner: root
 
    group: "{{ user }}"
 
    mode: "0640"
 

	
 
- name: Install extra packages for website
 
  apt:
 
  ansible.builtin.apt:
 
    name: "{{ packages }}"
 
    state: present
 
  register: install_extra_packages
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Retrieve requested Python interpreter version
 
  command:
 
  ansible.builtin.command:
 
    argv:
 
      - "{{ python_interpreter }}"
 
      - "-c"
 
      - "import sys; print(sys.version.split(' ')[0])"
 
  changed_when: false
 
  register: python_interpreter_version
 

	
 
- name: Retrieve virtual environment Python interpreter version (if initialised)
 
  command:
 
  ansible.builtin.command:
 
    argv:
 
      - "{{ home }}/virtualenv/bin/python"
 
      - "-c"
 
      - "import sys; print(sys.version.split(' ')[0])"
 
  # Virtual environment perhaps does not exist.
 
  failed_when: false
 
  changed_when: false
 
  register: virtualenv_python_version
 

	
 
- name: Retrieve virtual environment prompt
 
  command:
 
  ansible.builtin.command:
 
    argv:
 
      - "bash"
 
      - "-c"
 
      - "source '{{ home }}/virtualenv/bin/activate'; printenv PS1"
 
  failed_when: false
 
  changed_when: false
 
  register: current_virtualenv_prompt
 

	
 
- name: Remove virtual environment in case of mismatches
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ home }}/virtualenv"
 
    state: absent
 
  when: |
 
    virtualenv_python_version.rc != 0 or
 
    virtualenv_python_version.stdout.strip() != python_interpreter_version.stdout.strip() or
 
    current_virtualenv_prompt.stdout != "(" + fqdn + ") "
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Create directory for storing the Python virtual environment
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ home }}/virtualenv"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "02750"
 

	
 
- name: Create Python virtual environment
 
  command: '/usr/bin/virtualenv --python "{{ python_interpreter }}" --prompt "{{ virtualenv_prompt }}" "{{ home }}/virtualenv"'
 
  ansible.builtin.command: '/usr/bin/virtualenv --python "{{ python_interpreter }}" --prompt "{{ virtualenv_prompt }}" "{{ home }}/virtualenv"'
 
  args:
 
    creates: "{{ home }}/virtualenv/bin/{{ python_interpreter | basename }}"
 
  become: true
 
  become_user: "{{ admin }}"
 

	
 
- name: Configure project directory for the Python virtual environment
 
  template:
 
  ansible.builtin.template:
 
    src: "venv_project.j2"
 
    dest: "{{ home }}/virtualenv/.project"
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "0640"
 

	
 
- name: Deploy virtualenv wrapper
 
  template:
 
  ansible.builtin.template:
 
    src: "venv_exec.j2"
 
    dest: "{{ home }}/virtualenv/bin/exec"
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "0750"
 

	
 
- name: Set-up directory for storing requirements file for upgrade checks
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ pip_check_requirements_upgrades_directory }}/{{ fqdn }}"
 
    state: directory
 
    owner: root
 
    group: pipreqcheck
 
    mode: "0750"
 

	
 
- name: Deploy WSGI requirements files for upgrade checks
 
  template:
 
  ansible.builtin.template:
 
    src: "{{ item }}.j2"
 
    dest: "{{ pip_check_requirements_upgrades_directory }}/{{ fqdn }}/{{ item }}"
 
    owner: root
 
    group: pipreqcheck
 
    mode: "0640"
 
  with_items:
 
    - wsgi_requirements.in
 
    - wsgi_requirements.txt
 

	
 
- name: Deploy Gunicorn requirements file for installation purposes
 
  template:
 
  ansible.builtin.template:
 
    src: "wsgi_requirements.txt.j2"
 
    dest: "{{ home }}/.wsgi_requirements.txt"
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "0640"
 

	
 
- name: Install Gunicorn via requirements file
 
  become: true
 
  become_user: "{{ admin }}"
 
  pip:
 
  ansible.builtin.pip:
 
    requirements: "{{ home }}/.wsgi_requirements.txt"
 
    state: present
 
    virtualenv: "{{ home }}/virtualenv"
 
  register: install_gunicorn_via_requirements
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Install additional packages in Python virtual environment
 
  become: true
 
  become_user: "{{ admin }}"
 
  pip:
 
  ansible.builtin.pip:
 
    name: "{{ virtualenv_packages }}"
 
    state: present
 
    virtualenv: "{{ home }}/virtualenv"
 
  register: install_additional_packages_in_virtualenv
 
  when: virtualenv_packages | length > 0
 
  notify:
 
    - Restart WSGI services
 

	
 
- name: Deploy systemd socket configuration for website
 
  template:
 
  ansible.builtin.template:
 
    src: "systemd_wsgi_website.socket.j2"
 
    dest: "/etc/systemd/system/{{ fqdn }}.socket"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  register: deploy_systemd_socket_configuration
 
  notify:
 
    - Reload systemd
 
    - Restart WSGI services
 

	
 
- name: Deploy systemd service configuration for website
 
  template:
 
  ansible.builtin.template:
 
    src: "systemd_wsgi_website.service.j2"
 
    dest: "/etc/systemd/system/{{ fqdn }}.service"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  register: deploy_systemd_service_configuration
 
  notify:
 
    - Reload systemd
 
    - Restart WSGI services
 

	
 
- name: Enable the website service
 
  service:
 
  ansible.builtin.service:
 
    name: "{{ fqdn }}"
 
    enabled: true
 
    state: started
 

	
 
- name: Create directory where static files can be served from
 
  file:
 
  ansible.builtin.file:
 
    path: "{{ home }}/htdocs/"
 
    state: directory
 
    owner: "{{ admin }}"
 
    group: "{{ user }}"
 
    mode: "02750"
 

	
 
- name: Deploy nginx TLS private key for website
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/private/{{ fqdn }}_https.key"
 
    content: "{{ https_tls_key }}"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy nginx TLS certificate for website
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/certs/{{ fqdn }}_https.pem"
 
    content: "{{ https_tls_certificate }}"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy:
 
  ansible.builtin.copy:
 
    content: "/etc/ssl/certs/{{ fqdn }}_https.pem"
 
    dest: "/etc/check_certificate/{{ fqdn }}_https.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Deploy nginx configuration file for website
 
  template:
 
  ansible.builtin.template:
 
    src: "nginx_site.j2"
 
    dest: "/etc/nginx/sites-available/{{ fqdn }}"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
    validate: "/usr/local/bin/nginx_verify_site.sh -n '{{ fqdn }}' %s"
 
  notify:
 
    - Restart nginx
 

	
 
- name: Enable nginx website
 
  file:
 
  ansible.builtin.file:
 
    src: "/etc/nginx/sites-available/{{ fqdn }}"
 
    dest: "/etc/nginx/sites-enabled/{{ fqdn }}"
 
    state: link
 
  notify:
 
    - Restart nginx
 

	
 
- name: Set-up empty list of WSGI services to restart
 
  set_fact:
 
  ansible.builtin.set_fact:
 
    wsgi_services_to_restart: []
 
  when: "wsgi_services_to_restart is not defined"
 
  tags:
 
    - handlers
 

	
 
- name: Add service to list of WSGI services to restart  # noqa no-handler
 
  # [no-handler] Tasks that run when changed should likely be handlers
 
  #   This specific task is used in order to work around inability of Ansible
 
  #   to provide properly parametrised handlers for reusable roles.
 
  set_fact:
 
  ansible.builtin.set_fact:
 
    wsgi_services_to_restart: "{{ wsgi_services_to_restart + [fqdn] }}"
 
  when: |
 
    fqdn not in wsgi_services_to_restart and
 
    ((install_extra_packages is defined and install_extra_packages.changed) or
 
    (install_additional_packages_in_virtualenv is defined and install_additional_packages_in_virtualenv.changed) or
 
    (deploy_systemd_socket_configuration is defined and deploy_systemd_socket_configuration.changed) or
 
@@ -310,10 +310,10 @@
 
    (install_gunicorn_via_requirements is defined and install_gunicorn_via_requirements.changed) or
 
    (run_handlers | default(False) | bool()))
 
  tags:
 
    - handlers
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/xmpp_server/handlers/main.yml
Show inline comments
 
---
 

	
 
- name: Restart Prosody
 
  service:
 
  ansible.builtin.service:
 
    name: prosody
 
    state: restarted
roles/xmpp_server/molecule/default/cleanup.yml
Show inline comments
 
@@ -4,12 +4,12 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Remove X.509 material
 
      file:
 
      ansible.builtin.file:
 
        path: "{{ item }}"
 
        state: absent
 
      with_items:
 
        - "tests/data/x509"
 
        - "tests/data/.gimmecert"
roles/xmpp_server/molecule/default/prepare.yml
Show inline comments
 
@@ -4,19 +4,19 @@
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      ansible.builtin.command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      ansible.builtin.command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv: "{{ ['gimmecert', 'server', item.name] + item.fqdn }}"
 
      with_items:
 
        - name: ldap-server_ldap
 
@@ -37,53 +37,53 @@
 
            - conference.domain2
 
            - domain3
 
            - proxy.domain3
 
            - conference.domain3
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
      ansible.builtin.file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  become: true
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      ansible.builtin.raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      become: true
 
      changed_when: false
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
      ansible.builtin.apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Install tools for testing
 
      apt:
 
      ansible.builtin.apt:
 
        name:
 
          - gnutls-bin
 
          - nmap
 
        state: present
 

	
 
    - name: Use name provided via CLI when running STARTTLS handshake for XMPP via nmap
 
      replace:
 
      ansible.builtin.replace:
 
        path: "/usr/share/nmap/nselib/sslcert.lua"
 
        regexp: "host\\.name\\)"
 
        replace: "host.targetname)"
 

	
 
- name: Prepare, test fixtures
 
  hosts: bookworm
 
  become: true
 
  tasks:
 

	
 
    - name: Enable TLSv1.0+ in global OpenSSL configuration file in order to be able to test the web_server_tls_protocols parameter
 
      blockinfile:
 
      ansible.builtin.blockinfile:
 
        path: "/etc/ssl/openssl.cnf"
 
        block: |
 
          [openssl_init]
 
          ssl_conf = ssl_sect
 

	
 
          [ssl_sect]
 
@@ -95,13 +95,13 @@
 
        owner: root
 
        group: root
 
        mode: "0644"
 
        state: present
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
      ansible.builtin.lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: "0644"
 
@@ -115,49 +115,49 @@
 
- name: Prepare, helpers
 
  hosts: clients
 
  become: true
 
  tasks:
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
      ansible.builtin.apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
      ansible.builtin.copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /usr/local/share/ca-certificates/testca.crt
 
        owner: root
 
        group: root
 
        mode: "0644"
 
      notify:
 
        - Update CA certificate cache
 

	
 
    - name: Install console-based XMPP client (for interactive testing)
 
      apt:
 
      ansible.builtin.apt:
 
        name: mcabber
 
        state: present
 

	
 
    - name: Install console-based XMPP tool (for non-interactive testing)
 
      apt:
 
      ansible.builtin.apt:
 
        name: go-sendxmpp
 
        state: present
 

	
 
    - name: Create dedicated group for testing
 
      group:
 
      ansible.builtin.group:
 
        name: user
 
        state: present
 

	
 
    - name: Create dedicated user for testing
 
      user:
 
      ansible.builtin.user:
 
        name: user
 
        group: user
 
        shell: /bin/bash
 
        ansible.builtin.shell: /bin/bash
 

	
 
    - name: Deploy mcabber configuration files
 
      template:
 
      ansible.builtin.template:
 
        src: tests/data/mcabber.cfg.j2
 
        dest: "~user/{{ item.jid }}.cfg"
 
        owner: user
 
        group: user
 
        mode: "0600"
 
      with_items:
 
@@ -182,13 +182,13 @@
 
          security: tls
 
          nickname: noxmpp
 

	
 
  handlers:
 

	
 
    - name: Update CA certificate cache  # noqa no-changed-when
 
      command: /usr/sbin/update-ca-certificates --fresh
 
      ansible.builtin.command: /usr/sbin/update-ca-certificates --fresh
 
      # [no-changed-when] Commands should not change things if nothing needs doing
 
      #   Does not matter in test prepare stage.
 

	
 
- name: Prepare, helpers
 
  hosts: ldap-server
 
  become: true
 
@@ -199,13 +199,13 @@
 
- name: Prepare, test fixtures
 
  hosts: ldap-server
 
  become: true
 
  tasks:
 

	
 
    - name: Create LDAP accounts for testing
 
      ldap_entry:
 
      community.general.ldap_entry:
 
        dn: "{{ item.dn }}"
 
        objectClass: "{{ item.objectClass }}"
 
        attributes: "{{ item.attributes }}"
 
      with_items:
 
        - dn: uid=john,ou=people,dc=local
 
          objectClass:
 
@@ -265,19 +265,19 @@
 
- name: Prepare, test fixtures
 
  hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Install console-based XMPP tool (for non-interactive testing)
 
      apt:
 
      ansible.builtin.apt:
 
        name: "{{ sendxmpp_package }}"
 
        state: present
 
      vars:
 
        sendxmpp_package: "go-sendxmpp"
 

	
 
    - name: Deploy small Lua script for listing the enabled modules in Prosody
 
      copy:
 
      ansible.builtin.copy:
 
        src: list_prosody_modules.lua
 
        dest: "/usr/local/bin/list_prosody_modules.lua"
 
        owner: root
 
        group: root
 
        mode: "0755"
roles/xmpp_server/tasks/main.yml
Show inline comments
 
---
 

	
 
# Main implementation
 
# ===================
 

	
 
- name: Set-up the Debian backports repository
 
  template:
 
  ansible.builtin.template:
 
    src: backports.list.j2
 
    dest: /etc/apt/sources.list.d/backports.list
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  register: backports_repository_configuration
 
@@ -15,127 +15,127 @@
 
- name: Update apt cache if backports repository configuration changed (for immediate use)  # noqa no-handler
 
  # [no-handler] Tasks that run when changed should likely be handlers
 
  #   Since apt_repository module is not reliable (does not deploy
 
  #   change when changing distro version etc), we have to use
 
  #   template instead, but this also means we need to trigger the apt
 
  #   cache reload by hand.
 
  apt:
 
  ansible.builtin.apt:
 
    update_cache: true
 
  when: backports_repository_configuration.changed
 

	
 
- name: Install additional Prosody dependencies
 
  apt:
 
  ansible.builtin.apt:
 
    name:
 
      - lua-ldap
 
      - prosody-modules
 
    state: present
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Install Prosody
 
  apt:
 
  ansible.builtin.apt:
 
    name: prosody
 
    state: present
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Allow Prosody user to traverse the directory with TLS private keys
 
  user:
 
  ansible.builtin.user:
 
    name: prosody
 
    append: true
 
    groups: ssl-cert
 

	
 
- name: Deploy XMPP TLS private key
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.key"
 
    content: "{{ xmpp_tls_key }}"
 
    owner: root
 
    group: prosody
 
    mode: "0640"
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Deploy XMPP TLS certificate
 
  copy:
 
  ansible.builtin.copy:
 
    dest: "/etc/ssl/certs/{{ ansible_fqdn }}_xmpp.pem"
 
    content: "{{ xmpp_tls_certificate }}"
 
    owner: root
 
    group: root
 
    mode: "0644"
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Generate the XMPP server Diffie-Hellman parameter
 
  openssl_dhparam:
 
  community.crypto.openssl_dhparam:
 
    owner: root
 
    group: prosody
 
    mode: "0640"
 
    path: "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.dh.pem"
 
    size: 2048
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Deploy configuration file for checking certificate validity via cron
 
  copy:
 
  ansible.builtin.copy:
 
    content: "/etc/ssl/certs/{{ ansible_fqdn }}_xmpp.pem"
 
    dest: "/etc/check_certificate/{{ ansible_fqdn }}_xmpp.conf"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Deploy script for validating Prosody certificate
 
  copy:
 
  ansible.builtin.copy:
 
    src: "check_prosody_certificate.sh"
 
    dest: "/usr/local/bin/check_prosody_certificate.sh"
 
    owner: root
 
    group: root
 
    mode: "0755"
 

	
 
- name: Set-up crontab task that runs the Prosody certificate checker script once a day
 
  copy:
 
  ansible.builtin.copy:
 
    src: "cron_check_prosody_certificate"
 
    dest: "/etc/cron.d/check_prosody_certificate"
 
    owner: root
 
    group: root
 
    mode: "0644"
 

	
 
- name: Deploy LDAP client configuration (for validating LDAP server certificate)
 
  copy:
 
  ansible.builtin.copy:
 
    src: prosody_ldaprc
 
    dest: "/var/lib/prosody/.ldaprc"
 
    owner: root
 
    group: prosody
 
    mode: "0640"
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Deploy Prosody configuration file
 
  template:
 
  ansible.builtin.template:
 
    src: "prosody.cfg.lua.j2"
 
    dest: "/etc/prosody/prosody.cfg.lua"
 
    owner: root
 
    group: prosody
 
    mode: "0640"
 
  notify:
 
    - Restart Prosody
 

	
 
- name: Enable and start Prosody service
 
  service:
 
  ansible.builtin.service:
 
    name: prosody
 
    state: started
 
    enabled: true
 

	
 
- name: Deploy firewall configuration for XMPP server
 
  copy:
 
  ansible.builtin.copy:
 
    src: "ferm_xmpp.conf"
 
    dest: "/etc/ferm/conf.d/30-xmpp.conf"
 
    owner: root
 
    group: root
 
    mode: "0640"
 
  notify:
 
    - Restart ferm
 

	
 
- name: Explicitly run all handlers
 
  include_tasks: ../handlers/main.yml
 
  ansible.builtin.include_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
0 comments (0 inline, 0 general)