Configure Aegis host DNS and NFS support

This commit is contained in:
Fabio Scotto di Santolo
2026-09-16 10:19:06 +02:00
parent 160d63c02d
commit a97c64b08f
5 changed files with 133 additions and 10 deletions

View File

@@ -48,6 +48,8 @@ Ansible-driven personal infrastructure repo for Fedora and Void desktops, Fedora
- Rocky server after activation: `ansible-playbook ansible/site.yml --limit <host> --check --diff`
- Atlas NAS: `ansible-playbook ansible/site.yml --limit atlas --check --diff`
- Aegis IoT: `ansible-playbook ansible/site.yml --limit aegis --check --diff`
- Aegis NFS client layer: `ansible-playbook ansible/site.yml --limit aegis --tags nfs --list-tasks`
- Aegis host DNS: `ansible-playbook ansible/site.yml --limit aegis --tags dns --check --diff`
- Focused checks:
- Emacs is disabled by default; temporary Emacs check: `ansible-playbook ansible/site.yml --limit <host> --tags emacs --check --diff -e emacs_enabled=true`
- AI coding agents: `ansible-playbook ansible/site.yml --limit <host> --tags ai_agents --check --diff`
@@ -221,14 +223,18 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-i
- `aegis` is a remote Fedora IoT Raspberry Pi 4 node. Bootstrap it once with
`ansible/bootstrap/aegis.bu`; the remaining configuration is applied by `profile_aegis` over SSH.
- Fedora IoT is immutable. Do not add it to mutable Fedora package or shared dotfile roles.
- `profile_aegis` owns rootful Podman Quadlets, persistent container state under `/var/lib`, the
Podman auto-update timer, LAN-restricted firewalld rules, and SSH hardening. Keep
`aegis_lan_subnet` and `aegis_adguard_web_port` host-specific; SSH permits only the declared
- `profile_aegis` owns the `nfs-utils` rpm-ostree layer used as the Atlas NFS client and reports the
required reboot without initiating it. It also owns rootful Podman Quadlets, persistent container
state under `/var/lib`, the Podman auto-update timer, LAN-restricted firewalld rules, and SSH hardening. Keep
`aegis_lan_subnet`, `aegis_adguard_web_port`, and `aegis_network_connection_uuid` host-specific;
SSH permits only the declared
key-authenticated users, never root or password authentication. Keep Apple IDs and other
credentials in Vault and use `no_log` for their rendering.
- `aegis_adguard_web_port` defaults to `80`. The initial AdGuard Home wizard port `3000` is intentionally unmanaged: open and close it manually only while
completing initial setup. Disable the local systemd-resolved stub through `profile_aegis` before
AdGuard binds port 53; keep
`/etc/resolv.conf` linked to `/run/systemd/resolve/resolv.conf` so Aegis retains router-provided DNS.
`/etc/resolv.conf` linked to `/run/systemd/resolve/resolv.conf`. LAN clients may use AdGuard, but
Aegis must use the independent upstream DNS declared by `aegis_host_dns_servers` so Greenboot does
not depend on the AdGuard container during startup.
- iCloudPD requires post-deployment interactive MFA initialization; its cookie/configuration state is
persisted in `/var/lib/icloudpd/config`.

View File

