--- - name: Configure elogind to suspend on lid close tags: [packages] ansible.builtin.lineinfile: path: /etc/elogind/logind.conf regexp: '^#?HandleLidSwitch=' line: 'HandleLidSwitch=suspend' state: present - name: Ensure common config directories exist tags: [dotfiles, dotfiles:desktop] ansible.builtin.file: path: "{{ item }}" state: directory owner: "{{ username }}" group: "{{ user_group }}" mode: "0755" loop: - "{{ user_home }}/.config" - "{{ user_home }}/.config/autostart" - "{{ user_home }}/.config/dunst" - "{{ user_home }}/.config/alacritty" - "{{ user_home }}/.config/Thunar" - "{{ user_home }}/.config/rofi" - "{{ user_home }}/.tmux" - "{{ user_home }}/.tmux/bin" - "{{ user_home }}/.tmux/plugins" - name: Ensure user local bin directory exists tags: [dotfiles, dotfiles:desktop, dotfiles:host] ansible.builtin.file: path: "{{ user_home }}/.local/bin" state: directory owner: "{{ username }}" group: "{{ user_group }}" mode: "0755" - name: Enable gnome-keyring PAM auth hook tags: [packages, gnome] ansible.builtin.lineinfile: path: /etc/pam.d/login insertafter: '^auth\s+include\s+system-local-login$' line: "auth optional pam_gnome_keyring.so" state: present - name: Enable gnome-keyring PAM session hook tags: [packages, gnome] ansible.builtin.lineinfile: path: /etc/pam.d/login insertafter: '^session\s+include\s+system-local-login$' line: "session optional pam_gnome_keyring.so auto_start" state: present - name: Enable gnome-keyring PAM password hook tags: [packages, gnome] ansible.builtin.lineinfile: path: /etc/pam.d/login insertafter: '^password\s+include\s+system-local-login$' line: "password optional pam_gnome_keyring.so use_authtok" state: present - name: Check whether SSH host ed25519 key exists tags: [services] ansible.builtin.stat: path: /etc/ssh/ssh_host_ed25519_key register: desktop_ssh_host_ed25519_key when: - (host_sshd_settings | default({})) | length > 0 or (host_sshd_allow_users | default([])) | length > 0 - name: Generate missing SSH host keys on desktop host tags: [services] ansible.builtin.command: ssh-keygen -A changed_when: true when: - (host_sshd_settings | default({})) | length > 0 or (host_sshd_allow_users | default([])) | length > 0 - not desktop_ssh_host_ed25519_key.stat.exists - name: Require authorized SSH keys before disabling password authentication on desktop host tags: [services] ansible.builtin.assert: that: - (host_authorized_ssh_keys | default([])) | length > 0 fail_msg: >- SSH password authentication is disabled for this host, but no authorized SSH keys are defined. Set vault_ikaros_authorized_ssh_keys in secrets/vault.yml or secrets/vault.local.yml before applying this configuration. when: - "'sshd' in (host_enabled_services | default([]))" - (host_sshd_settings | default({})).PasswordAuthentication | default('yes') == 'no' - name: Ensure desktop user SSH directory exists tags: [services, dotfiles] ansible.builtin.file: path: "{{ user_home }}/.ssh" state: directory owner: "{{ username }}" group: "{{ user_group }}" mode: "0700" when: (host_authorized_ssh_keys | default([])) | length > 0 - name: Ensure desktop user authorized_keys file exists tags: [services, dotfiles] ansible.builtin.file: path: "{{ user_home }}/.ssh/authorized_keys" state: touch owner: "{{ username }}" group: "{{ user_group }}" mode: "0600" when: (host_authorized_ssh_keys | default([])) | length > 0 - name: Manage desktop user authorized SSH keys exclusively tags: [services, dotfiles] ansible.posix.authorized_key: user: "{{ username }}" key: "{{ host_authorized_ssh_keys | join('\n') }}" state: present exclusive: true manage_dir: false when: (host_authorized_ssh_keys | default([])) | length > 0 - name: Apply SSH daemon settings on desktop host tags: [services] ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^\s*{{ item.key }}\s+' line: "{{ item.key }} {{ item.value }}" state: present validate: "sshd -t -f %s" notify: Reload SSH service loop: "{{ host_sshd_settings | default({}) | dict2items }}" loop_control: label: "{{ item.key }}" when: (host_sshd_settings | default({})) | length > 0 - name: Restrict SSH login to allowed desktop users tags: [services] ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^\s*AllowUsers\s+' line: "AllowUsers {{ host_sshd_allow_users | join(' ') }}" state: present validate: "sshd -t -f %s" notify: Reload SSH service when: (host_sshd_allow_users | default([])) | length > 0 - name: Define effective desktop UFW rules tags: [services, packages] ansible.builtin.set_fact: desktop_ufw_rules_effective: "{{ host_ufw_rules | default([]) }}" - name: Apply host UFW rules on desktop tags: [services, packages] community.general.ufw: rule: "{{ item.rule }}" name: "{{ item.name | default(omit) }}" port: "{{ item.port | default(omit) }}" proto: "{{ item.proto | default(omit) }}" from_ip: "{{ item.src | default(omit) }}" to_ip: "{{ item.dest | default(omit) }}" from_port: "{{ item.from_port | default(omit) }}" direction: "{{ item.direction | default(omit) }}" interface: "{{ item.interface | default(omit) }}" interface_in: "{{ item.interface_in | default(omit) }}" interface_out: "{{ item.interface_out | default(omit) }}" route: "{{ item.route | default(omit) }}" comment: "{{ item.comment | default(omit) }}" loop: "{{ desktop_ufw_rules_effective }}" loop_control: label: "{{ item.name | default(item.port) }}" - name: Enable UFW firewall on desktop when host rules are defined tags: [services, packages] community.general.ufw: state: enabled when: (desktop_ufw_rules_effective | default([])) | length > 0 - name: Check whether libvirt service directory exists tags: [packages, services] ansible.builtin.stat: path: /etc/sv/libvirtd register: libvirtd_service_dir - name: Enable libvirt daemon service tags: [packages, services] ansible.builtin.file: src: /etc/sv/libvirtd dest: /var/service/libvirtd state: link when: libvirtd_service_dir.stat.exists - name: Check virtualization group availability tags: [packages] ansible.builtin.getent: database: group key: "{{ item }}" loop: - kvm - libvirt loop_control: label: "{{ item }}" register: desktop_virtualization_group_state failed_when: false - name: Add desktop user to virtualization groups tags: [packages] ansible.builtin.user: name: "{{ username }}" groups: "{{ item }}" append: true loop: >- {{ desktop_virtualization_group_state.results | default([]) | selectattr('failed', 'equalto', false) | selectattr('ansible_facts.getent_group', 'defined') | map(attribute='item') | list }} loop_control: label: "{{ item }}" - name: Ensure emptty log directory exists tags: [packages, services, emptty] ansible.builtin.file: path: /var/log/emptty state: directory owner: root group: root mode: "0755" - name: Ensure emptty session directories exist tags: [packages, services, emptty] ansible.builtin.file: path: "{{ item }}" state: directory owner: root group: root mode: "0755" loop: - /etc/emptty/xsessions - /etc/emptty/wayland-sessions - name: Configure emptty tags: [packages, services, emptty] ansible.builtin.template: src: emptty-conf.j2 dest: /etc/emptty/conf owner: root group: root mode: "0644" notify: Restart emptty - name: Copy common desktop dotfiles tags: [dotfiles, dotfiles:desktop] ansible.builtin.copy: src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" dest: "{{ user_home }}/{{ item.dest }}" owner: "{{ username }}" group: "{{ user_group }}" mode: "{{ item.mode }}" loop: "{{ desktop_common_dotfiles | default([]) }}" loop_control: label: "{{ item.dest }}" - name: Render desktop templates with private values tags: [dotfiles, dotfiles:desktop] ansible.builtin.template: src: "{{ item.src }}" dest: "{{ user_home }}/{{ item.dest }}" owner: "{{ username }}" group: "{{ user_group }}" mode: "{{ item.mode }}" loop: - src: desktop/.gitconfig.j2 dest: .gitconfig mode: "0644" - src: desktop/.mbsyncrc.j2 dest: .mbsyncrc mode: "0600" - src: desktop/.msmtprc.j2 dest: .msmtprc mode: "0600" - src: desktop/email.el.j2 dest: .emacs.d/lisp/misc/email.el mode: "0644" loop_control: label: "{{ item.dest }}" - name: Define managed tmux plugin directories tags: [dotfiles, dotfiles:desktop, tmux] ansible.builtin.set_fact: tmux_managed_plugin_names: - tpm - tmux-sensible - tmux-autoreload - tmux-resurrect - tmux-continuum - name: Check whether tmux plugin directories are git checkouts tags: [dotfiles, dotfiles:desktop, tmux] ansible.builtin.stat: path: "{{ user_home }}/.tmux/plugins/{{ item }}/.git" loop: "{{ tmux_managed_plugin_names }}" loop_control: label: "{{ item }}" register: tmux_plugin_git_state - name: Remove stale vendored tmux plugin directories tags: [dotfiles, dotfiles:desktop, tmux] ansible.builtin.file: path: "{{ user_home }}/.tmux/plugins/{{ item.item }}" state: absent loop: "{{ tmux_plugin_git_state.results }}" loop_control: label: "{{ item.item }}" when: - item.stat.exists == false - name: Bootstrap tmux plugin manager checkout tags: [dotfiles, dotfiles:desktop, tmux] ansible.builtin.git: repo: https://github.com/tmux-plugins/tpm dest: "{{ user_home }}/.tmux/plugins/tpm" version: master update: true become_user: "{{ username }}" environment: HOME: "{{ user_home }}" - name: Install tmux plugins through TPM tags: [dotfiles, dotfiles:desktop, tmux] ansible.builtin.command: cmd: "{{ user_home }}/.tmux/plugins/tpm/bin/install_plugins" become_user: "{{ username }}" environment: HOME: "{{ user_home }}" register: tmux_plugin_install changed_when: >- (tmux_plugin_install.stdout | default('')) is search('download success') or (tmux_plugin_install.stderr | default('')) is search('download success') - name: Refresh user font cache tags: [dotfiles, dotfiles:desktop] ansible.builtin.command: fc-cache -f become_user: "{{ username }}" environment: HOME: "{{ user_home }}" changed_when: false - name: Ensure .gnupg directory exists tags: [dotfiles, dotfiles:desktop] ansible.builtin.file: path: "{{ user_home }}/.gnupg" state: directory owner: "{{ username }}" group: "{{ user_group }}" mode: "0700" - name: Copy gpg-agent.conf tags: [dotfiles, dotfiles:desktop] ansible.builtin.copy: src: "{{ playbook_dir }}/../dotfiles/desktop/.gnupg/gpg-agent.conf" dest: "{{ user_home }}/.gnupg/gpg-agent.conf" owner: "{{ username }}" group: "{{ user_group }}" mode: "0600" - name: Ensure local user directories exist tags: [dotfiles, dotfiles:desktop] ansible.builtin.file: path: "{{ item.path }}" state: directory owner: "{{ username }}" group: "{{ user_group }}" mode: "{{ item.mode }}" loop: - path: "{{ user_home }}/.local" mode: "0755" - path: "{{ user_home }}/.local/state" mode: "0755" - path: "{{ user_home }}/.local/state/ssh-agent" mode: "0700" - path: "{{ user_home }}/.local/share" mode: "0755" - path: "{{ user_home }}/.local/share/keyrings" mode: "0700" - path: "{{ user_home }}/.local/src" mode: "0755" - name: Ensure maildir directories exist tags: [dotfiles, dotfiles:desktop] ansible.builtin.file: path: "{{ item }}" state: directory owner: "{{ username }}" group: "{{ user_group }}" mode: "0700" loop: - "{{ user_home }}/Maildir" - "{{ user_home }}/Maildir/iCloudAccount" - "{{ user_home }}/Maildir/ProtonMailAccount" - name: Ensure flathub remote is configured tags: [packages] community.general.flatpak_remote: name: "{{ desktop_flatpak_remote_name | default('flathub') }}" state: present flatpakrepo_url: "{{ desktop_flatpak_remote_url | default('https://dl.flathub.org/repo/flathub.flatpakrepo') }}" when: (desktop_flatpak_packages | default([])) | length > 0 - name: Install desktop flatpak applications tags: [packages] community.general.flatpak: name: "{{ desktop_flatpak_packages }}" state: present remote: "{{ desktop_flatpak_remote_name | default('flathub') }}" method: system when: (desktop_flatpak_packages | default([])) | length > 0 - name: Install Flatpak extensions tags: [packages] community.general.flatpak: name: "{{ item }}" state: present remote: "{{ desktop_flatpak_remote_name | default('flathub') }}" method: system loop: "{{ desktop_flatpak_extensions | default([]) }}" when: - (desktop_flatpak_packages | default([])) | length > 0 - (desktop_flatpak_extensions | default([])) | length > 0 - item | length > 0 - name: Build and install desktop source tools tags: [packages] ansible.builtin.include_tasks: file: source_tool.yml apply: tags: [packages] loop: "{{ desktop_source_tools }}" when: desktop_source_tools | length > 0 loop_control: loop_var: source_tool label: "{{ source_tool.name }}" - name: Install desktop npm packages tags: [packages] community.general.npm: name: "{{ item.name }}" global: true state: "{{ item.state | default('present') }}" become: true loop: "{{ desktop_npm_packages | default([]) }}" when: desktop_npm_packages | length > 0 loop_control: label: "{{ item.name }}"