summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmed Abdelhalim <[email protected]>2025-08-11 00:32:00 +0200
committerAhmed Abdelhalim <[email protected]>2025-08-11 00:32:00 +0200
commit20ab3adb6b08944235c707490449c8906394564f (patch)
tree8f0bded9360fde2cb6779d4e8cd50d41a3741c4c
parentb837d1af24552836cf85a17013ca7b210e1b727c (diff)
Add network role
-rw-r--r--group_vars/all.yml.example2
-rw-r--r--molecule/default/Dockerfile.archlinux.j224
-rw-r--r--molecule/default/Dockerfile.raspberrypi.j224
-rw-r--r--molecule/default/Dockerfile.ubuntu.j229
-rw-r--r--molecule/default/converge.yml9
-rw-r--r--molecule/default/molecule.yml41
-rw-r--r--roles/network/README.md12
-rw-r--r--roles/network/defaults/main.yml3
-rw-r--r--roles/network/handlers/main.yml13
-rw-r--r--roles/network/meta/argument_specs.yml29
-rw-r--r--roles/network/meta/main.yml19
-rw-r--r--roles/network/tasks/install-archlinux.yml15
-rw-r--r--roles/network/tasks/install-debian.yml15
-rw-r--r--roles/network/tasks/main.yml89
-rw-r--r--roles/network/templates/NetworkManager.conf.j222
-rw-r--r--roles/network/templates/eth0-connection.nmconnection.j216
-rw-r--r--roles/network/templates/wifi-connection.nmconnection.j223
-rw-r--r--roles/network/vars/archlinux.yml11
-rw-r--r--roles/network/vars/debian.yml13
-rw-r--r--site.yml2
20 files changed, 411 insertions, 0 deletions
diff --git a/group_vars/all.yml.example b/group_vars/all.yml.example
index ed97d539..e0529a63 100644
--- a/group_vars/all.yml.example
+++ b/group_vars/all.yml.example
@@ -1 +1,3 @@
---
+network_wifi_ssid: "TEST_WIFI_SSID"
+network_wifi_pass: "TEST_WIFI_PASS"
diff --git a/molecule/default/Dockerfile.archlinux.j2 b/molecule/default/Dockerfile.archlinux.j2
new file mode 100644
index 00000000..1d5a1cd5
--- /dev/null
+++ b/molecule/default/Dockerfile.archlinux.j2
@@ -0,0 +1,24 @@
+FROM docker.io/library/archlinux
+
+ENV container docker
+
+RUN pacman -Syu --noconfirm --needed python3 \
+ && pacman -Scc --noconfirm
+
+RUN (cd /lib/systemd/system/sysinit.target.wants/; \
+ for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
+ rm -f /lib/systemd/system/multi-user.target.wants/*;\
+ rm -f /etc/systemd/system/*.wants/*;\
+ rm -f /lib/systemd/system/local-fs.target.wants/*; \
+ rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
+ rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
+ rm -f /lib/systemd/system/basic.target.wants/*;\
+ rm -f /lib/systemd/system/anaconda.target.wants/*;
+
+# Workaround archlinux not including any non-indo-european locales
+# https://gitlab.archlinux.org/archlinux/archlinux-docker/-/issues/59
+RUN cp -r /usr/share/i18n/locales/en_US /usr/share/i18n/locales/de_DE;
+
+VOLUME ["/sys/fs/cgroup"]
+
+CMD ["/lib/systemd/systemd"]
diff --git a/molecule/default/Dockerfile.raspberrypi.j2 b/molecule/default/Dockerfile.raspberrypi.j2
new file mode 100644
index 00000000..1b1133f4
--- /dev/null
+++ b/molecule/default/Dockerfile.raspberrypi.j2
@@ -0,0 +1,24 @@
+# Based on the amazing work of geerlingguy <3
+# FROM docker.io/geerlingguy/docker-debian12-ansible
+FROM docker.io/library/debian:bookworm
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+ENV container docker
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ systemd python3 avahi-daemon \
+ && rm -Rf /var/lib/apt/lists/* \
+ && rm -Rf /usr/share/doc \
+ && rm -Rf /usr/share/man \
+ && apt-get clean
+
+RUN rm -f /lib/systemd/system/multi-user.target.wants/getty.target
+
+# Mimic Raspberry OS default boot (for testing)
+RUN systemctl enable avahi-daemon
+
+VOLUME ["/sys/fs/cgroup", "/tmp", "/run", "/opt"]
+
+CMD ["/lib/systemd/systemd"]
diff --git a/molecule/default/Dockerfile.ubuntu.j2 b/molecule/default/Dockerfile.ubuntu.j2
new file mode 100644
index 00000000..4cf904ed
--- /dev/null
+++ b/molecule/default/Dockerfile.ubuntu.j2
@@ -0,0 +1,29 @@
+# Based on the amazing work of geerlingguy <3
+# FROM docker.io/geerlingguy/docker-ubuntu2404-ansible
+FROM docker.io/library/ubuntu:noble
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+ENV container docker
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends locales systemd avahi-daemon python3 \
+ && apt-get clean \
+ && rm -Rf /var/lib/apt/lists/* \
+ && rm -Rf /usr/share/doc \
+ && rm -Rf /usr/share/man
+
+# Fix potential UTF-8 errors with ansible-test.
+RUN locale-gen en_US.UTF-8
+
+# Remove unnecessary getty and udev targets that result in high CPU usage when using
+# multiple containers with Molecule (https://github.com/ansible/molecule/issues/1104)
+RUN rm -f /lib/systemd/system/systemd*udev* \
+ && rm -f /lib/systemd/system/getty.target
+
+# Mimic Ubuntu OS default boot (for testing)
+RUN systemctl enable avahi-daemon
+
+VOLUME ["/sys/fs/cgroup", "/tmp", "/run", "/opt"]
+
+CMD ["/lib/systemd/systemd"]
diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml
new file mode 100644
index 00000000..d0c2418d
--- /dev/null
+++ b/molecule/default/converge.yml
@@ -0,0 +1,9 @@
+---
+- name: Converge
+ hosts: instance
+ vars:
+ ansible_become_method: su
+ network_wifi_ssid: "TEST_WIFI_SSID"
+ network_wifi_pass: "TEST_WIFI_PASS"
+ roles:
+ - role: network
diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml
new file mode 100644
index 00000000..c0ec4e96
--- /dev/null
+++ b/molecule/default/molecule.yml
@@ -0,0 +1,41 @@
+---
+role_name_check: 1
+dependency:
+ name: galaxy
+ options:
+ ignore-errors: true
+driver:
+ name: podman
+platforms:
+ - name: instance
+ image: ${MOLECULE_DISTRO:-archlinux}
+ dockerfile: Dockerfile.${MOLECULE_DISTRO:-archlinux}.j2
+ platform: "${MOLECULE_PLATFORM:-linux/amd64}"
+ pre_build_image: false
+ privileged: true
+ command: ${MOLECULE_COMMAND:-"/lib/systemd/systemd"}
+ tmpfs:
+ "/tmp": "rw"
+ "/run": "rw,exec"
+ volumes:
+ - "/sys/fs/cgroup:/sys/fs/cgroup:rw"
+ cgroupns_mode: host
+provisioner:
+ name: ansible
+ inventory:
+ links:
+ host_vars: "../../host_vars/"
+ group_vars: "../../group_vars/"
+ env:
+ MOLECULE_DISTRO: "${MOLECULE_DISTRO:-archlinux}"
+ ANSIBLE_ROLES_PATH: "../../roles"
+ config_options:
+ defaults:
+ callback_result_format: yaml
+ interpreter_python: /usr/bin/python3
+ ssh_connection:
+ pipelining: true
+ playbooks:
+ converge: converge.yml
+verifier:
+ name: ansible
diff --git a/roles/network/README.md b/roles/network/README.md
new file mode 100644
index 00000000..ef0a566d
--- /dev/null
+++ b/roles/network/README.md
@@ -0,0 +1,12 @@
+# Ansible Role: network
+
+This role configure the basic networking functionality of a linux distro
+
+## Role Variables
+
+- `hostname` the hostname to be configure if provided.
+- `network_wifi_ssid` the name of the WIFI network to be configured (default: "").
+- `network_wifi_pass` the passphrase of the WIFI network to be configure (default: "").
+- `network_packages` the packages to install for a distro (default in distro vars).
+- `network_packages_removed` the packages to remove from a distro (default in distro vars).
+- `network_services` the services names to start/enable for a distro (default in distro vars).
diff --git a/roles/network/defaults/main.yml b/roles/network/defaults/main.yml
new file mode 100644
index 00000000..5e1076a7
--- /dev/null
+++ b/roles/network/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+network_wifi_ssid: ""
+network_wifi_pass: ""
diff --git a/roles/network/handlers/main.yml b/roles/network/handlers/main.yml
new file mode 100644
index 00000000..df50d41d
--- /dev/null
+++ b/roles/network/handlers/main.yml
@@ -0,0 +1,13 @@
+---
+- name: "Reload systemd"
+ become: true
+ ansible.builtin.systemd_service:
+ daemon_reload: true
+ when: not ansible_is_chroot
+
+- name: "Restart NetworkManager"
+ become: true
+ ansible.builtin.systemd_service:
+ name: "NetworkManager"
+ state: "restarted"
+ when: not ansible_is_chroot
diff --git a/roles/network/meta/argument_specs.yml b/roles/network/meta/argument_specs.yml
new file mode 100644
index 00000000..cd30b69c
--- /dev/null
+++ b/roles/network/meta/argument_specs.yml
@@ -0,0 +1,29 @@
+---
+argument_specs:
+ main:
+ options:
+ hostname:
+ type: "str"
+ description: "The distro linux network hostname to be used"
+ network_wifi_ssid:
+ type: "str"
+ description: "The WIFI SSID to be configure when provided"
+ required: false
+ default: ""
+ network_wifi_pass:
+ type: "str"
+ description: "The WIFI Passphrase to be configure when provided"
+ required: false
+ default: ""
+ network_packages:
+ type: "list"
+ description: "The network packages to install"
+ elements: "str"
+ network_packages_removed:
+ type: "list"
+ description: "The network packages to remove"
+ elements: "str"
+ network_services:
+ type: "list"
+ description: "The network services to enable"
+ elements: "str"
diff --git a/roles/network/meta/main.yml b/roles/network/meta/main.yml
new file mode 100644
index 00000000..a129a772
--- /dev/null
+++ b/roles/network/meta/main.yml
@@ -0,0 +1,19 @@
+---
+dependencies: []
+galaxy_info:
+ role_name: network
+ author: a14m
+ description: "Configure basic distro networking features"
+ company: "kartoffeln.work GmbH."
+ license: "license MIT"
+ min_ansible_version: "2.18"
+ platforms:
+ - name: ArchLinux
+ versions:
+ - all
+ - name: Ubuntu
+ versions:
+ - noble
+ - name: Debian
+ versions:
+ - bookworm
diff --git a/roles/network/tasks/install-archlinux.yml b/roles/network/tasks/install-archlinux.yml
new file mode 100644
index 00000000..94384c5a
--- /dev/null
+++ b/roles/network/tasks/install-archlinux.yml
@@ -0,0 +1,15 @@
+---
+- name: "Ensure network_packages are installed"
+ become: true
+ community.general.pacman:
+ name: "{{ network_packages }}"
+ state: "present"
+ tags: [required_for_boot]
+
+- name: "Ensrue network_packages_removed are removed"
+ become: true
+ community.general.pacman:
+ name: "{{ network_packages_removed }}"
+ state: "absent"
+ extra_args: "-n" # Removes config files too
+ # Not required for boot
diff --git a/roles/network/tasks/install-debian.yml b/roles/network/tasks/install-debian.yml
new file mode 100644
index 00000000..057a4d0f
--- /dev/null
+++ b/roles/network/tasks/install-debian.yml
@@ -0,0 +1,15 @@
+---
+- name: "Ensure network_packages are installed"
+ become: true
+ ansible.builtin.apt:
+ pkg: "{{ network_packages }}"
+ state: "present"
+ tags: [required_for_boot]
+
+- name: "Ensrue network_packages_removed are removed"
+ become: true
+ ansible.builtin.apt:
+ name: "{{ network_packages_removed }}"
+ state: "absent"
+ purge: true
+ # Not required for boot
diff --git a/roles/network/tasks/main.yml b/roles/network/tasks/main.yml
new file mode 100644
index 00000000..44a9e300
--- /dev/null
+++ b/roles/network/tasks/main.yml
@@ -0,0 +1,89 @@
+---
+- name: "Configure /etc/hostname"
+ become: true
+ ansible.builtin.copy:
+ dest: "/etc/hostname"
+ mode: "0644"
+ content: |
+ {{ hostname }}
+ when: hostname is defined
+ tags: [required_for_boot]
+
+- name: "Configure /etc/hosts"
+ become: true
+ ansible.builtin.copy:
+ dest: "/etc/hosts"
+ mode: "0644"
+ content: |
+ 127.0.0.1 localhost
+ 127.0.1.1 {{ hostname }}
+ ::1 localhost ip6-localhost ip6-loopback
+ ff02::1 ip6-allnodes
+ ff02::2 ip6-allrouters
+ when: hostname is defined
+ # Not required for boot
+
+- name: "Include OS-specific variables"
+ ansible.builtin.include_vars: "{{ ansible_os_family | lower }}.yml"
+ tags: [required_for_boot]
+
+- name: "Install OS-specific packages"
+ ansible.builtin.include_tasks: "install-{{ ansible_os_family | lower }}.yml"
+ tags: [required_for_boot]
+
+- name: "(chroot): Ensure network_services are enabled"
+ ansible.builtin.command:
+ cmd: "systemctl enable {{ item }}"
+ changed_when: true
+ with_items: "{{ network_services }}"
+ when: ansible_is_chroot
+ # noqa: command-instead-of-module module doesn't work inside chroot
+ tags: [required_for_boot]
+
+- name: "Ensure network_services are enabled"
+ become: true
+ ansible.builtin.systemd_service:
+ name: "{{ item }}"
+ enabled: true
+ state: "started"
+ with_items: "{{ network_services }}"
+ when: not ansible_is_chroot
+ # Not required for boot
+
+- name: "Configure NetworkManager"
+ become: true
+ tags: [required_for_boot]
+ notify:
+ - "Restart NetworkManager"
+ - "Reload systemd"
+ block:
+ - name: "Configure NetworkManager"
+ ansible.builtin.template:
+ src: "NetworkManager.conf.j2"
+ dest: "/etc/NetworkManager/NetworkManager.conf"
+ mode: "0644"
+
+ - name: "Configure NetworkManager Captive Portals"
+ ansible.builtin.get_url:
+ dest: "/etc/NetworkManager/dispatcher.d/90-open_captive_portal"
+ # yamllint disable-line
+ url: "https://raw.githubusercontent.com/Seme4eg/captive-portal-sh/04751034437b6abd92647cab1b22cef586c86f4e/90-open_captive_portal"
+ checksum: "sha1:75f4c827939e7dd433357ab4776c787be02c485b"
+ mode: "0750"
+
+ - name: "Configure ethernet connection"
+ ansible.builtin.template:
+ src: "eth0-connection.nmconnection.j2"
+ dest: "/etc/NetworkManager/system-connections/ethernet.nmconnection"
+ mode: "0600"
+ owner: "root"
+ group: "root"
+
+ - name: "Configure wifi connection"
+ ansible.builtin.template:
+ src: "wifi-connection.nmconnection.j2"
+ dest: "/etc/NetworkManager/system-connections/{{ network_wifi_ssid }}.nmconnection"
+ mode: "0600"
+ owner: "root"
+ group: "root"
+ when: network_wifi_ssid != ""
diff --git a/roles/network/templates/NetworkManager.conf.j2 b/roles/network/templates/NetworkManager.conf.j2
new file mode 100644
index 00000000..32d8a442
--- /dev/null
+++ b/roles/network/templates/NetworkManager.conf.j2
@@ -0,0 +1,22 @@
+[connectivity]
+uri=https://ping.archlinux.org
+
+[main]
+dhcp=dhcpcd
+
+[device-mac-randomization]
+wifi.scan-rand-mac-address=yes
+
+[connection-mac-randomization]
+# Random MAC on every Ethernet connection
+ethernet.cloned-mac-address=random
+# Random (but permanent) MAC on every wifi network
+wifi.cloned-mac-address=stable
+
+[connection]
+ipv6.ip6-privacy=2
+ipv6.dhcp-duid=stable-uuid
+wifi.powersave=2
+
+[logging]
+level=INFO
diff --git a/roles/network/templates/eth0-connection.nmconnection.j2 b/roles/network/templates/eth0-connection.nmconnection.j2
new file mode 100644
index 00000000..b5cbe276
--- /dev/null
+++ b/roles/network/templates/eth0-connection.nmconnection.j2
@@ -0,0 +1,16 @@
+[connection]
+id=ethernet
+type=ethernet
+autoconnect=true
+interface-name=eth0
+
+[ethernet]
+
+[ipv4]
+method=auto
+
+[ipv6]
+addr-gen-mode=default
+method=auto
+
+[proxy]
diff --git a/roles/network/templates/wifi-connection.nmconnection.j2 b/roles/network/templates/wifi-connection.nmconnection.j2
new file mode 100644
index 00000000..9fffbd12
--- /dev/null
+++ b/roles/network/templates/wifi-connection.nmconnection.j2
@@ -0,0 +1,23 @@
+[connection]
+id={{ network_wifi_ssid }}
+uuid={{ network_wifi_ssid | to_uuid }}
+type=wifi
+autoconnect=true
+
+[wifi]
+mode=infrastructure
+ssid={{ network_wifi_ssid }}
+
+[wifi-security]
+auth-alg=open
+key-mgmt=wpa-psk
+psk={{ network_wifi_pass }}
+
+[ipv4]
+method=auto
+
+[ipv6]
+addr-gen-mode=default
+method=auto
+
+[proxy]
diff --git a/roles/network/vars/archlinux.yml b/roles/network/vars/archlinux.yml
new file mode 100644
index 00000000..c3732716
--- /dev/null
+++ b/roles/network/vars/archlinux.yml
@@ -0,0 +1,11 @@
+---
+network_packages:
+ - "dhcpcd"
+ - "networkmanager"
+
+network_packages_removed: []
+
+network_services:
+ - "dhcpcd"
+ - "systemd-resolved"
+ - "NetworkManager"
diff --git a/roles/network/vars/debian.yml b/roles/network/vars/debian.yml
new file mode 100644
index 00000000..5a9e8797
--- /dev/null
+++ b/roles/network/vars/debian.yml
@@ -0,0 +1,13 @@
+---
+network_packages:
+ - "dhcpcd"
+ - "network-manager"
+ - "systemd-resolved"
+
+network_packages_removed:
+ - "avahi-daemon"
+
+network_services:
+ - "dhcpcd"
+ - "systemd-resolved"
+ - "NetworkManager"
diff --git a/site.yml b/site.yml
index 82c3b99a..35e125d2 100644
--- a/site.yml
+++ b/site.yml
@@ -4,3 +4,5 @@
hosts:
- homelab
- chroot
+ roles:
+ - role: "network"