Add dormant Rocky server profile (#2)

* Add dormant Rocky server profile

* feat: activate Rocky server profile for prometheus

* fix: complete Rocky server migration tooling

* Remove FreeBSD profile

* feat: add Aegis Fedora CoreOS profile

* docs: define Git Flow branch prefixes

* Add Aegis TPM-backed btrfs storage

Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com>

* Preserve existing Aegis filesystem tables

Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com>

* Remove unsupported Aegis TPM storage

Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com>

* Configure Aegis pi Btrfs storage

Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com>

* Mount Aegis Btrfs as root

Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com>

* Handle Maven on Mise

* Feature/aegis coreos (#7)

* feat(aegis): add ARM image bootstrap workflow

* feat(aegis): manage firewall and SSH hardening

* feat(aegis): harden Fedora IoT services

* chore(aegis): remove local TLS configuration

* fix(aegis): restore supported Fedora IoT bootstrap

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: fscotto <17803710+fscotto@users.noreply.github.com>
This commit is contained in:
Fabio Scotto di Santolo
2026-09-08 10:36:29 +02:00
committed by GitHub
parent ae1ca44aa7
commit eab66b6d3d
20 changed files with 507 additions and 271 deletions

View File

@@ -16,17 +16,39 @@ rocky_syncthing_archive_url: >-
~ '.tar.gz'
}}
rocky_manage_openzfs_repo: false
rocky_manage_syncthing_binary: false
rocky_manage_docker_repo: false
rocky_manage_github_cli_repo: false
rocky_docker_repo_url: https://download.docker.com/linux/rhel/docker-ce.repo
rocky_docker_repo_file: /etc/yum.repos.d/docker-ce.repo
rocky_github_cli_repo_url: https://cli.github.com/packages/rpm/gh-cli.repo
rocky_github_cli_repo_file: /etc/yum.repos.d/gh-cli.repo
enabled_services:
- firewalld
rocky_common_packages:
- bash-completion
- bat
- fzf
- git
- jq
- tree
- unzip
- vim-enhanced
- wget
- zip
- zoxide
rocky_packages_base:
- cockpit
- dnf-plugins-core
- firewalld
- nfs-utils
- openssh-server
- policycoreutils-python-utils
- rsync
- samba
- sudo
- zfs
rocky_profile_packages: []
rocky_docker_packages: []
rocky_docker_conflicting_packages: []

View File

@@ -0,0 +1,59 @@
---
rocky_manage_docker_repo: true
rocky_manage_github_cli_repo: true
rocky_profile_packages:
- avahi
- curl
- dmidecode
- dosfstools
- gcc
- gcc-c++
- git-delta
- gh
- gnupg2
- htop
- make
- nmap-ncat
- nodejs
- parted
- pciutils
- pinentry
- ranger
- ripgrep
rocky_docker_packages:
- containerd.io
- docker-buildx-plugin
- docker-ce
- docker-ce-cli
- docker-compose-plugin
rocky_docker_conflicting_packages:
- docker
- docker-client
- docker-client-latest
- docker-common
- docker-engine
- docker-latest
- docker-latest-logrotate
- docker-logrotate
- podman
- runc
enabled_services:
- firewalld
- docker
server_firewall_backend: firewalld
server_firewalld_zone: public
server_firewalld_services:
- ssh
server_firewalld_ports: []
server_firewalld_absent_ports:
- 22000/tcp
- 22000/udp
- 21027/udp
server_sshd_service_name: sshd
server_compose_selinux_mount_option: Z
server_syncthing_enabled: false

View File

