From 7090ea558537a669a679cd25f23084b53d618375 Mon Sep 17 00:00:00 2001 From: Michael Balsillie Date: Wed, 9 Sep 2026 16:50:19 -0400 Subject: [PATCH] Sudoers config and hostname config working --- .../dl01.balsillie.house/network.yml | 3 + playbooks/archlinux-servers.yml | 19 +++-- roles/hostname/tasks/main.yml | 23 ++++++ roles/hostname/vars/main.yml | 1 + roles/sshd/handlers/main.yml | 4 +- roles/sshd/tasks/main.yml | 47 +++++++++++- roles/sshd/vars/main.yml | 26 +++++-- roles/sudoers/tasks/main.yml | 76 +++++++++++++++++++ roles/sudoers/vars/main.yml | 4 + 9 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 inventory/host_vars/dl01.balsillie.house/network.yml create mode 100644 roles/hostname/tasks/main.yml create mode 100644 roles/hostname/vars/main.yml create mode 100644 roles/sudoers/tasks/main.yml create mode 100644 roles/sudoers/vars/main.yml diff --git a/inventory/host_vars/dl01.balsillie.house/network.yml b/inventory/host_vars/dl01.balsillie.house/network.yml new file mode 100644 index 0000000..b679bfb --- /dev/null +++ b/inventory/host_vars/dl01.balsillie.house/network.yml @@ -0,0 +1,3 @@ +# code: language=ansible + +ipv4_only: true diff --git a/playbooks/archlinux-servers.yml b/playbooks/archlinux-servers.yml index 2ba4575..3b70d26 100644 --- a/playbooks/archlinux-servers.yml +++ b/playbooks/archlinux-servers.yml @@ -1,4 +1,4 @@ ---- +# code: language=ansible - name: Configure ssh and firewall hosts: @@ -7,11 +7,18 @@ become: true pre_tasks: - - name: Set IP facts + - name: Set IPv4 facts become: false ansible.builtin.set_fact: - ipv4_address: "{{ query('community.dns.lookup', inventory_hostname, type='A', nxdomain_handling = 'fail') | first }}" - ipv6_address: "{{ query('community.dns.lookup', inventory_hostname, type='AAAA', nxdomain_handling = 'fail') | first }}" + ipv4_address: "{{ query('community.dns.lookup', inventory_hostname, type='A', nxdomain_handling='fail') | first }}" + + + - name: Set IPv6 facts + become: false + when: + - not (ipv4_only | default(false)) + ansible.builtin.set_fact: + ipv6_address: "{{ query('community.dns.lookup', inventory_hostname, type='AAAA', nxdomain_handling='fail') | first }}" - name: Install basic utilities community.general.pacman: @@ -22,4 +29,6 @@ update_cache: true roles: - - sshd + # - hostname + - sudoers + # - sshd diff --git a/roles/hostname/tasks/main.yml b/roles/hostname/tasks/main.yml new file mode 100644 index 0000000..b98333a --- /dev/null +++ b/roles/hostname/tasks/main.yml @@ -0,0 +1,23 @@ +# code: language=ansible + +- name: Add IPv4 address to /etc/hosts + ansible.builtin.lineinfile: + path: /etc/hosts + line: "{{ ipv4_address }} {{ inventory_hostname }} {{ inventory_hostname_short }}" + +- name: Ensure IPv4 loopback exists in /etc/hosts + ansible.builtin.lineinfile: + path: /etc/hosts + line: "127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname_short }}" + +- name: Add IPv6 address to /etc/hosts + when: + - not (ipv4_only | default(false)) + ansible.builtin.lineinfile: + path: /etc/hosts + line: "{{ ipv6_address }} {{ inventory_hostname }} {{ inventory_hostname_short }}" + +- name: Set hostname + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + use: systemd diff --git a/roles/hostname/vars/main.yml b/roles/hostname/vars/main.yml new file mode 100644 index 0000000..f4366fe --- /dev/null +++ b/roles/hostname/vars/main.yml @@ -0,0 +1 @@ +# code: language=ansible diff --git a/roles/sshd/handlers/main.yml b/roles/sshd/handlers/main.yml index 6477757..e7b16db 100644 --- a/roles/sshd/handlers/main.yml +++ b/roles/sshd/handlers/main.yml @@ -1,4 +1,4 @@ -#code: language=ansible +# code: language=ansible - name: Restart sshd ansible.builtin.systemd_service: @@ -11,4 +11,4 @@ ansible.builtin.systemd_service: name: systemd-networkd.service scope: system - state: restarted \ No newline at end of file + state: restarted diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml index cecf069..97d36ba 100644 --- a/roles/sshd/tasks/main.yml +++ b/roles/sshd/tasks/main.yml @@ -1,4 +1,4 @@ -#code: language=ansible +# code: language=ansible - name: Disable link local addressing ansible.builtin.lineinfile: @@ -26,7 +26,7 @@ [Link] ActivationPolicy=always-up RequiredForOnline=yes - RequiredFamilyForOnline=both + RequiredFamilyForOnline={{ sshd_required_family_for_online }} create: false group: root insertbefore: '^\[Network\]\s*$' @@ -69,7 +69,23 @@ notify: - Restart sshd -- name: Configure sshd_config +- name: Add an ssh group + ansible.builtin.group: + local: false + name: ssh + state: present + system: true + +- name: Add user to ssh group + ansible.builtin.user: + append: true + groups: + - ssh + local: false + name: "{{ sshd_user }}" + state: present + +- name: Configure sshd_config (IPv4) ansible.builtin.lineinfile: backrefs: false create: true @@ -82,7 +98,28 @@ path: "/etc/ssh/sshd_config" regexp: "{{ item.pattern }}" state: present - loop: "{{ sshd_config_lines }}" + loop: "{{ sshd_ipv4_config_lines }}" + loop_control: + label: "{{ item.label }}" + notify: + - Restart sshd + +- name: Configure sshd_config (IPv6) + when: + - not (ipv4_only | default(false)) + ansible.builtin.lineinfile: + backrefs: false + create: true + encoding: "utf-8" + firstmatch: false + group: root + line: "{{ item.line }}" + mode: "0664" + owner: root + path: "/etc/ssh/sshd_config" + regexp: "{{ item.pattern }}" + state: present + loop: "{{ sshd_ipv6_config_lines }}" loop_control: label: "{{ item.label }}" notify: @@ -110,6 +147,8 @@ label: "{{ item.comment }}" - name: Configure UFW IPv6 rules + when: + - not (ipv4_only | default(false)) community.general.ufw: comment: "{{ item.comment }}" direction: "in" diff --git a/roles/sshd/vars/main.yml b/roles/sshd/vars/main.yml index 5501a37..7d58560 100644 --- a/roles/sshd/vars/main.yml +++ b/roles/sshd/vars/main.yml @@ -1,8 +1,13 @@ -#code: language=ansible +# code: language=ansible sshd_port: 22 -sshd_config_lines: +sshd_user: ladmin + +sshd_address_family: "{{ (ipv4_only | default(false)) | ansible.builtin.ternary('inet', 'any') }}" +sshd_required_family_for_online: "{{ (ipv4_only | default(false)) | ansible.builtin.ternary('ipv4', 'both') }}" + +sshd_ipv4_config_lines: - label: PubkeyAuthentication pattern: '^\s*#*\s*PubkeyAuthentication\s*(yes|no)$' line: 'PubkeyAuthentication yes' @@ -29,19 +34,24 @@ sshd_config_lines: line: 'UsePAM yes' - label: PermitRootLogin pattern: '^\s*#*\s*PermitRootLogin\s*(yes|no|prohibit-password)$' - line: 'PermitRootLogin prohibit-password' + line: 'PermitRootLogin no' - label: AddressFamily pattern: '^\s*#*\s*AddressFamily\s*(inet|inet6|any)$' - line: 'AddressFamily any' + line: "AddressFamily {{ sshd_address_family }}" - label: ListenAddress (IPv4) pattern: "^\\s*#*\\s*ListenAddress\\s*(0\\.0\\.0\\.0|{{ ipv4_address | replace('.', '\\.') }})$" line: "ListenAddress {{ ipv4_address }}" - - label: ListenAddress (IPv6) - pattern: "^\\s*#*\\s*ListenAddress\\s*(::|{{ ipv6_address}})$" - line: "ListenAddress {{ ipv6_address }}" - label: Port pattern: '^\s*#*\s*Port\s*[0-9]{1,5}$' line: "Port {{ sshd_port }}" + - label: AllowGroups + pattern: '^\s*#*\s*AllowGroups\s*.*$' + line: "AllowGroups ssh" + +sshd_ipv6_config_lines: + - label: ListenAddress (IPv6) + pattern: "^\\s*#*\\s*ListenAddress\\s*(::|{{ ipv6_address }})$" + line: "ListenAddress {{ ipv6_address }}" sshd_ufw_ipv4_rules: - comment: SSH Clients v4 @@ -55,4 +65,4 @@ sshd_ufw_ipv6_rules: - comment: "SSH Clients v6" source: "2600:4040:593d:8b30::/64" - comment: "SSH Servers v6" - source: "2600:4040:593d:8b10::/64" \ No newline at end of file + source: "2600:4040:593d:8b10::/64" diff --git a/roles/sudoers/tasks/main.yml b/roles/sudoers/tasks/main.yml new file mode 100644 index 0000000..371251e --- /dev/null +++ b/roles/sudoers/tasks/main.yml @@ -0,0 +1,76 @@ +# code: language=ansible + +- name: Ensure sudo is installed + community.general.pacman: + name: + - sudo + state: present + update_cache: true + +- name: Create the sudo group + ansible.builtin.group: + local: false + name: sudo + state: present + system: true + +- name: Get target users current groups + ansible.builtin.getent: + database: group + split: ':' + register: sudoers_user_groups_result + +- name: Set empty sudoers_user_target_groups + ansible.builtin.set_fact: + sudoers_user_target_groups: [] + +- name: Loop group list and select groups containing sudoer user + when: + - sudoers_user in sudoers_user_groups_result.ansible_facts.getent_group[item] + ansible.builtin.set_fact: + sudoers_user_target_groups: "{{ sudoers_user_target_groups + [item] }}" + loop: "{{ sudoers_user_groups_result.ansible_facts.getent_group.keys() | list }}" + loop_control: + label: "{{ item }}" + +- name: Filter sudoers_user_target_groups for wheel and users groups, and ensure it contains sudo group + ansible.builtin.set_fact: + sudoers_user_target_groups: "{{ ((sudoers_user_target_groups | difference(['wheel', 'users'])) + ['sudo']) | unique }}" + +- name: Add user to sudo group and remove from wheel/users + ansible.builtin.user: + append: false + comment: "{{ sudoers_user_comment }}" + groups: "{{ sudoers_user_target_groups }}" + local: false + name: "{{ sudoers_user }}" + state: present + +- name: Add sudoers entry + community.general.sudoers: + commands: + - ALL + defaults: + - '!fqdn' # Ensures using shortname only when assessing hostname in sudo rule + group: sudo + host: "{{ inventory_hostname_short }}" + name: sudo_group + nopassword: false + runas: root + state: present + sudoers_path: "/etc/sudoers.d" + validation: required + +- name: Remove default sudoers file + ansible.builtin.file: + path: /etc/sudoers.d/90-cloud-init-users + state: absent + +- name: Disable root login + ansible.builtin.user: + expires: 0 + name: root + password: '!' + password_lock: true + shell: /usr/bin/nologin + state: present diff --git a/roles/sudoers/vars/main.yml b/roles/sudoers/vars/main.yml new file mode 100644 index 0000000..a3b3857 --- /dev/null +++ b/roles/sudoers/vars/main.yml @@ -0,0 +1,4 @@ +# code: language=ansible + +sudoers_user: ladmin +sudoers_user_comment: "Local Administrator"