@@ -193,12 +193,17 @@ ansible/bootstrap/generate-aegis-ign.sh --write IMAGE DEVICE
The controller manages it remotely as `pi@aegis`; unlike local desktop profiles, Aegis is
intentionally an SSH inventory target. `profile_aegis` manages rootful Podman Quadlets for AdGuard
Home and iCloudPD, persistent data under `/var/lib`, the Podman auto-update timer, LAN-restricted
firewalld rules, SSH key-only access for `pi`, and `wake-ikaros`. Set the host-local
`aegis_lan_subnet` and `aegis_adguard_web_port` values before applying it. The playbook permits
firewalld rules, SSH key-only access for `pi`, the `nfs-utils` rpm-ostree layer required by the
Atlas NFS client, and `wake-ikaros`. A new layered package deployment requires a manual reboot; the
role reports this condition but never reboots Aegis automatically. Set the host-local
`aegis_lan_subnet`, `aegis_adguard_web_port`, and `aegis_network_connection_uuid` values before
applying it. The playbook permits
AdGuard Home HTTP on port `80`; the initial wizard port `3000` is intentionally unmanaged and must be
opened and closed manually during initial setup. The profile disables the local systemd-resolved DNS
stub and points `/etc/resolv.conf` to its full resolver data, freeing port 53
for AdGuard while retaining DNS learned from the router. Define
stub and points `/etc/resolv.conf` to its full resolver data, freeing port 53 for AdGuard. LAN clients
may use AdGuard on Aegis, while Aegis itself uses the independent upstream DNS declared by
`aegis_host_dns_servers`; this prevents Greenboot from depending on the AdGuard container during
startup. Reboot Aegis after changing its NetworkManager DNS profile. Define
`vault_aegis_icloudpd_apple_id` in Vault before applying it. iCloudPD still requires interactive MFA
initialization after its first deployment.
@@ -213,6 +218,21 @@ ANSIBLE_LOCAL_TEMP=/tmp/ansible-local \
ansible-playbook ansible/site.yml --limit aegis --check --diff --ask-become-pass
```
Apply only the independent host DNS configuration, then reboot Aegis manually:
```bash
ANSIBLE_LOCAL_TEMP=/tmp/ansible-local \
ansible-playbook ansible/site.yml --limit aegis --tags dns --ask-become-pass
```
Layer the Atlas NFS client package independently, then reboot Aegis manually when the role reports
that the new deployment is ready:
```bash
ANSIBLE_LOCAL_TEMP=/tmp/ansible-local \
ansible-playbook ansible/site.yml --limit aegis --tags nfs --ask-become-pass
```
## NAS
`atlas` is a Rocky Linux 9 NAS reached through SSH. Normally its pool already exists and the profile

View File

@@ -9,6 +9,12 @@ ansible_ssh_use_tty: false
aegis_lan_subnet: 192.168.178.0/24
aegis_adguard_web_port: 80
aegis_network_connection_name: FRITZ!Box 7530 NR
aegis_network_connection_uuid: a52fda3d-3eb6-351f-bf04-753edcb76944
aegis_host_dns_servers:
- 192.168.178.1
aegis_host_dns_search_domains:
- fritz.box
aegis_ssh_authorized_keys:
- name: ikaros
key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINrIxXjA3ffPwziKGR5gzc4gAoBehQPlnEMcXF4Wl0ZS ikaros"

View File

@@ -1,5 +1,11 @@
---
aegis_hostname: aegis
aegis_layered_packages:
- nfs-utils
aegis_network_connection_name: ""
aegis_network_connection_uuid: ""
aegis_host_dns_servers: []
aegis_host_dns_search_domains: []
aegis_adguard_image: docker.io/adguard/adguardhome:latest
aegis_icloudpd_image: docker.io/boredazfcuk/icloudpd:latest
aegis_icloudpd_folder_structure: '{:%Y/%m/%d}'

View File

@@ -1,4 +1,18 @@
---
- name: Manage Aegis layered packages
tags: [aegis, packages, nfs]
community.general.rpm_ostree_pkg:
name: "{{ aegis_layered_packages }}"
state: present
register: aegis_layered_packages_result
when: aegis_layered_packages | length > 0
- name: Report reboot required for Aegis layered packages
tags: [aegis, packages, nfs]
ansible.builtin.debug:
msg: Reboot Aegis to activate the newly layered packages, then rerun the playbook.
when: aegis_layered_packages_result.needs_reboot | default(false)
- name: Require Aegis iCloudPD Apple ID
tags: [aegis, icloudpd]
ansible.builtin.assert:
@@ -8,15 +22,86 @@
no_log: true
- name: Require completed Aegis network placeholders
tags: [aegis, firewall, services]
tags: [aegis, dns, firewall, network, services]
ansible.builtin.assert:
that:
- aegis_lan_subnet != 'CHANGEME_LAN_SUBNET'
- aegis_firewalld_zone | length > 0
- aegis_adguard_web_port | int > 0
- aegis_adguard_web_port | int < 65536
- aegis_network_connection_name | length > 0
- aegis_network_connection_uuid | length > 0
- aegis_host_dns_servers | length > 0
- ansible_facts["default_ipv4"]["address"] not in aegis_host_dns_servers
- aegis_ssh_allowed_users | length > 0
fail_msg: Define the Aegis LAN subnet, firewalld zone, AdGuard web port, and SSH users.
fail_msg: >-
Define the Aegis LAN subnet, firewalld zone, AdGuard web port, independent host DNS,
NetworkManager connection, and SSH users. Aegis must not use its own address as upstream DNS.
- name: Verify the declared Aegis NetworkManager connection exists
tags: [aegis, dns, network, services]
ansible.builtin.command:
argv:
- nmcli
- --get-values
- connection.id
- connection
- show
- uuid
- "{{ aegis_network_connection_uuid }}"
register: aegis_network_connection
changed_when: false
failed_when: >-
aegis_network_connection.rc != 0
or aegis_network_connection.stdout != aegis_network_connection_name
- name: Read the current Aegis host DNS configuration
tags: [aegis, dns, network, services]
ansible.builtin.command:
argv:
- nmcli
- --get-values
- ipv4.ignore-auto-dns,ipv4.dns,ipv4.dns-search,ipv6.ignore-auto-dns
- connection
- show
- uuid
- "{{ aegis_network_connection_uuid }}"
register: aegis_host_dns_current
changed_when: false
- name: Configure independent upstream DNS for the Aegis host
tags: [aegis, dns, network, services]
ansible.builtin.command:
argv:
- nmcli
- connection
- modify
- uuid
- "{{ aegis_network_connection_uuid }}"
- ipv4.ignore-auto-dns
- "yes"
- ipv4.dns
- "{{ aegis_host_dns_servers | join(',') }}"
- ipv4.dns-search
- "{{ aegis_host_dns_search_domains | join(',') }}"
- ipv6.ignore-auto-dns
- "yes"
register: aegis_host_dns_profile
when: >-
aegis_host_dns_current.stdout_lines !=
[
'yes',
aegis_host_dns_servers | join(','),
aegis_host_dns_search_domains | join(','),
'yes'
]
changed_when: true
- name: Report Aegis reboot required for host DNS changes
tags: [aegis, dns, network, services]
ansible.builtin.debug:
msg: Reboot Aegis to activate its independent upstream DNS before testing another OS update.
when: aegis_host_dns_profile.changed | default(false)
- name: Set Aegis hostname
tags: [aegis, services]