@@ -25,6 +25,9 @@ profile_packages:
- rsync
server_dotfiles:
- src: .bashrc.d/20-editor-server.sh
dest: .bashrc.d/20-editor-server.sh
mode: "0644"
- src: .gnupg/gpg-agent.conf
dest: .gnupg/gpg-agent.conf
mode: "0600"
@@ -50,6 +53,10 @@ server_templates:
no_log: true
server_directories:
- path: "{{ server_user_home }}/.bashrc.d"
owner: "{{ server_username }}"
group: "{{ server_user_group }}"
mode: "0755"
- path: "{{ server_user_home }}/.gnupg"
owner: "{{ server_username }}"
group: "{{ server_user_group }}"
@@ -82,6 +89,17 @@ server_directories:
owner: root
group: root
mode: "0755"
- path: /srv/nextcloud
owner: root
group: root
mode: "0755"
- path: /srv/nextcloud/data
owner: root
group: root
mode: "0755"
server_syncthing_enabled: true
server_syncthing_directories:
- path: /opt/syncthing/config
owner: root
group: root
@@ -94,30 +112,6 @@ server_directories:
owner: "1000"
group: "1000"
mode: "0755"
- path: /srv/nextcloud
owner: root
group: root
mode: "0755"
- path: /srv/nextcloud/data
owner: root
group: root
mode: "0755"
server_ufw_rules:
- rule: allow
name: OpenSSH
- rule: allow
port: "22000"
proto: tcp
comment: Syncthing sync traffic
- rule: allow
port: "22000"
proto: udp
comment: Syncthing QUIC sync traffic
- rule: allow
port: "21027"
proto: udp
comment: Syncthing local discovery
server_sshd_settings:
PermitRootLogin: "no"

View File

@@ -1,37 +0,0 @@
---
ubuntu_packages_base:
- curl
- ufw
- htop
- build-essential
- nodejs
- git-delta
- jq
- ripgrep
ubuntu_manage_docker_repo: true
ubuntu_emacs_packages:
- emacs
- pandoc
- latexmk
- texlive-luatex
- texlive-latex-base
- texlive-latex-recommended
- texlive-fonts-recommended
ubuntu_docker_packages:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
enabled_services:
- ufw
- docker
ubuntu_dotfiles:
- src: .bashrc.d/
dest: .bashrc.d/
mode: preserve

View File

@@ -26,6 +26,16 @@ atlas_zfs_dataset_icloud_photos: icloud_photos
atlas_mount_root: /CHANGEME_ATLAS_MOUNT_ROOT
atlas_manage_storage: false
rocky_manage_openzfs_repo: true
rocky_manage_syncthing_binary: true
host_packages:
- cockpit
- nfs-utils
- policycoreutils-python-utils
- samba
- zfs
atlas_nfs_exports:
- path: "{{ atlas_work_mountpoint }}"
clients: "{{ atlas_lan_subnet }}(rw,sync,no_subtree_check,root_squash)"

View File

@@ -1,5 +1,8 @@
---
hostname: prometheus
ansible_host: 179.237.102.172
ansible_user: rocky
ansible_port: 22
ansible_ssh_private_key_file: /home/fscotto/.ssh/id_ed25519
host_packages: []
host_enabled_services: []
server_username: rocky

View File

@@ -20,6 +20,8 @@ all:
platform_rocky:
hosts:
atlas:
children:
rocky_server:
void:
children:
@@ -67,10 +69,6 @@ all:
nymph:
ansible_connection: local
ubuntu:
children:
ubuntu_server:
workstation:
children:
workstation_dev:
@@ -82,7 +80,7 @@ all:
server:
children:
ubuntu_server:
rocky_server:
workstation_dev_fedora:
hosts:
@@ -94,7 +92,6 @@ all:
deadalus:
ansible_connection: local
ubuntu_server:
rocky_server:
hosts:
prometheus:
ansible_connection: local

View File

