Compare commits

...

2 Commits

Author SHA1 Message Date
Fabio Scotto di Santolo
76f3e10ee4 Verify WireGuard handshakes and restore Podman networking 2026-09-15 22:38:56 +02:00
Fabio Scotto di Santolo
c899bb7192 Harden Rocky storage and sharing configuration 2026-09-15 22:05:48 +02:00
12 changed files with 181 additions and 85 deletions

View File

@@ -161,8 +161,11 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-i
use `10.0.0.2:4533` for Navidrome and `10.0.0.2:8384` for the Syncthing GUI. Syncthing does not use host networking: use `10.0.0.2:4533` for Navidrome and `10.0.0.2:8384` for the Syncthing GUI. Syncthing does not use host networking:
its GUI, transfer, QUIC and discovery ports are explicitly published only on `10.0.0.2`; native transfer/discovery does not use the HTTP proxy. its GUI, transfer, QUIC and discovery ports are explicitly published only on `10.0.0.2`; native transfer/discovery does not use the HTTP proxy.
- `wireguard_overlay` manages the required `wg0` path between Prometheus and Atlas, persists private keys only on their - `wireguard_overlay` manages the required `wg0` path between Prometheus and Atlas, persists private keys only on their
respective hosts, and exchanges only derived public keys. The initial run must include both hosts. Prometheus respective hosts, exchanges only derived public keys, and verifies a real peer handshake. The initial run must
opens `51820/udp`; the Atlas backend role admits service ports only in the WireGuard firewalld zone. include both hosts. Prometheus
opens `51820/udp`; after creating the WireGuard firewalld zone, restore Prometheus' rootful Podman networking with
`podman network reload --all` so the existing proxy stack retains container DNS. The Atlas backend role admits
service ports only in the WireGuard firewalld zone.
## Atlas NAS TODO ## Atlas NAS TODO
- Provide the required Vault variables and validate the first remote bootstrap on the real Rocky Linux 9 host. - Provide the required Vault variables and validate the first remote bootstrap on the real Rocky Linux 9 host.

View File

@@ -219,13 +219,18 @@ clients use NFSv4 and Windows/WSL clients use SMB; both are restricted to the co
For the first run, provide `vault_atlas_admin_password_hash`, `vault_atlas_samba_password`, and For the first run, provide `vault_atlas_admin_password_hash`, `vault_atlas_samba_password`, and
`vault_atlas_immich_db_password`. Bootstrap the host through its `vault_atlas_immich_db_password`. Bootstrap the host through its
existing administrator: existing administrator. Open `51820/udp` towards Prometheus in the provider firewall first, then
include both WireGuard peers in the same idempotent playbook run:
```bash ```bash
ansible-playbook ansible/site.yml --limit atlas \ ansible-playbook ansible/site.yml --limit prometheus,atlas \
-e atlas_connection_username=<existing-admin> -e atlas_connection_username=<existing-admin> \
-e atlas_create_pool=true
``` ```
The explicit pool gate is safe to repeat: the role creates the RAIDZ2 pool only when it is absent.
WireGuard waits for a real peer handshake before the play continues.
`vault_atlas_admin_password_hash` must be an `/etc/shadow`-compatible hash, not a clear-text `vault_atlas_admin_password_hash` must be an `/etc/shadow`-compatible hash, not a clear-text
Cockpit password. Subsequent runs use `atlas_admin_username`. Atlas declares storage, sharing, and its Cockpit password. Subsequent runs use `atlas_admin_username`. Atlas declares storage, sharing, and its
LAN firewall rules enabled. Before the first apply, check the existing pool and mountpoints, LAN subnet, LAN firewall rules enabled. Before the first apply, check the existing pool and mountpoints, LAN subnet,
@@ -262,7 +267,9 @@ storage paths from the `zpool` mounted at `/zpool`: music is read-only at
containers. The backend role never creates the pool. The separate `wireguard_overlay` role manages `wg0` containers. The backend role never creates the pool. The separate `wireguard_overlay` role manages `wg0`
between Prometheus (`10.0.0.1`) and Atlas (`10.0.0.2`), generating private keys once between Prometheus (`10.0.0.1`) and Atlas (`10.0.0.2`), generating private keys once
on their respective hosts and exchanging only public keys through Ansible. Prometheus alone opens on their respective hosts and exchanging only public keys through Ansible. Prometheus alone opens
`51820/udp` publicly. Backend ports are admitted only in the WireGuard firewalld zone. `51820/udp` publicly. When the WireGuard zone is created, Ansible reloads firewalld and immediately
reloads Prometheus' rootful Podman networks so the existing proxy stack retains container DNS and
connectivity. Backend ports are admitted only in the WireGuard firewalld zone.
`backend_phase1_start_services` stays false during the application-state transfer, so the first real `backend_phase1_start_services` stays false during the application-state transfer, so the first real
backend run renders the Quadlets without creating an empty Atlas database. After stopping Navidrome backend run renders the Quadlets without creating an empty Atlas database. After stopping Navidrome

