From efad1b9a677f1d06615bfd4d1e7d25a29c74d16b Mon Sep 17 00:00:00 2001 From: Sandwich Date: Fri, 26 Dec 2025 20:38:42 +0100 Subject: [PATCH] Configuration role refactor and network template --- roles/configuration/tasks/bootloader.yml | 65 +++++ roles/configuration/tasks/extras.yml | 69 +++++ roles/configuration/tasks/fstab.yml | 65 +++++ roles/configuration/tasks/locales.yml | 88 ++++++ roles/configuration/tasks/main.yml | 339 ++--------------------- roles/configuration/tasks/network.yml | 96 +++++++ roles/configuration/tasks/selinux.yml | 19 ++ roles/configuration/tasks/services.yml | 14 + roles/configuration/tasks/sudo.yml | 7 + roles/configuration/tasks/users.yml | 37 +++ roles/configuration/templates/network.j2 | 29 +- 11 files changed, 498 insertions(+), 330 deletions(-) create mode 100644 roles/configuration/tasks/bootloader.yml create mode 100644 roles/configuration/tasks/extras.yml create mode 100644 roles/configuration/tasks/fstab.yml create mode 100644 roles/configuration/tasks/locales.yml create mode 100644 roles/configuration/tasks/network.yml create mode 100644 roles/configuration/tasks/selinux.yml create mode 100644 roles/configuration/tasks/services.yml create mode 100644 roles/configuration/tasks/sudo.yml create mode 100644 roles/configuration/tasks/users.yml diff --git a/roles/configuration/tasks/bootloader.yml b/roles/configuration/tasks/bootloader.yml new file mode 100644 index 0000000..59a8c57 --- /dev/null +++ b/roles/configuration/tasks/bootloader.yml @@ -0,0 +1,65 @@ +--- +- name: Configure Bootloader + block: + - name: Install Bootloader + vars: + configuration_use_efibootmgr: "{{ is_rhel | default(false) }}" + configuration_efi_dir: >- + {{ "/boot/efi" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot" }} + configuration_bootloader_id: >- + {{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }} + configuration_efi_vendor: >- + {{ "redhat" if os | lower in ["rhel8", "rhel9", "rhel10"] else os | lower }} + configuration_efibootmgr_cmd: >- + /usr/sbin/efibootmgr -c -L '{{ os }}' -d "{{ install_drive }}" -p 1 + -l '\efi\EFI\{{ configuration_efi_vendor }}\shimx64.efi' + configuration_grub_cmd: >- + /usr/sbin/grub-install --target=x86_64-efi + --efi-directory={{ configuration_efi_dir }} + --bootloader-id={{ configuration_bootloader_id }} + configuration_bootloader_cmd: >- + {{ configuration_efibootmgr_cmd if configuration_use_efibootmgr else configuration_grub_cmd }} + ansible.builtin.command: "arch-chroot /mnt {{ configuration_bootloader_cmd }}" + register: configuration_bootloader_result + changed_when: configuration_bootloader_result.rc == 0 + + - name: Ensure lvm2 for non btrfs filesystems + when: os | lower == "archlinux" and filesystem != "btrfs" + ansible.builtin.lineinfile: + path: /mnt/etc/mkinitcpio.conf + regexp: "^(HOOKS=.*block)(?!.*lvm2)(.*)" + line: '\1 lvm2\2' + backrefs: true + + - name: Regenerate initramfs + vars: + configuration_initramfs_cmd: >- + {{ + '/usr/sbin/mkinitcpio -P' + if os | lower == "archlinux" + else ( + '/usr/sbin/update-initramfs -u -k all' + if is_debian | default(false) + else '/usr/bin/dracut --regenerate-all --force' + ) + }} + ansible.builtin.command: "arch-chroot /mnt {{ configuration_initramfs_cmd }}" + register: configuration_initramfs_result + changed_when: configuration_initramfs_result.rc == 0 + + - name: Generate grub config + vars: + configuration_efi_vendor: >- + {{ "redhat" if os | lower in ["rhel8", "rhel9", "rhel10"] else os | lower }} + configuration_grub_cfg_cmd: >- + {{ '/usr/sbin/grub2-mkconfig -o /boot/efi/EFI/' + configuration_efi_vendor + '/grub.cfg' + if is_rhel | default(false) + else '/usr/sbin/grub-mkconfig -o ' + ( + '/boot/efi/EFI/ubuntu/grub.cfg' + if os | lower in ["ubuntu", "ubuntu-lts"] + else '/boot/grub/grub.cfg' + ) + }} + ansible.builtin.command: "arch-chroot /mnt {{ configuration_grub_cfg_cmd }}" + register: configuration_grub_result + changed_when: configuration_grub_result.rc == 0 diff --git a/roles/configuration/tasks/extras.yml b/roles/configuration/tasks/extras.yml new file mode 100644 index 0000000..3188868 --- /dev/null +++ b/roles/configuration/tasks/extras.yml @@ -0,0 +1,69 @@ +--- +- name: Append vim configurations to vimrc + ansible.builtin.blockinfile: + path: "{{ '/mnt/etc/vim/vimrc' if is_debian | default(false) else '/mnt/etc/vimrc' }}" + block: | + set encoding=utf-8 + set number + set autoindent + set smartindent + set mouse=a + insertafter: EOF + marker: "" + failed_when: false + +- name: Add memory tuning parameters + ansible.builtin.blockinfile: + path: /mnt/etc/sysctl.d/90-memory.conf + create: true + block: | + vm.swappiness=10 + vm.vfs_cache_pressure=50 + vm.dirty_background_ratio=1 + vm.dirty_ratio=10 + vm.page-cluster=10 + marker: "" + mode: "0644" + +- name: Create zram config + when: os | lower not in ['debian11', 'rhel8'] + ansible.builtin.copy: + dest: /mnt/etc/systemd/zram-generator.conf + content: | + [zram0] + zram-size = ram / 2 + compression-algorithm = zstd + swap-priority = 100 + fs-type = swap + mode: "0644" + +- name: Copy Custom Shell config + ansible.builtin.template: + src: custom.sh.j2 + dest: /mnt/etc/profile.d/custom.sh + mode: "0644" + +- name: Create login banner + ansible.builtin.copy: + dest: "{{ item }}" + content: | + ************************************************************** + * WARNING: Unauthorized access to this system is prohibited. * + * All activities are monitored and logged. * + * Disconnect immediately if you are not an authorized user. * + ************************************************************** + owner: root + group: root + mode: "0644" + loop: + - /mnt/etc/issue + - /mnt/etc/issue.net + +- name: Remove motd files + when: os | lower in ["rhel8", "rhel9", "rhel10"] + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /mnt/etc/motd.d/cockpit + - /mnt/etc/motd.d/insights-client diff --git a/roles/configuration/tasks/fstab.yml b/roles/configuration/tasks/fstab.yml new file mode 100644 index 0000000..adce034 --- /dev/null +++ b/roles/configuration/tasks/fstab.yml @@ -0,0 +1,65 @@ +--- +- name: Generate fstab content + ansible.builtin.command: + argv: + - genfstab + - -LU + - /mnt + register: configuration_fstab_result + changed_when: false + +- name: Write fstab + ansible.builtin.copy: + dest: /mnt/etc/fstab + content: "{{ configuration_fstab_result.stdout }}\n" + owner: root + group: root + mode: "0644" + +- name: Remove deprecated attr2 and disable large extent + when: os | lower in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] and filesystem == "xfs" + ansible.builtin.replace: + path: /mnt/etc/fstab + regexp: "(xfs.*?)(attr2)" + replace: '\1allocsize=64m' + +- name: Replace ISO UUID entry with /dev/sr0 in fstab + when: os in ["rhel8", "rhel9", "rhel10"] + vars: + configuration_fstab_dvd_line: >- + {{ + '/usr/local/install/redhat/rhel.iso /usr/local/install/redhat/dvd iso9660 loop,nofail 0 0' + if hypervisor == 'vmware' + else '/dev/sr0 /usr/local/install/redhat/dvd iso9660 ro,relatime,nojoliet,check=s,map=n,nofail 0 0' + }} + ansible.builtin.lineinfile: + path: /mnt/etc/fstab + regexp: '^.*\/dvd.*$' + line: "{{ configuration_fstab_dvd_line }}" + state: present + +- name: Write image from RHEL ISO to the target machine + when: os in ["rhel8", "rhel9", "rhel10"] and hypervisor == 'vmware' + ansible.builtin.command: + argv: + - dd + - if=/dev/sr1 + - of=/mnt/usr/local/install/redhat/rhel.iso + - bs=4M + creates: /mnt/usr/local/install/redhat/rhel.iso + register: configuration_rhel_iso_result + changed_when: configuration_rhel_iso_result.rc == 0 + +- name: Ensure TempFS is configured in fstab + ansible.builtin.lineinfile: + path: /mnt/etc/fstab + regexp: "{{ fstab_entry.regexp }}" + line: "{{ fstab_entry.line }}" + insertafter: EOF + loop: + - {regexp: '^# TempFS$', line: '# TempFS'} + - {regexp: '^tmpfs\\s+/tmp\\s+', line: 'tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0'} + - {regexp: '^tmpfs\\s+/var/tmp\\s+', line: 'tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec 0 0'} + - {regexp: '^tmpfs\\s+/dev/shm\\s+', line: 'tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0'} + loop_control: + loop_var: fstab_entry diff --git a/roles/configuration/tasks/locales.yml b/roles/configuration/tasks/locales.yml new file mode 100644 index 0000000..02c8dc4 --- /dev/null +++ b/roles/configuration/tasks/locales.yml @@ -0,0 +1,88 @@ +--- +- name: Set local timezone + ansible.builtin.command: "{{ item }}" + loop: + - systemctl daemon-reload + - arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime + register: configuration_timezone_result + changed_when: configuration_timezone_result.rc == 0 + +- name: Setup locales + block: + - name: Configure locale.gen + when: not is_rhel | default(false) + ansible.builtin.lineinfile: + dest: /mnt/etc/locale.gen + regexp: "{{ item.regex }}" + line: "{{ item.line }}" + loop: + - {regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8} + + - name: Generate locales + when: not is_rhel | default(false) + ansible.builtin.command: arch-chroot /mnt /usr/sbin/locale-gen + register: configuration_locale_result + changed_when: configuration_locale_result.rc == 0 + + - name: Set hostname + vars: + configuration_hostname_fqdn: >- + {{ + hostname + if '.' in hostname + else ( + hostname + '.' + vm_dns_search + if vm_dns_search is defined and vm_dns_search | length + else hostname + ) + }} + ansible.builtin.copy: + content: "{{ configuration_hostname_fqdn }}" + dest: /mnt/etc/hostname + mode: "0644" + + - name: Add host entry to /etc/hosts + vars: + configuration_hostname_fqdn: >- + {{ + hostname + if '.' in hostname + else ( + hostname + '.' + vm_dns_search + if vm_dns_search is defined and vm_dns_search | length + else hostname + ) + }} + configuration_hostname_short: "{{ hostname.split('.')[0] }}" + configuration_hostname_entries: >- + {{ [configuration_hostname_fqdn, configuration_hostname_short] | unique | join(' ') }} + configuration_hosts_line: >- + {{ vm_ip | default(inventory_hostname) }} {{ configuration_hostname_entries }} + ansible.builtin.lineinfile: + path: /mnt/etc/hosts + line: "{{ configuration_hosts_line }}" + state: present + + - name: Create vconsole.conf + ansible.builtin.copy: + content: KEYMAP=us + dest: /mnt/etc/vconsole.conf + mode: "0644" + + - name: Create locale.conf + ansible.builtin.copy: + content: LANG=en_US.UTF-8 + dest: /mnt/etc/locale.conf + mode: "0644" + + - name: Ensure SSH password authentication is enabled + ansible.builtin.lineinfile: + path: /mnt/etc/ssh/sshd_config + regexp: "^#?PasswordAuthentication\\s+" + line: "PasswordAuthentication yes" + + - name: SSH permit root login + ansible.builtin.replace: + path: /mnt/etc/ssh/sshd_config + regexp: "^#?PermitRootLogin.*" + replace: "PermitRootLogin yes" diff --git a/roles/configuration/tasks/main.yml b/roles/configuration/tasks/main.yml index 4df691e..19d1c90 100644 --- a/roles/configuration/tasks/main.yml +++ b/roles/configuration/tasks/main.yml @@ -1,324 +1,17 @@ --- -- name: Configuration - block: - - name: Generate fstab - ansible.builtin.shell: genfstab -LU /mnt > /mnt/etc/fstab - changed_when: result.rc == 0 - register: result - - - name: Remove depricated attr2 and disable large extent - when: os in ["almalinux", "rhel8", "rhel9", "rhel10", "rocky"] and filesystem == "xfs" - ansible.builtin.replace: - path: /mnt/etc/fstab - regexp: "(xfs.*?)(attr2)" - replace: '\1allocsize=64m' - - - name: Replace ISO UUID entry with /dev/sr0 in fstab - when: os in ["rhel8", "rhel9", "rhel10"] - ansible.builtin.lineinfile: - path: /mnt/etc/fstab - regexp: '^.*\/dvd.*$' - line: - "{{ '/usr/local/install/redhat/rhel.iso /usr/local/install/redhat/dvd iso9660 loop,nofail 0 0' if hypervisor == 'vmware' - else '/dev/sr0 /usr/local/install/redhat/dvd iso9660 ro,relatime,nojoliet,check=s,map=n,nofail 0 0' }}" - state: present - backrefs: true - - - name: Write image from RHEL ISO to the target machine - when: os in ["rhel8", "rhel9", "rhel10"] and hypervisor == 'vmware' - ansible.builtin.command: dd if=/dev/sr1 of=/mnt/usr/local/install/redhat/rhel.iso bs=4M - changed_when: result.rc == 0 - register: result - - - name: Append TempFS to fstab - ansible.builtin.lineinfile: - path: /mnt/etc/fstab - line: "{{ item }}" - insertafter: EOF - with_items: - - "" - - "# TempFS" - - tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0 - - tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec 0 0 - - tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec 0 0 - - - name: Set local timezone - ansible.builtin.command: "{{ item }}" - changed_when: result.rc == 0 - register: result - with_items: - - systemctl daemon-reload - - arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime - - - name: Setup locales - block: - - name: Configure locale.gen - when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] - ansible.builtin.lineinfile: - dest: /mnt/etc/locale.gen - regexp: "{{ item.regex }}" - line: "{{ item.line }}" - loop: - - { regex: en_US\.UTF-8 UTF-8, line: en_US.UTF-8 UTF-8 } - - - name: Generate locales - when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] - ansible.builtin.command: arch-chroot /mnt /usr/sbin/locale-gen - changed_when: result.rc == 0 - register: result - - - name: Set hostname - ansible.builtin.copy: - content: "{{ hostname }}{% if vm_dns_search is defined and vm_dns_search | length %}.{{ vm_dns_search }}{% endif %}" - dest: /mnt/etc/hostname - mode: "0644" - - - name: Add host entry to /etc/hosts - ansible.builtin.lineinfile: - path: /mnt/etc/hosts - line: "{{ ansible_host }} {{ hostname }}{% if vm_dns_search is defined and vm_dns_search | length %} {{ hostname }}.{{ vm_dns_search }}{% endif %}" - state: present - - - name: Create vconsole.conf - ansible.builtin.copy: - content: KEYMAP=us - dest: /mnt/etc/vconsole.conf - mode: "0644" - - - name: Create locale.conf - ansible.builtin.copy: - content: LANG=en_US.UTF-8 - dest: /mnt/etc/locale.conf - mode: "0644" - - - name: SSH permit Password - ansible.builtin.replace: - path: /mnt/etc/ssh/sshd_config - regexp: "#PasswordAuthentication yes" - replace: PasswordAuthentication yes - - - name: SSH permit root login - ansible.builtin.replace: - path: /mnt/etc/ssh/sshd_config - regexp: "^#?PermitRootLogin.*" - replace: "PermitRootLogin yes" - - - name: Enable Systemd Services - ansible.builtin.command: > - arch-chroot /mnt systemctl enable NetworkManager - {{ - ' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else - (' sshd' if os | lower not in ['debian11', 'debian12', 'debian13'] else '') - }} - {{ - 'logrotate systemd-resolved systemd-timesyncd systemd-networkd' - if os | lower == 'archlinux' else '' - }} - changed_when: result.rc == 0 - register: result - - - name: Configure grub - when: os | lower not in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] - block: - - name: Add commandline information to grub config - ansible.builtin.lineinfile: - dest: /mnt/etc/default/grub - regexp: ^GRUB_CMDLINE_LINUX_DEFAULT= - line: GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3" - - - name: Change Grub time - ansible.builtin.lineinfile: - dest: /mnt/etc/default/grub - regexp: ^GRUB_TIMEOUT= - line: GRUB_TIMEOUT=1 - - - name: Configure Bootloader - block: - - name: Install Bootloader - ansible.builtin.command: arch-chroot /mnt - {% if os | lower not in ["archlinux", "debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] %} /usr/sbin/efibootmgr - -c -L '{{ os }}' -d "{{ install_drive }}" -p 1 - -l '\efi\EFI\{% if os | lower in ["rhel8", "rhel9", "rhel10"] %}redhat{% else %}{{ os | lower }}{% endif %}\shimx64.efi' - {% else %}/usr/sbin/grub-install --target=x86_64-efi --efi-directory={{ "/boot/efi" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot" }} - --bootloader-id={{ "ubuntu" if os | lower in ["ubuntu", "ubuntu-lts"] else os }} - {% endif %} - changed_when: result.rc == 0 - register: result - - - name: Ensure lvm2 for non btrfs filesystems - when: os | lower == "archlinux" and filesystem != "btrfs" - ansible.builtin.lineinfile: - path: /mnt/etc/mkinitcpio.conf - regexp: "^(HOOKS=.*block)(?!.*lvm2)(.*)" - line: '\1 lvm2\2' - backrefs: true - - - name: Regenerate initramfs - when: os | lower not in ["debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] - ansible.builtin.command: arch-chroot /mnt - {% if os | lower == "archlinux" %} /usr/sbin/mkinitcpio -P - {% else %} /usr/bin/dracut --regenerate-all --force - {% endif %} - changed_when: result.rc == 0 - register: result - - - name: Generate grub config - ansible.builtin.command: arch-chroot /mnt - {% if os | lower not in ["archlinux", "debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] %} - /usr/sbin/grub2-mkconfig -o /boot/efi/EFI/{% if os | lower in ["rhel8", "rhel9", "rhel10"] %}redhat{% else %}{{ os | lower }}{% endif %}/grub.cfg - {% else %} - /usr/sbin/grub-mkconfig -o {{ "/boot/efi/EFI/ubuntu/grub.cfg" if os | lower in ["ubuntu", "ubuntu-lts"] else "/boot/grub/grub.cfg" }} - {% endif %} - changed_when: result.rc == 0 - register: result - - - name: Extra Configuration - block: - - name: Append vim configurations to vimrc - failed_when: false - ansible.builtin.blockinfile: - path: - "{{ '/mnt/etc/vim/vimrc' if os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'] - else '/mnt/etc/vimrc' }}" - block: | - set encoding=utf-8 - set number - set autoindent - set smartindent - set mouse=a - insertafter: EOF - marker: "" - - - name: Add memory tuning parameters - ansible.builtin.blockinfile: - path: /mnt/etc/sysctl.d/90-memory.conf - create: true - block: | - vm.swappiness=10 - vm.vfs_cache_pressure=50 - vm.dirty_background_ratio=1 - vm.dirty_ratio=10 - vm.page-cluster=10 - marker: "" - mode: "0644" - - - name: Create zram config - when: os not in ['debian11', 'rhel8'] - ansible.builtin.copy: - dest: /mnt/etc/systemd/zram-generator.conf - content: | - [zram0] - zram-size = ram / 2 - compression-algorithm = zstd - swap-priority = 100 - fs-type = swap - mode: "0644" - - - name: Copy Custom Shell config - ansible.builtin.template: - src: custom.sh.j2 - dest: /mnt/etc/profile.d/custom.sh - mode: "0644" - - - name: Create login banner - ansible.builtin.copy: - dest: "{{ item }}" - content: | - ************************************************************** - * WARNING: Unauthorized access to this system is prohibited. * - * All activities are monitored and logged. * - * Disconnect immediately if you are not an authorized user. * - ************************************************************** - owner: root - group: root - mode: "0644" - loop: - - /mnt/etc/issue - - /etc/issue.net - - - name: Remove motd files - when: os | lower in ["rhel8", "rhel9", "rhel10"] - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - /etc/motd.d/cockpit - - /etc/motd.d/insights-client - - - name: Setup Network - block: - - name: Generate UUID for Network Profile - ansible.builtin.command: uuidgen - changed_when: net_uuid.rc == 0 - register: net_uuid - - - name: Retrieve Network Interface Name - ansible.builtin.shell: set -o pipefail && ip r | awk 'NR==1 {print $5}' - changed_when: net_inf.rc == 0 - register: net_inf - - - name: Register MAC Address of the Network Interface - ansible.builtin.shell: set -o pipefail && ip link show "{{ net_inf.stdout }}" | awk '/link\/ether/ {print $2}' | tr '[:lower:]' '[:upper:]' - register: net_mac - changed_when: net_mac.rc == 0 - - - name: Copy NetworkManager keyfile - ansible.builtin.template: - src: network.j2 - dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection - mode: "0600" - - - name: Fix Ubuntu unmanaged devices - when: os | lower in ["ubuntu", "ubuntu-lts"] - ansible.builtin.file: - path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf - state: touch - mode: "0644" - - - name: Setup user account - block: - - name: Create user account - ansible.builtin.command: "{{ item }}" - with_items: - - arch-chroot /mnt /usr/sbin/useradd --create-home --user-group --groups - {{ "sudo" if os | lower in ["debian11", "debian12", "debian13", "ubuntu", "ubuntu-lts"] else "wheel" }} - {{ user_name }} --password {{ user_password | password_hash('sha512') }} --shell /bin/bash - - arch-chroot /mnt /usr/sbin/usermod --password '{{ root_password | password_hash('sha512') }}' root --shell /bin/bash - changed_when: result.rc == 0 - register: result - - - name: Add SSH public key to authorized_keys - when: user_public_key is defined - ansible.builtin.lineinfile: - path: /mnt/home/{{ user_name }}/.ssh/authorized_keys - line: "{{ user_public_key }}" - owner: 1000 - group: 1000 - mode: "0600" - create: true - - - name: Give sudo access to wheel group - ansible.builtin.copy: - content: "{{ '%sudo ALL=(ALL) ALL' if os | lower in ['debian11', 'debian12', 'debian13', 'ubuntu', 'ubuntu-lts'] else '%wheel ALL=(ALL) ALL' }}" - dest: /mnt/etc/sudoers.d/01-wheel - mode: "0440" - validate: /usr/sbin/visudo --check --file=%s - - - name: Fix SELinux - when: os | lower in ['almalinux', 'fedora', 'rhel8', 'rhel9', 'rhel10', 'rocky'] - block: - - name: Fix SELinux by pre-labeling the filesystem before first boot - when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rhel10', 'rocky'] and (selinux | default(true) | bool) - ansible.builtin.command: > - arch-chroot /mnt /sbin/setfiles -v -F - -e /dev -e /proc -e /sys -e /run - /etc/selinux/targeted/contexts/files/file_contexts / - register: setfiles_result - changed_when: setfiles_result.rc == 0 - - - name: Disable SELinux - when: os | lower == "fedora" or not (selinux | default(true) | bool) - ansible.builtin.lineinfile: - path: /mnt/etc/selinux/config - regexp: ^SELINUX= - line: SELINUX=permissive +- name: Include configuration tasks + ansible.builtin.include_tasks: "{{ configuration_task }}" + loop: + - fstab.yml + - locales.yml + - services.yml + - grub.yml + - encryption.yml + - bootloader.yml + - extras.yml + - network.yml + - users.yml + - sudo.yml + - selinux.yml + loop_control: + loop_var: configuration_task diff --git a/roles/configuration/tasks/network.yml b/roles/configuration/tasks/network.yml new file mode 100644 index 0000000..f3303a1 --- /dev/null +++ b/roles/configuration/tasks/network.yml @@ -0,0 +1,96 @@ +--- +- name: Generate UUID for Network Profile + ansible.builtin.set_fact: + configuration_net_uuid: "{{ ('LAN-' ~ hostname) | ansible.builtin.to_uuid }}" + changed_when: false + +- name: Read network interfaces + ansible.builtin.command: + argv: + - ip + - -o + - link + - show + register: configuration_ip_link + changed_when: false + failed_when: false + +- name: Resolve network interface and MAC address + vars: + configuration_net_inf_from_facts: "{{ (ansible_default_ipv4 | default({})).get('interface', '') }}" + configuration_net_inf_from_ip: >- + {{ + ( + configuration_ip_link.stdout + | default('') + | regex_findall('^[0-9]+: ([^:]+):', multiline=True) + | reject('equalto', 'lo') + | list + | first + ) + | default('') + }} + configuration_net_inf_effective: >- + {{ configuration_net_inf_from_facts | default(configuration_net_inf_from_ip, true) }} + configuration_net_inf_regex: "{{ configuration_net_inf_effective | ansible.builtin.regex_escape }}" + configuration_net_mac_from_virtualization: "{{ virtualization_mac_address | default('') }}" + configuration_net_mac_from_facts: >- + {{ + ( + (ansible_facts | default({})).get(configuration_net_inf_effective, {}).get('macaddress', '') + ) + | default( + (ansible_facts | default({})).get('ansible_' + configuration_net_inf_effective, {}).get('macaddress', ''), + true + ) + }} + configuration_net_mac_from_ip: >- + {{ + ( + configuration_ip_link.stdout + | default('') + | regex_findall( + '^\\d+: ' ~ configuration_net_inf_regex ~ ':.*?link/ether\\s+([0-9A-Fa-f:]{17})', + multiline=True + ) + | first + ) + | default('') + }} + ansible.builtin.set_fact: + configuration_net_inf: "{{ configuration_net_inf_effective }}" + configuration_net_mac: >- + {{ + ( + configuration_net_mac_from_virtualization + | default(configuration_net_mac_from_facts, true) + | default(configuration_net_mac_from_ip, true) + ) + | upper + }} + changed_when: false + +- name: Validate Network Interface Name + ansible.builtin.assert: + that: + - configuration_net_inf | length > 0 + fail_msg: Failed to detect an active network interface. + +- name: Validate Network Interface MAC Address + ansible.builtin.assert: + that: + - configuration_net_mac | length > 0 + fail_msg: Failed to detect the MAC address for network interface {{ configuration_net_inf }}. + +- name: Copy NetworkManager keyfile + ansible.builtin.template: + src: network.j2 + dest: /mnt/etc/NetworkManager/system-connections/LAN.nmconnection + mode: "0600" + +- name: Fix Ubuntu unmanaged devices + when: os | lower in ["ubuntu", "ubuntu-lts"] + ansible.builtin.file: + path: /mnt/etc/NetworkManager/conf.d/10-globally-managed-devices.conf + state: touch + mode: "0644" diff --git a/roles/configuration/tasks/selinux.yml b/roles/configuration/tasks/selinux.yml new file mode 100644 index 0000000..c23f327 --- /dev/null +++ b/roles/configuration/tasks/selinux.yml @@ -0,0 +1,19 @@ +--- +- name: Fix SELinux + when: is_rhel | default(false) + block: + - name: Fix SELinux by pre-labeling the filesystem before first boot + when: os | lower in ['almalinux', 'rhel8', 'rhel9', 'rhel10', 'rocky'] and (selinux | default(true) | bool) + ansible.builtin.command: > + arch-chroot /mnt /sbin/setfiles -v -F + -e /dev -e /proc -e /sys -e /run + /etc/selinux/targeted/contexts/files/file_contexts / + register: configuration_setfiles_result + changed_when: configuration_setfiles_result.rc == 0 + + - name: Disable SELinux + when: os | lower == "fedora" or not (selinux | default(true) | bool) + ansible.builtin.lineinfile: + path: /mnt/etc/selinux/config + regexp: ^SELINUX= + line: SELINUX=permissive diff --git a/roles/configuration/tasks/services.yml b/roles/configuration/tasks/services.yml new file mode 100644 index 0000000..0315bcf --- /dev/null +++ b/roles/configuration/tasks/services.yml @@ -0,0 +1,14 @@ +--- +- name: Enable Systemd Services + ansible.builtin.command: > + arch-chroot /mnt systemctl enable NetworkManager + {{ + ' ssh' if os | lower in ['ubuntu', 'ubuntu-lts'] else + (' sshd' if os | lower not in ['debian11', 'debian12', 'debian13'] else '') + }} + {{ + 'logrotate systemd-resolved systemd-timesyncd systemd-networkd' + if os | lower == 'archlinux' else '' + }} + register: configuration_enable_services_result + changed_when: configuration_enable_services_result.rc == 0 diff --git a/roles/configuration/tasks/sudo.yml b/roles/configuration/tasks/sudo.yml new file mode 100644 index 0000000..f1f37fa --- /dev/null +++ b/roles/configuration/tasks/sudo.yml @@ -0,0 +1,7 @@ +--- +- name: Give sudo access to wheel group + ansible.builtin.copy: + content: "{{ '%sudo ALL=(ALL) ALL' if is_debian | default(false) else '%wheel ALL=(ALL) ALL' }}" + dest: /mnt/etc/sudoers.d/01-wheel + mode: "0440" + validate: /usr/sbin/visudo --check --file=%s diff --git a/roles/configuration/tasks/users.yml b/roles/configuration/tasks/users.yml new file mode 100644 index 0000000..9282554 --- /dev/null +++ b/roles/configuration/tasks/users.yml @@ -0,0 +1,37 @@ +--- +- name: Create user account + vars: + configuration_user_group: >- + {{ "sudo" if is_debian | default(false) else "wheel" }} + configuration_useradd_cmd: >- + arch-chroot /mnt /usr/sbin/useradd --create-home --user-group + --groups {{ configuration_user_group }} {{ user_name }} + --password {{ user_password | password_hash('sha512') }} --shell /bin/bash + configuration_root_cmd: >- + arch-chroot /mnt /usr/sbin/usermod --password + '{{ root_password | password_hash('sha512') }}' root --shell /bin/bash + ansible.builtin.command: "{{ item }}" + loop: + - "{{ configuration_useradd_cmd }}" + - "{{ configuration_root_cmd }}" + register: configuration_user_result + changed_when: configuration_user_result.rc == 0 + +- name: Ensure .ssh directory exists + when: user_public_key is defined + ansible.builtin.file: + path: /mnt/home/{{ user_name }}/.ssh + state: directory + owner: 1000 + group: 1000 + mode: "0700" + +- name: Add SSH public key to authorized_keys + when: user_public_key is defined + ansible.builtin.lineinfile: + path: /mnt/home/{{ user_name }}/.ssh/authorized_keys + line: "{{ user_public_key }}" + owner: 1000 + group: 1000 + mode: "0600" + create: true diff --git a/roles/configuration/templates/network.j2 b/roles/configuration/templates/network.j2 index 062b65b..a03ece1 100644 --- a/roles/configuration/templates/network.j2 +++ b/roles/configuration/templates/network.j2 @@ -1,18 +1,33 @@ [connection] id=LAN -uuid={{ net_uuid.stdout }} +uuid={{ configuration_net_uuid }} type=ethernet [ethernet] -mac-address={{ net_mac.stdout }} +mac-address={{ configuration_net_mac }} [ipv4] -address={{ vm_ip }}/{{ vm_nms | default (24) }},{{ vm_gw }} -dns={{ vm_dns }} -{% if vm_dns_search is defined %} -dns-search={{ vm_dns_search }} -{% endif %} +{% set dns_value = vm_dns | default('') %} +{% set dns_list_raw = dns_value if dns_value is iterable and dns_value is not string else dns_value.split(',') %} +{% set dns_list = dns_list_raw | map('trim') | reject('equalto', '') | list %} +{% set search_value = vm_dns_search | default('') %} +{% set search_list_raw = search_value if search_value is iterable and search_value is not string else search_value.split(',') %} +{% set search_list = search_list_raw | map('trim') | reject('equalto', '') | list %} +{% if vm_ip is defined and vm_ip | length %} +address1={{ vm_ip }}/{{ vm_nms | default(24) }}{{ (',' ~ vm_gw) if (vm_gw is defined and vm_gw | length) else '' }} method=manual +{% else %} +method=auto +{% endif %} +{% if dns_list %} +dns={{ dns_list | join(';') }} +{% endif %} +{% if dns_list or search_list %} +ignore-auto-dns=true +{% endif %} +{% if search_list %} +dns-search={{ search_list | join(';') }} +{% endif %} [ipv6] addr-gen-mode=stable-privacy