@@ -32,6 +32,7 @@
ansible.builtin.dnf:
name: "{{ rocky_openzfs_release_rpm }}"
state: present
when: rocky_manage_openzfs_repo | bool
- name: Disable OpenZFS DKMS repository
tags: [packages, storage]
@@ -39,6 +40,7 @@
name:
- zfs
state: disabled
when: rocky_manage_openzfs_repo | bool
- name: Enable OpenZFS kmod repository
tags: [packages, storage]
@@ -46,6 +48,36 @@
name:
- zfs-kmod
state: enabled
when: rocky_manage_openzfs_repo | bool
- name: Configure official Docker RPM repository
tags: [packages, docker]
ansible.builtin.get_url:
url: "{{ rocky_docker_repo_url }}"
dest: "{{ rocky_docker_repo_file }}"
owner: root
group: root
mode: "0644"
when: rocky_manage_docker_repo | bool
- name: Configure official GitHub CLI RPM repository
tags: [packages]
ansible.builtin.get_url:
url: "{{ rocky_github_cli_repo_url }}"
dest: "{{ rocky_github_cli_repo_file }}"
owner: root
group: root
mode: "0644"
when: rocky_manage_github_cli_repo | bool
- name: Remove packages conflicting with Docker CE
tags: [packages, docker]
ansible.builtin.dnf:
name: "{{ rocky_docker_conflicting_packages }}"
state: absent
when:
- rocky_manage_docker_repo | bool
- rocky_docker_conflicting_packages | length > 0
- name: Refresh Rocky package metadata
tags: [packages]
@@ -58,20 +90,30 @@
name: >-
{{
(
(common_packages | default([]))
(rocky_common_packages | default([]))
+ (rocky_packages_base | default([]))
+ (profile_packages | default([]))
+ (rocky_profile_packages | default([]))
+ (rocky_docker_packages | default([]))
+ (host_packages | default([]))
) | unique
}}
state: present
- name: Add Rocky user to docker group
tags: [packages, docker]
ansible.builtin.user:
name: "{{ effective_username }}"
groups: docker
append: true
when: rocky_docker_packages | length > 0
- name: Require supported architecture for Syncthing
tags: [packages, syncthing]
ansible.builtin.assert:
that:
- ansible_facts['architecture'] == 'x86_64'
fail_msg: The pinned Atlas Syncthing binary currently supports x86_64 only.
when: rocky_manage_syncthing_binary | bool
- name: Read installed Syncthing version
tags: [packages, syncthing]
@@ -83,6 +125,7 @@
changed_when: false
failed_when: false
check_mode: false
when: rocky_manage_syncthing_binary | bool
- name: Determine whether Syncthing must be installed
tags: [packages, syncthing]
@@ -92,6 +135,7 @@
('syncthing v' ~ rocky_syncthing_version ~ ' ')
not in (rocky_syncthing_version_check.stdout | default(''))
}}
when: rocky_manage_syncthing_binary | bool
- name: Create temporary Syncthing extraction directory
tags: [packages, syncthing]
@@ -101,7 +145,9 @@
owner: root
group: root
mode: "0755"
when: rocky_syncthing_install_required | bool
when:
- rocky_manage_syncthing_binary | bool
- rocky_syncthing_install_required | bool
- name: Download pinned Syncthing release
tags: [packages, syncthing]
@@ -112,7 +158,9 @@
owner: root
group: root
mode: "0644"
when: rocky_syncthing_install_required | bool
when:
- rocky_manage_syncthing_binary | bool
- rocky_syncthing_install_required | bool
- name: Extract pinned Syncthing release
tags: [packages, syncthing]
@@ -120,7 +168,9 @@
src: "/tmp/syncthing-{{ rocky_syncthing_version }}.tar.gz"
dest: "/tmp/syncthing-{{ rocky_syncthing_version }}"
remote_src: true
when: rocky_syncthing_install_required | bool
when:
- rocky_manage_syncthing_binary | bool
- rocky_syncthing_install_required | bool
- name: Install pinned Syncthing binary
tags: [packages, syncthing]
@@ -136,16 +186,20 @@
owner: root
group: root
mode: "0755"
when: rocky_syncthing_install_required | bool
when:
- rocky_manage_syncthing_binary | bool
- rocky_syncthing_install_required | bool
- name: Remove Syncthing release archive
tags: [packages, syncthing]
ansible.builtin.file:
path: "/tmp/syncthing-{{ rocky_syncthing_version }}.tar.gz"
state: absent
when: rocky_manage_syncthing_binary | bool
- name: Remove Syncthing extraction directory
tags: [packages, syncthing]
ansible.builtin.file:
path: "/tmp/syncthing-{{ rocky_syncthing_version }}"
state: absent
when: rocky_manage_syncthing_binary | bool

View File