View File

@@ -5,6 +5,9 @@ platform_package_manager: dnf
platform_service_manager: systemd platform_service_manager: systemd
rocky_openzfs_release_rpm: https://zfsonlinux.org/epel/zfs-release-3-0.el9.noarch.rpm rocky_openzfs_release_rpm: https://zfsonlinux.org/epel/zfs-release-3-0.el9.noarch.rpm
rocky_openzfs_gpg_key_url: >-
https://raw.githubusercontent.com/zfsonlinux/zfsonlinux.github.com/master/zfs-release/RPM-GPG-KEY-openzfs-key2
rocky_openzfs_gpg_key_fingerprint: 7DC7 299D CF7C 7FD9 CD87 701B A599 FD5E 9DB8 4141
rocky_syncthing_version: 2.1.3 rocky_syncthing_version: 2.1.3
rocky_syncthing_archive_checksum: sha256:f929eb8e5b72a85543eeeefb2c38f34a68e0c530e70758a2905b78840c76602c rocky_syncthing_archive_checksum: sha256:f929eb8e5b72a85543eeeefb2c38f34a68e0c530e70758a2905b78840c76602c
rocky_syncthing_archive_url: >- rocky_syncthing_archive_url: >-

View File

@@ -28,8 +28,12 @@ atlas_manage_firewall: true
atlas_firewalld_zone: public atlas_firewalld_zone: public
atlas_zfs_pool: zpool atlas_zfs_pool: zpool
# Populate only for the first pool bootstrap with four real persistent disk paths. # Populate only for the first pool bootstrap with four real persistent disk paths.
# Example: /dev/disk/by-id/ata-Seagate_IronWolf_... # Confirmed empty 4 TB IronWolf data disks; the NVMe system disk is intentionally excluded.
atlas_zpool_disks: [] atlas_zpool_disks:
- /dev/disk/by-id/ata-ST4000VN006-3CW104_WW6AC1XM
- /dev/disk/by-id/ata-ST4000VN006-3CW104_WW6A73T2
- /dev/disk/by-id/ata-ST4000VN006-3CW104_WW6A6VJK
- /dev/disk/by-id/ata-ST4000VN006-3CW104_WW6AC1LM
atlas_create_pool: false atlas_create_pool: false
atlas_zfs_dataset_work: work atlas_zfs_dataset_work: work
atlas_zfs_dataset_archive: archive atlas_zfs_dataset_archive: archive

View File

@@ -19,6 +19,7 @@ wireguard_overlay_enabled: true
wireguard_address: 10.0.0.1/24 wireguard_address: 10.0.0.1/24
wireguard_listen_port: 51820 wireguard_listen_port: 51820
wireguard_enable_ipv4_forwarding: true wireguard_enable_ipv4_forwarding: true
wireguard_reload_rootful_podman_networks: true
wireguard_peers: wireguard_peers:
- name: atlas - name: atlas
host: atlas host: atlas

View File

@@ -27,6 +27,14 @@
name: epel-release name: epel-release
state: present state: present
- name: Import official OpenZFS EL9+ signing key
tags: [packages, storage]
ansible.builtin.rpm_key:
state: present
key: "{{ rocky_openzfs_gpg_key_url }}"
fingerprint: "{{ rocky_openzfs_gpg_key_fingerprint }}"
when: rocky_manage_openzfs_repo | bool
- name: Install official OpenZFS repository package - name: Install official OpenZFS repository package
tags: [packages, storage] tags: [packages, storage]
ansible.builtin.dnf: ansible.builtin.dnf:

View File

@@ -16,6 +16,7 @@
- name: Inspect declared Atlas pool disks - name: Inspect declared Atlas pool disks
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ item }}" path: "{{ item }}"
follow: true
loop: "{{ atlas_zpool_disks }}" loop: "{{ atlas_zpool_disks }}"
loop_control: loop_control:
label: "{{ item }}" label: "{{ item }}"

View File

@@ -56,6 +56,16 @@
notify: Reload NFS exports notify: Reload NFS exports
when: atlas_manage_sharing | bool when: atlas_manage_sharing | bool
- name: Ensure Atlas NFS configuration drop-in directory exists
tags: [atlas, sharing]
ansible.builtin.file:
path: /etc/nfs.conf.d
state: directory
owner: root
group: root
mode: "0755"
when: atlas_manage_sharing | bool
- name: Configure Atlas NFSv4-only service - name: Configure Atlas NFSv4-only service
tags: [atlas, sharing] tags: [atlas, sharing]
ansible.builtin.template: ansible.builtin.template:
@@ -214,9 +224,22 @@
- atlas_manage_sharing | bool - atlas_manage_sharing | bool
- not ansible_check_mode - not ansible_check_mode
- name: Read Atlas file-sharing service state - name: Check active Atlas file-sharing services
tags: [atlas, sharing, services, security] tags: [atlas, sharing, services, security]
ansible.builtin.service_facts: ansible.builtin.command:
argv:
- systemctl
- is-active
- --quiet
- "{{ item }}"
loop:
- nfs-server.service
- smb.service
loop_control:
label: "{{ item }}"
register: atlas_file_sharing_service_activity
changed_when: false
failed_when: false
when: when:
- atlas_manage_sharing | bool - atlas_manage_sharing | bool
- not ansible_check_mode - not ansible_check_mode
@@ -225,10 +248,7 @@
tags: [atlas, sharing, services, security] tags: [atlas, sharing, services, security]
ansible.builtin.assert: ansible.builtin.assert:
that: that:
- ansible_facts.services['nfs-server.service'] is defined - atlas_file_sharing_service_activity.results | map(attribute='rc') | list == [0, 0]
- ansible_facts.services['nfs-server.service'].state == 'running'
- ansible_facts.services['smb.service'] is defined
- ansible_facts.services['smb.service'].state == 'running'
fail_msg: Atlas NFSv4 or SMB3 did not start after its managed configuration was applied. fail_msg: Atlas NFSv4 or SMB3 did not start after its managed configuration was applied.
when: when:
- atlas_manage_sharing | bool - atlas_manage_sharing | bool

View File

@@ -4,7 +4,12 @@ PubkeyAuthentication yes
PasswordAuthentication no PasswordAuthentication no
KbdInteractiveAuthentication no KbdInteractiveAuthentication no
AuthenticationMethods publickey AuthenticationMethods publickey
AuthorizedKeysFile {% for key in atlas_admin_ssh_keys %}%h/.ssh/authorized_keys.d/{{ key.name }}{% if not loop.last %} {% endif %}{% endfor %} AuthorizedKeysFile {{
atlas_admin_ssh_keys
| map(attribute='name')
| map('regex_replace', '^', '%h/.ssh/authorized_keys.d/')
| join(' ')
}}
X11Forwarding no X11Forwarding no
AllowTcpForwarding {{ atlas_ssh_allow_tcp_forwarding }} AllowTcpForwarding {{ atlas_ssh_allow_tcp_forwarding }}
AllowAgentForwarding no AllowAgentForwarding no

View File

@@ -10,6 +10,9 @@ wireguard_mtu: 1420
wireguard_firewalld_zone: wireguard wireguard_firewalld_zone: wireguard
wireguard_public_firewalld_zone: public wireguard_public_firewalld_zone: public
wireguard_enable_ipv4_forwarding: false wireguard_enable_ipv4_forwarding: false
wireguard_reload_rootful_podman_networks: false
wireguard_handshake_retries: 12
wireguard_handshake_delay: 5
wireguard_peers: [] wireguard_peers: []
wireguard_packages: wireguard_packages:
- wireguard-tools - wireguard-tools

View File

@@ -132,6 +132,20 @@
- wireguard_firewalld_zone_result is changed - wireguard_firewalld_zone_result is changed
- not ansible_check_mode - not ansible_check_mode
- name: Restore rootful Podman networking after firewalld reload
ansible.builtin.command:
argv:
- podman
- network
- reload
- --all
register: wireguard_podman_network_reload
changed_when: wireguard_podman_network_reload.stdout_lines | length > 0
when:
- wireguard_firewalld_zone_result is changed
- wireguard_reload_rootful_podman_networks | bool
- not ansible_check_mode
- name: Assign the WireGuard interface to its firewalld zone - name: Assign the WireGuard interface to its firewalld zone
ansible.posix.firewalld: ansible.posix.firewalld:
interface: "{{ wireguard_interface }}" interface: "{{ wireguard_interface }}"
@@ -156,3 +170,23 @@
state: started state: started
daemon_reload: true daemon_reload: true
when: not ansible_check_mode when: not ansible_check_mode
- name: Apply pending WireGuard handlers before verification
ansible.builtin.meta: flush_handlers
when: not ansible_check_mode
- name: Wait for every WireGuard peer handshake
ansible.builtin.command:
argv:
- wg
- show
- "{{ wireguard_interface }}"
- latest-handshakes
register: wireguard_latest_handshakes
changed_when: false
retries: "{{ wireguard_handshake_retries }}"
delay: "{{ wireguard_handshake_delay }}"
until:
- wireguard_latest_handshakes.stdout_lines | length == wireguard_peers | length
- wireguard_latest_handshakes.stdout_lines | select('search', '\t0$') | list | length == 0
when: not ansible_check_mode

View File

@@ -1,71 +1,78 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
34663237313764396365646239613936373362306636663862373964343131636362333265306564 31386434333363613930316363393564373332303236306233643365386639346631336232373361
3739343661336433303637343066626263646530663464380a636363303065643130336239663335 3732633931376438313835373537666438383664306266380a633531316432343166323361303465
64323265303964383635366235656163353333393166363635333831343531356339363939333530 39306136386664356163346266303963373839373763343136346135633236333333326331313063
6266306339323862300a353530623639643836323135363566653161356630316565323233333937 6264306265373865310a373735393632373861333433326632303931633732636535326264346537
34343637383766623036633435346131393935303736613963653762663336383336366666333961 39633766326361666432396432623132616666363462373237623664363664373362346366383230
39346336356563383464306364373438666638353731616566656164386365373966623230313933 65326665303762356233356531306331333231376163353638363936626562623937323166623065
61343237373034616163363733326139306665366339383866316666396138373164366363613164 62633165383033303362336238343037353930396430336537363565333132666532323662653262
34313638373435623439326164396264393838316263633630653935626635333362386132313864 65373531313264353938666161373064393239653165666462336665323962336134343432316134
34643937653730336637633137623937346131396330356665626564666561343630383562646563 32373361613539356262313333663964623034313230356439626139383539326261663765373034
65393532656162323931663266323635343437613639373731623631636533326533396662373032 36633933366662656464306561393130373238313730336638663932633935313037363133636266
61386436613235353638613731313835373137643533363936326566316165636137653438393238 36663935303735623132663464376633306431396662306166393831313566323238363865303162
37343765356366626666363162663262313663393038323531346461343731396334623339323865 66303732376530653435613966373832333161333137366230613166303061333433336461386234
65323464323465326364633263346561316364336431323763386138383132643136663630636439 63393030616662373666643164663862653037383336323766646330653131623930353265336231
66393564343462663933626464623866613563376234663430353837343139346363313539313839 39646335353635616465663763306262353931316562616437313362616136623735646535616431
65386134653932393464356562346238336535323130373235303964313664363031623137383365 33363439623361343231363663363535663265366166346439623935323632366336363135373462
39356530666564383334626330613039303135626237393233353362363033653239343634356261 62646662316538323734333334393566333463653833326162663065646634363336373865623932
35356533643937393834383930336633623932363435646261633837663536356462356535613030 33646533636638386534366561663930613536663935663638313137646537626431393035653466
63626438393466616238383030643631343661613630623738323933386434636461383136376261 36623435613966323166363630383531656436373366343364346439343034333934623836336636
39616137336134663130613234633266383434336133353334373063366232663839316536376565 38653534343563393434646430306662343435653465363439326261373537666233353731306436
62643766316464393135633564373062663335633533626631326534333232323364343133393534 35323739336361343665633239366633393530346335396635316238323435663466316235376536
63396465363066643261303334363966343935323635383938616539323838393235373730313832 38303839313433643038353236616632626363653339346334303136306138336461383831626536
37313235316264643932343062353162353534653963336634373264343937653035333735393766 39303966393034333739363061363865326165303236656438316537396463383935393764346135
32393765643535383535616335613136336566653637343835366538633737313962336531333533 66323632323833353833643434316566326366633562666262386232653730303038613336663264
32376163613861313139393863646331386133363435373364316134376533316136396533353161 62636332383834393861373665393364653362636339346632303463386565633830336363393065
39353737633439656466396561623938646438636664373438323866613636653963393938346363 31383530613161366436323163393366386635316562633436383134623061353937326363396439
63616366313030623464613832336566356339343931643436393138346463356161653039666632 38636438396637616362373937666361303536376164636533653536306338356263313965623336
63396465306630336634316632663930613637643331363236353363383162333865383536623235 32633461623861643138613734313164633562613932386163643062353636376266633166373838
33306232333439383135306266656666616135363433636332663865633234653530666435356164 39613438653531316333663736366161313832613830353566356461393435656234383037353335
34336338343831633966666334643436373162336333313666613766656638656530373663383036 32343661376266353538643531313239306432646335383734623233373063316430383362643531
39366134326134323435326434383637313334336562386638346333303666396336653231396463 35393263343534363936373361316265653934383735663933663365363564663966646335353337
37633131393564656265646530373262393231373663303133323566666630366530626439353062 63366365383466393765336533363130643236313331633537346237353631623334633330376164
37323138656431653235303439653133303831383864376562353363373466396334373063616561 32616530623032663761643437336536323332343130393339313232623364656334613233323833
34343932383433323331363633643432303633323337656261386339653263393832396539633938 64346637343738386335343631333035636337633732333662663763326362636432646136353064
36303634336162613366376435366530663632656263363436666532663561636465613736303962 30393061326435323837633632333765623931663265326137373135303035623464333366653566
35663035303437313933373533336639323563376539303730323933346636626462336530303135 66613133396339376264313964353932396136613538383264363865633536373839663465333437
65623036326663363130326438376161303463363839653564623462663561346236393262643035 37613765626131343330653063663764346364316264363635653438396331363263623562333735
63363631663834303734393330353730333234626236616636326236376133633635376435326630 30646563303439663639376430336336383761363365353838613036333032306434623661636138
33383035363466326139336431353937363236303134633662653066356164656366353038366264 63616439636437663732386164346365643834376631303263376563323662373734653631613730
63343261393865303163633166663433373362663261343166303932313061393463346662366165 31373039656238303462643930303531613931373065316435303661343862623034653364653736
31396333633964636265326539396533343932363433636438363137356430663764373835373566 37613835616630316133333130633631653639336266313438633166316539373433333661613839
63633265323537353666653862623030646661366531646163303261363035356138346538623466 32356139366232313336343062323265366563633735383661393335386163653133313664613264
63323235393835353864303362356465393739303531653139316338643136346164366630383635 63303739323863333439316461366137656434666366306466356633306663623730653939663430
64376261376465303134383938346639386563363532313532663532656462663362643339353733 39313764663534316562326435316264633236373834323665356266346532323565323532333438
61356566613638336639323235393132623032303639393065363238366337333237363863326365 33306237623430613463393164383332356533303433343465343930636563363862373330613632
32383563313062363166656137626639363138363236383763663262363531646133356434633636 38643937613263313435626166313464316133373338373261666331653436373063393162636339
39653666626539356538313234636634386438386434303336313337323638383863376163356365 66356434663239646334383433626566336433653265336332323866633666646132663836313537
32346330306361343337373636376239643538396334303038636664633666306562316435303332 66663766306438396131623533613834626331653731323137303539303835306632663132616363
33663238336336353237396139633133386439376162616439313862323462613636646262326162 64303438353836613136623562626664326364656133383865383730373762666539383036396337
62653237636161393938336435333730636237313363663835323932613933373466343163646331 66393636343561333435313032353939316138306336316337353861383238326136373265663433
37383466386437303433616162323433343761623831323163363331613164376565623633356335 62366566343866626336646466386561353061343735306565383437333931613635393034363430
61366336393938383036623962353031333735376266643866363562653965306335636531376138 37633765663239643435623066313331353862393966306563393838386334393162306562363062
64303764343565376561623933663035646163343235646565666465323864323065636462383962 61633363386564373834383432323861323364623365306439353631323463326461383039356466
66633336313032323333366237366561613734376132346537373136376639623163313837613235 34396464653233626435656463326439303665633532656639376633353932666630626564616564
37393332323539303338353365373766383537626162613738343534396339613336323437646466 34326638383634353033326232646339393638663637313136653763336265616635326666336530
61623636303665623262633632653633373931373933366138316565353938656232313961373865 33663261376262626136346265656130653831636662306132393837306135643831353534626636
66393230663532616532666561666465313361316432376432313034343333636566626564323066 34383762386665666363313932336632326230646439663366663037323562633630373137333232
34613331633439626233333939303461393239623262376265393132313134653537396165343262 37393164656137303131313738396131613561306332356436303436636338623233343637363332
39303135366566623037646265616630313638383732323064303237626334383261303230383162 36613137316337666461333237373266326238303531396432383461616239316630346230303735
66633164353330666436376666316236363164373230633062636430663632393837366630643539 63636535383766353338643932366339333130663632386337643932636630316432313465393766
33663233306464616165613337633030656661393336613036333036666565356232333966616361 39613065623631316165313134386231616165366266323634643632626230303861376461323433
62353465643839373266333866353135396262303461666465393736636638636462666136613461 35346137326563646332303334313530383464373838373633363635373766333362386466323836
31373130663563393833633930323766656530616261323363383333306631653563363734343034 32613236646561343365656239346239353866663336393930356238653463336361333033643331
64383962346463663861356362346437346630353835383062373433396335343931343462386165 61323430663031383239353363616666336637666230663633616464616638303966343631386632
33636266306563346431376438333463653165663962346262633037393238393135323536633866 32333735643936353638666336303133356435396338653465323234316234626536666635333238
65623663323365643233346232613936373562363532373162613533316335376138366432316362 38313661303466333464666538363938656631396666643566343763396638336663376430646532
30303662363436636263313064363235393632353430386438663833666665316561323431396430 38666234653330646262633062356238343536336637356432313137313561363937363936383364
64623435323461313763613730643762633535393533333635313435613665383535633161353539 30643937383833663339643862363234643765386164316138636565643434373734383339363138
37666665313730663366646537363963636631363836353437663963656566353962633935383263 36323163633837326132393365333236633264386664373234313061373835346634663137383837
38663930373135353336326530396636373938333934326630303138643563633934656566663963 62666561353532303663346365343131316233633163323938623066656332383030393864363536
6461373661386230356262643732373861366139323261303961 38383939383935613432613837333863313239653831333438383133343763633838353964353161
61323462343835613937653465633563306462613631323762656437626133336638396663646362
30323661383134653336366234663333336261353162373030626266656336356233316265636661
34303865313433633138363936373561636537353831373033303163646436303932626138356633
63656364353163313037613262396338636230646330666331616534313466306361363433656132
66633231626665303165346339373764666264313838313063323732653837383736633235363064
37353632336238623366313432376163653535656134633634313065356533343933666135396633
30613134646132613637656461303431613064393438363231383464663765316638