@@ -1,82 +0,0 @@
---
- name: Copy Ubuntu dotfiles
tags: [dotfiles, dotfiles:common]
ansible.builtin.copy:
src: "{{ playbook_dir }}/../dotfiles/ubuntu/{{ item.src }}"
dest: "{{ effective_user_home }}/{{ item.dest }}"
owner: "{{ effective_username }}"
group: "{{ effective_user_group }}"
mode: "{{ item.mode }}"
loop: "{{ ubuntu_dotfiles | default([]) }}"
loop_control:
label: "{{ item.dest }}"
- name: Ensure Docker apt keyrings directory exists
tags: [packages]
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
owner: root
group: root
mode: "0755"
when: ubuntu_manage_docker_repo | default(false)
- name: Download Docker apt repository signing key
tags: [packages]
ansible.builtin.get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
owner: root
group: root
mode: "0644"
when: ubuntu_manage_docker_repo | default(false)
- name: Configure Docker apt repository
tags: [packages]
ansible.builtin.apt_repository:
repo: >-
deb [arch={{ 'amd64' if ansible_facts['architecture'] == 'x86_64'
else 'arm64' if ansible_facts['architecture'] in ['aarch64', 'arm64']
else ansible_facts['architecture'] }}
signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu
{{ ansible_facts['distribution_release'] }} stable
filename: docker
state: present
update_cache: true
when: ubuntu_manage_docker_repo | default(false)
- name: Refresh apt package cache
tags: [packages]
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Install packages on Ubuntu
tags: [packages]
ansible.builtin.apt:
name: >-
{{
(
(common_packages | default([]))
+ (ubuntu_packages_base | default([]))
+ (ubuntu_docker_packages | default([]))
+ (profile_packages | default([]))
+ (
(ubuntu_emacs_packages | default([]))
if (emacs_enabled | default(false) | bool)
else []
)
+ (host_packages | default([]))
)
| unique
}}
state: present
- name: Add user to docker group
tags: [packages]
ansible.builtin.user:
name: "{{ effective_username }}"
groups: docker
append: true
when: (ubuntu_docker_packages | default([])) | length > 0

View File

@@ -2,5 +2,5 @@
- name: Reload SSH service
tags: [services]
ansible.builtin.service:
name: ssh
name: "{{ server_sshd_service_name }}"
state: reloaded

View File

@@ -1,16 +1,12 @@
---
- name: Copy server dotfiles
tags: [dotfiles, dotfiles:server]
ansible.builtin.copy:
src: "{{ playbook_dir }}/../dotfiles/server/{{ item.src }}"
dest: "{{ server_user_home }}/{{ item.dest }}"
owner: "{{ server_username }}"
group: "{{ server_user_group }}"
mode: "{{ item.mode }}"
loop: "{{ server_dotfiles | default([]) }}"
loop_control:
label: "{{ item.dest }}"
- name: Require supported server firewall backend
tags: [services, packages]
ansible.builtin.assert:
that:
- server_firewall_backend == 'firewalld'
fail_msg: >-
server_firewall_backend must be firewalld for the Rocky server profile.
- name: Require server container secret variables
tags: [dotfiles, dotfiles:server, services]
@@ -30,10 +26,30 @@
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
loop: "{{ server_directories | default([]) }}"
loop: >-
{{
(server_directories | default([]))
+ (
server_syncthing_directories | default([])
if server_syncthing_enabled | default(true) | bool
else []
)
}}
loop_control:
label: "{{ item.path }}"
- name: Copy server dotfiles
tags: [dotfiles, dotfiles:server]
ansible.builtin.copy:
src: "{{ playbook_dir }}/../dotfiles/server/{{ item.src }}"
dest: "{{ server_user_home }}/{{ item.dest }}"
owner: "{{ server_username }}"
group: "{{ server_user_group }}"
mode: "{{ item.mode }}"
loop: "{{ server_dotfiles | default([]) }}"
loop_control:
label: "{{ item.dest }}"
- name: Render server templates
tags: [dotfiles, dotfiles:server]
ansible.builtin.template:
@@ -68,33 +84,41 @@
notify: Reload SSH service
when: (server_sshd_allow_users | default([])) | length > 0
- name: Define effective server UFW rules
- name: Allow server services through firewalld
tags: [services, packages]
ansible.builtin.set_fact:
server_ufw_rules_effective: "{{ server_ufw_rules | default([]) }}"
- name: Apply server UFW rules
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: "{{ server_ufw_rules_effective }}"
loop_control:
label: "{{ item.name | default(item.port) }}"
- name: Enable UFW firewall on server
tags: [services, packages]
community.general.ufw:
ansible.posix.firewalld:
service: "{{ item }}"
zone: "{{ server_firewalld_zone }}"
state: enabled
when: (server_ufw_rules_effective | default([])) | length > 0
permanent: true
immediate: true
loop: "{{ server_firewalld_services | default([]) }}"
loop_control:
label: "{{ item }}"
when: server_firewall_backend == 'firewalld'
- name: Allow server ports through firewalld
tags: [services, packages]
ansible.posix.firewalld:
port: "{{ item }}"
zone: "{{ server_firewalld_zone }}"
state: enabled
permanent: true
immediate: true
loop: "{{ server_firewalld_ports | default([]) }}"
loop_control:
label: "{{ item }}"
when: server_firewall_backend == 'firewalld'
- name: Remove disabled server ports from firewalld
tags: [services, packages]
ansible.posix.firewalld:
port: "{{ item }}"
zone: "{{ server_firewalld_zone }}"
state: disabled
permanent: true
immediate: true
loop: "{{ server_firewalld_absent_ports | default([]) }}"
loop_control:
label: "{{ item }}"
when: server_firewall_backend == 'firewalld'

View File

@@ -85,6 +85,14 @@
roles:
- profile_atlas
- name: Configure Rocky Linux server
hosts: rocky_server
become: true
roles:
- dotfiles_common
- profile_server
- name: Configure personal workstation role on Fedora
hosts: platform_fedora:&role_personal_workstation
become: true
@@ -112,12 +120,3 @@
roles:
- profile_workstation_dev_wsl
- name: Configure Ubuntu server
hosts: ubuntu_server
become: true
roles:
- packages_ubuntu
- services_systemd
- profile_server

View File

@@ -1,4 +1,5 @@
---
{% set selinux_volume_option = server_compose_selinux_mount_option | default('') %}
version: "3.8"
services:
@@ -14,8 +15,8 @@ services:
ND_ENABLETRANSCODING: "true"
volumes:
- "/opt/navidrome/data:/data"
- "/opt/music:/music:ro"
- "/opt/navidrome/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
- "/opt/music:/music:ro{{ ',' ~ selinux_volume_option if selinux_volume_option else '' }}"
user: "1000:1000"
networks:
- web
@@ -30,8 +31,8 @@ services:
- "443:443"
- "81:81"
volumes:
- "/opt/npm/data:/data"
- "/opt/npm/letsencrypt:/etc/letsencrypt"
- "/opt/npm/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
- "/opt/npm/letsencrypt:/etc/letsencrypt{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
networks:
- web
- gitea
@@ -66,7 +67,7 @@ services:
POSTGRES_PASSWORD: "{{ vault_postgres_root_password }}"
volumes:
- "/opt/postgres/data:/var/lib/postgresql/data"
- "/opt/postgres/data:/var/lib/postgresql/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
networks:
- web
gitea:
@@ -79,14 +80,15 @@ services:
networks:
- gitea
volumes:
- /opt/gitea/data:/data
- /opt/gitea/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- /home/git/.ssh:/data/git/.ssh
- /home/git/.ssh:/data/git/.ssh{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}
ports:
- "3000:3000"
- "127.0.0.1:222:22"
{% if server_syncthing_enabled | default(true) | bool %}
syncthing:
image: syncthing/syncthing:2
container_name: syncthing
@@ -95,14 +97,15 @@ services:
expose:
- "8384"
volumes:
- "/opt/syncthing/config:/var/syncthing"
- "/srv/syncthing/data:/data"
- "/opt/syncthing/config:/var/syncthing{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
- "/srv/syncthing/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
ports:
- "22000:22000/tcp"
- "22000:22000/udp"
- "21027:21027/udp"
networks:
- web
{% endif %}
networks:
web: