Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
dabf868
feat: migrate project from Ubuntu 25.10 to Ubuntu 26.04 LTS
Copilot Jul 29, 2026
f56a742
fix: align ISO volume label between mkiso.sh and README
Copilot Jul 29, 2026
a0ff836
fix: auto-derive EFI partition offsets from ISO via fdisk in mkiso.sh
Copilot Jul 29, 2026
ddfc6d1
fix: replace fdisk EFI offset parsing with Python MBR reader; fix mki…
Copilot Jul 31, 2026
715bdb7
docs: add grub-pc-bin to README.md §5.2 install command
Copilot Jul 31, 2026
3cc87e5
refactor: extract inline Python EFI params into scripts/get_efi_param…
Copilot Jul 31, 2026
865ceb1
fix: add GPT EFI partition fallback in get_efi_params.py for Ubuntu 2…
Copilot Jul 31, 2026
bb261fd
Replace "admin" user - used sytem-insaller wide, fix kernel cmd line …
clauspruefer Aug 2, 2026
5ca5ad4
Remove "nomodeset" kernel cmd line param - causes wrong display setup…
clauspruefer Aug 2, 2026
f9b1498
fix: copy all hardening files to ISO including .service, .tpl, .deskt…
Copilot Aug 2, 2026
039349f
feat: add MIRROR_ADDRESS config; fix user scripts copy; fix snapd use…
Copilot Aug 3, 2026
9104395
Change mirror to HTTPS URL
clauspruefer Aug 3, 2026
925ee6d
fix: properly remove and deactivate gnome-initial-setup
Copilot Aug 3, 2026
0f9569f
Add config option MIRROR_ADDRESS with https URL
clauspruefer Aug 3, 2026
17846ff
docs: update CHANGELOG.md with all v0.4 changes
Copilot Aug 3, 2026
886ff39
docs: add high-level summary bullet points to each v0.x section in CH…
Copilot Aug 3, 2026
e41f332
docs: add missing v0.3 section to CHANGELOG.md (ISO autogeneration)
Copilot Aug 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,88 @@ All notable changes to the Hardened Ubuntu project will be documented in this fi
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## v0.4

- Major Ubuntu update to the long-term supported 26.04 LTS version
- Bugs from previous versions fixed for a 100% clean installer workflow
- GNOME initial setup reliably removed during automated installation
- User automation / autoinstall process working 100%

### Changed

#### Ubuntu 26.04 LTS Migration

- Migrated entire project from Ubuntu 25.10 to Ubuntu 26.04 LTS.
- Updated `scripts/mkiso.sh`: ISO source/output filenames updated to `ubuntu-26.04-desktop-amd64.iso` / `ubuntu-26.04-hardened.iso`; volume label updated to `Ubuntu 26.04 LTS Hardened`.
- Updated `scripts/README.md`: host OS requirement updated to Ubuntu 26.04 LTS.
- Updated `iso/README.md`: download filename updated to `ubuntu-26.04-desktop-amd64.iso`; run directory clarified to inside the `iso/` directory.
- Updated `README.md`: all Ubuntu 25.10 version strings, section headings, ISO filenames, and download URLs updated to Ubuntu 26.04 LTS.

#### GRUB Kernel Command Line

- Removed `nomodeset` parameter from default `GRUB_KERNEL_CMDLINE` in `config.sh`; `nomodeset` forces software rendering and causes incorrect display setup on systems with Intel integrated graphics.

#### Repository Mirror Configuration

- `MIRROR_ADDRESS` configuration parameter added to `config.sh` under the `# repository mirror` group; defaults to `https://archive.ubuntu.com/ubuntu`.
- `patch-ubuntu-mirrors-https.sh` updated to replace the default `archive.ubuntu.com` URL with the configured `MIRROR_ADDRESS` value when set, enabling regional or local mirror selection without modifying the installer scripts.
- Default `MIRROR_ADDRESS` set to HTTPS to enforce encrypted package download from the default Ubuntu archive.

#### Installer / Autoinstall

- `autoinstall/autoinstall.yaml` `late-commands`: `apt-get remove gnome-initial-setup` prefixed with `curtin in-target --` to ensure the package is removed from the installed target system (without the prefix the command ran in the throwaway live installer environment only).
- Installation working directory path fixed from `/opt/hardened` to `/opt/hardening` in `autoinstall/autoinstall.yaml` `runcmd`.

#### User Script Deployment

- `config.sh` added to the per-user `~/autoinstall-scripts/` copy in `disable-services.sh` so that sourced environment variables are available in the user context.
- `prepare-user-autostart.sh`: resolved `user-autostart.tpl` using `SCRIPT_DIR="$(dirname "$0")"` instead of a bare relative path that resolved against the current working directory, fixing template copy failures when the script is invoked via `su -c`.
- `disable-services.sh`: fixed `su -c` invocation path for `disable-user-services.sh` from `./disable-user-services.sh` to `~/autoinstall-scripts/disable-user-services.sh`.

#### Snapd and GNOME User-Level Service Deactivation

- Removed incorrectly placed `systemctl --user mask` block from `disable-services.sh`; these commands ran as root without a user D-Bus session and were silently ignored.
- Per-user snap and snapd user services now masked before first login by creating `/dev/null` symlinks directly in `~/.config/systemd/user/` inside the per-user loop (equivalent to `systemctl --user mask` but session-independent).
- `gnome-initial-setup-first-login.service` added to the per-user `/dev/null` symlink list; in Ubuntu 24.04+ this user-level service is launched by GDM on first login independently of the `~/.config/gnome-initial-setup-done` marker file.

### Added

#### ISO Generation Script

- Added ISO generation script `scripts/mkiso.sh` and documentation.

#### EFI Partition Auto-Detection

- Added `scripts/get_efi_params.py`: reads EFI System Partition start and size (in 512-byte LBA sectors) directly from the ISO binary. Searches the MBR partition table first (type `0xEF`), then falls back to the GPT partition table (EFI System Partition GUID `C12A7328-F81F-11D2-BA4B-00A0C93EC93B`) to support modern Ubuntu 26.04 ISOs which use GPT.
- `scripts/mkiso.sh` updated to call `get_efi_params.py` at runtime, replacing the previously hardcoded Ubuntu 25.10 EFI offset values (`EFI_START_D`, `EFI_END_D`, `EFI_SIZE_D`, `EFI_START_S`) with values derived directly from the source ISO.

#### ISO Generation Tests

- Added `tests/test_mkiso.sh`: shell test suite for `scripts/get_efi_params.py` covering correct MBR and GPT EFI parameter extraction, arithmetic consistency of derived values (`EFI_END_D`, `EFI_START_S`), error exit on missing EFI partition, and error exit on missing ISO file.
- Added `tests/create_test_iso.py`: helper script generating minimal synthetic ISO binaries with configurable MBR or GPT partition table layouts for use as test fixtures.

#### Package Removal

- `gnome-initial-setup` added to `apt-remove-cmds.sh` to ensure the package is removed during first-boot hardening, providing a belt-and-suspenders removal in addition to the `late-commands` step in `autoinstall.yaml`.

## v0.3

- Initial ISO autogeneration support via `scripts/mkiso.sh`

### Added

#### ISO Generation Script

- Addded ISO generation script `scripts/mkiso.sh` and documentation.
- Added `scripts/mkiso.sh`: automates the creation of a bootable hybrid ISO image using `xorriso`, embedding the autoinstall configuration and hardening scripts into the Ubuntu desktop ISO.
- Added `scripts/README.md`: documents dependencies (`xorriso`, `grub-pc-bin`) and the correct run procedure (from inside the `iso/` directory as root).

## v0.2

- WiFi support added with NetworkManager integration
- NTP / Chrony static server configuration introduced
- Automated multi-user installation support with per-user service management
- Firefox browser privacy and security hardening extended

### Added

#### WiFi Support
Expand Down Expand Up @@ -99,6 +171,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## v0.1

- Initial release of the Hardened Ubuntu project
- Core system hardening: DNS-over-HTTPS, IOMMU, USBGuard, sysctl, and service disabling
- SNAP and snapd completely removed; Firefox installed as a native non-SNAP package
- Fully automated installation via Ubuntu autoinstall with custom ISO generation

### Added

#### Core Security Features
Expand Down
18 changes: 18 additions & 0 deletions CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Configurable parameters:
- [NEXTDNS_STAMP](#nextdns_stamp)
- [KERNEL_DOMAIN_NAME](#kernel_domain_name)
- [USER_IDS](#user_ids)
- [MIRROR_ADDRESS](#mirror_address)

---

Expand Down Expand Up @@ -213,3 +214,20 @@ Used by `disable-services.sh` to iterate over each user and perform per-user set
```sh
USER_IDS="admin user1"
```

---

## MIRROR_ADDRESS

The apt repository mirror URL used to replace the default `archive.ubuntu.com` address.

Used by `patch-ubuntu-mirrors-https.sh` after converting the sources file to HTTPS. If set to a value other than the default, the `archive.ubuntu.com` URL is replaced with the specified mirror across `/etc/apt/sources.list.d/ubuntu.sources`. This is useful when a regional or local mirror offers faster or more reliable package downloads.

> [!NOTE]
> The value must be a full URL including the scheme and path (e.g. `https://mirror.example.com/ubuntu`). Set to `http://archive.ubuntu.com/ubuntu` to keep the default Ubuntu archive.

**Example:**

```sh
MIRROR_ADDRESS="https://mirror.example.com/ubuntu"
```
72 changes: 42 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ Historically, building Linux systems from source (such as Hardened Linux From Sc

Experience has demonstrated that while established Linux distributions like Ubuntu offer numerous advantages, they also present significant security concerns and default configurations unsuitable for production environments without proper hardening.

This repository addresses these shortcomings by providing a comprehensive hardening solution for Ubuntu 25.10 workstation systems, enabling production-ready deployment within minutes.
This repository addresses these shortcomings by providing a comprehensive hardening solution for Ubuntu 26.04 LTS workstation systems, enabling production-ready deployment within minutes.

**Additional Resources:**
- For detailed information about Hardened Ubuntu and NextDNS security configuration, see: [Hardened Ubuntu NextDNS Security Guide](https://www.der-it-pruefer.de/security/Hardened-Ubuntu-NextDNS-Security)
- Download autointall-ready ISO at [https://download.webcodex.de/iso/ubuntu-25.10-hardened.iso](https://download.webcodex.de/iso/ubuntu-25.10-hardened.iso)
- Download autointall-ready ISO at [https://download.webcodex.de/iso/ubuntu-26.04-hardened.iso](https://download.webcodex.de/iso/ubuntu-26.04-hardened.iso)

## Table of Contents

- [1. Abstract](#1-abstract)
- [1.1. Ubuntu 25.10 Key Features](#11-ubuntu-2510-key-features)
- [1.2. Security Concerns in Default Ubuntu 25.10](#12-security-concerns-in-default-ubuntu-2510)
- [2. Hardened Ubuntu 25.10 (Desktop)](#2-hardened-ubuntu-2510-desktop)
- [1.1. Ubuntu 26.04 LTS Key Features](#11-ubuntu-2604-lts-key-features)
- [1.2. Security Concerns in Default Ubuntu 26.04 LTS](#12-security-concerns-in-default-ubuntu-2604-lts)
- [2. Hardened Ubuntu 26.04 LTS (Desktop)](#2-hardened-ubuntu-2604-lts-desktop)
- [2.1. Security Features](#21-security-features)
- [2.2. Preserved Components](#22-preserved-components)
- [2.3. Prerequisites](#23-prerequisites)
Expand All @@ -40,16 +40,16 @@ This repository addresses these shortcomings by providing a comprehensive harden
- [5.3. Post-Installation Hardening](#53-post-installation-hardening)
- [5.4. Fully Automated Installation with Late Commands](#54-fully-automated-installation-with-late-commands)

## 1.1. Ubuntu 25.10 Key Features
## 1.1. Ubuntu 26.04 LTS Key Features

- XServer-less, 100% Wayland architecture (GNOME 49)
- Enhanced service dependency management and customization (systemd)
- Significantly improved YAML-based auto-installation
- Hardware-based hard drive encryption using TPM 2.0+ (experimental)

## 1.2. Security Concerns in Default Ubuntu 25.10
## 1.2. Security Concerns in Default Ubuntu 26.04 LTS

Ubuntu 25.10 ships with several security-relevant features enabled by default that provide insufficient administrative control:
Ubuntu 26.04 LTS ships with several security-relevant features enabled by default that provide insufficient administrative control:

- Fully automated unattended upgrades
- Automated UEFI firmware updates
Expand All @@ -62,9 +62,9 @@ Ubuntu 25.10 ships with several security-relevant features enabled by default th
> [!WARNING]
> Automated update processes combined with DNS poisoning attacks present severe security risks.

# 2. Hardened Ubuntu 25.10 (Desktop)
# 2. Hardened Ubuntu 26.04 LTS (Desktop)

This repository provides comprehensive hardening configurations for default Ubuntu 25.10 Desktop installations, specifically designed for software development and workstation environments.
This repository provides comprehensive hardening configurations for default Ubuntu 26.04 LTS Desktop installations, specifically designed for software development and workstation environments.

The solution aims to achieve an optimal balance between usability and security.

Expand Down Expand Up @@ -96,10 +96,10 @@ The solution aims to achieve an optimal balance between usability and security.

## 2.3. Prerequisites

- Ubuntu 25.10 Desktop ISO image
- Ubuntu 26.04 LTS Desktop ISO image
- USB bootable installer (UNetbootin or Rufus)
- GPT-only mode enabled in Rufus for UEFI/Secure Boot configurations
- Optional: EFI partition encryption (Ubuntu 25.10 supports TPM 2.0)
- Optional: EFI partition encryption (Ubuntu 26.04 LTS supports TPM 2.0)
- Local DHCP configuration with NTP option (DHCP option 42)

# 3. Secure DNS Configuration with NextDNS
Expand Down Expand Up @@ -127,7 +127,7 @@ To establish secure DNS infrastructure and prevent DNS-based attacks:

# 4. Installation Instructions

This section provides step-by-step instructions for installing and configuring the hardened Ubuntu 25.10 system.
This section provides step-by-step instructions for installing and configuring the hardened Ubuntu 26.04 LTS system.

## 4.1. Overview

Expand Down Expand Up @@ -157,6 +157,9 @@ vim config.sh
Configure the following parameters:

```bash
# repository mirror
export MIRROR_ADDRESS="https://archive.ubuntu.com/ubuntu"

# network interface configuration
export NET_IF_NAME="enp2s0" # NIC name
export NET_IF_MACADDRESS="12:34:56:78:9a:9b" # interface MAC
Expand All @@ -171,7 +174,7 @@ export NET_WIFI_AUTH_PASS="Wifi-Password" # WiFi passphrase
export NET_NTP_STATIC_SERVER="192.168.1.1" # static NTP server IP

# grub kernel command line options (optional)
export GRUB_KERNEL_CMDLINE="i915.enable_dc=0 i915.modeset=1 i915.enable_psr=0 intel_idle.max_cstate=1"
export GRUB_KERNEL_CMDLINE="i915.enable_dc=0 i915.enable_psr=0 intel_idle.max_cstate=1"

# NextDNS configuration
export NEXTDNS_ID="a1b2c3" # NextDNS configuration ID
Expand All @@ -181,7 +184,7 @@ export NEXTDNS_STAMP="Base64Hash" # SDNS stamp
export KERNEL_DOMAIN_NAME="domain.name" # kernel domain name

# system users (must exist in autoinstall.yaml, space-separated)
export USER_IDS="admin user1"
export USER_IDS="administrator user1"
```

**To find your network interface name:**
Expand Down Expand Up @@ -251,7 +254,7 @@ After rebooting, the second installer script must be executed. This script **req
**Execute the script:**

```bash
cd hardened-ubuntu
cd /opt/hardening/
sudo ./installer-step2.sh
```

Expand Down Expand Up @@ -306,7 +309,7 @@ sudo ./installer-step3.sh
> **A system reboot is required after completing step 3** to apply all user-level service and
> autostart configuration changes.

After completing all steps, your Ubuntu 25.10 system is hardened and ready for use. The system includes:
After completing all steps, your Ubuntu 26.04 LTS system is hardened and ready for use. The system includes:

- Encrypted DNS traffic via DNS-over-HTTPS
- Enhanced security configurations
Expand All @@ -321,7 +324,7 @@ For automated deployments, you can integrate the hardening scripts into a USB in

## 5.1. Autoinstall Configuration

The repository includes a template autoinstall configuration at `/autoinstall/autoinstall.yaml`. This file can be customized and integrated into an Ubuntu 25.10 installation ISO.
The repository includes a template autoinstall configuration at `/autoinstall/autoinstall.yaml`. This file can be customized and integrated into an Ubuntu 26.04 LTS installation ISO.

### 5.1.1. Configuration File Structure

Expand Down Expand Up @@ -383,14 +386,16 @@ mkpasswd -m yescrypt

## 5.2. Creating Bootable USB Installation Medium

1. **Download Ubuntu 25.10 Desktop ISO** from the official Ubuntu website.
1. **Download Ubuntu 26.04 LTS Desktop ISO** from the official Ubuntu website.

2. **Create the autoinstall ISO** by adding your customized autoinstall.yaml:

```bash
ISO_FILE="ubuntu-26.04-desktop-amd64.iso"

# extract Ubuntu ISO
mkdir -p /tmp/ubuntu-iso /tmp/ubuntu-custom
sudo mount -o loop ubuntu-25.10-desktop-amd64.iso /tmp/ubuntu-iso
sudo mount -o loop "${ISO_FILE}" /tmp/ubuntu-iso
cp -rT /tmp/ubuntu-iso /tmp/ubuntu-custom

# add autoinstall configuration
Expand All @@ -399,22 +404,29 @@ cp autoinstall/autoinstall.yaml /tmp/ubuntu-custom/

# copy hardening scripts to ISO
mkdir -p /tmp/ubuntu-custom/hardening
cp *.sh *.conf *.toml *.yaml *.js /tmp/ubuntu-custom/hardening/
cp *.sh *.conf *.toml *.yaml *.js *.service *.tpl *.desktop hosts debconf-selections.txt /tmp/ubuntu-custom/hardening/

# install xorriso and grub-pc-bin (required for eltorito.img hybrid ISO support)
sudo apt-get install xorriso grub-pc-bin

# install xorriso
sudo apt-get install xorriso
# derive EFI partition offsets directly from the ISO's MBR partition table
EFI_PARAMS=$(python3 scripts/get_efi_params.py "${ISO_FILE}")
Comment on lines +409 to +413
EFI_START_D=$(echo "${EFI_PARAMS}" | cut -d' ' -f1)
EFI_SIZE_D=$(echo "${EFI_PARAMS}" | cut -d' ' -f2)
EFI_END_D=$(( EFI_START_D + EFI_SIZE_D - 1 ))
EFI_START_S=$(( EFI_START_D / 4 ))

# create custom (hybrid) ISO
sudo xorriso \
-as mkisofs \
-V "Ubuntu 25.10 Hardened" \
-V "Ubuntu 26.04 LTS Hardened" \
--modification-date="$(date -u +"%Y%m%d%H%M%S00")" \
--grub2-mbr --interval:local_fs:0s-15s:zero_mbrpt,zero_gpt:'ubuntu-25.10-desktop-amd64.iso' \
--grub2-mbr --interval:local_fs:0s-15s:zero_mbrpt,zero_gpt:"${ISO_FILE}" \
--protective-msdos-label \
-partition_cyl_align off \
-partition_offset 16 \
--mbr-force-bootable \
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b --interval:local_fs:11126816d-11137071d::'ubuntu-25.10-desktop-amd64.iso' \
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b --interval:local_fs:"${EFI_START_D}d-${EFI_END_D}d"::"${ISO_FILE}" \
-appended_part_as_gpt \
-iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 \
-c '/boot.catalog' \
Expand All @@ -424,10 +436,10 @@ sudo xorriso \
-boot-info-table \
--grub2-boot-info \
-eltorito-alt-boot \
-e '--interval:appended_partition_2_start_2781704s_size_10256d:all::' \
-e "--interval:appended_partition_2_start_${EFI_START_S}s_size_${EFI_SIZE_D}d:all::" \
-no-emul-boot \
-boot-load-size 10256 \
-o /tmp/ubuntu-25.10-hardened.iso \
-boot-load-size "${EFI_SIZE_D}" \
-o /tmp/ubuntu-26.04-hardened.iso \
/tmp/ubuntu-custom/
```

Expand All @@ -446,7 +458,7 @@ sudo xorriso \
lsblk

# write the iso to usb (replace sdx with your usb device)
sudo dd if=/tmp/ubuntu-25.10-hardened.iso of=/dev/sdX bs=4M status=progress oflag=sync
sudo dd if=/tmp/ubuntu-26.04-hardened.iso of=/dev/sdX bs=4M status=progress oflag=sync
```

## 5.3. Post-Installation Hardening
Expand Down
1 change: 1 addition & 0 deletions apt-remove-cmds.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# remove unwanted packages
apt-get remove -qy avahi-daemon
apt-get remove -qy bluez bluez-cups bluez-obexd
apt-get remove -qy gnome-initial-setup
apt-get remove -qy ubuntu-insights
apt-get remove -qy ubuntu-report
apt-get remove -qy fwupd
Expand Down
4 changes: 2 additions & 2 deletions autoinstall/autoinstall.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ autoinstall:
toggle: null
identity:
realname: 'Sysadmin User'
username: admin
username: administrator
password: '$y$j9T$u2.Sxog5EGXbH1sqVnrVD.$Qi76Enig/FpDS92jEhxsa6fLSZh4KwOMSEqfr8TH8L.'
hostname: system-hostname
storage:
Expand All @@ -30,5 +30,5 @@ autoinstall:
late-commands:
- mkdir -p /target/opt/hardening
- cp -r /cdrom/hardening/* /target/opt/hardening/
- apt-get remove -qy gnome-initial-setup
- curtin in-target -- apt-get remove -qy gnome-initial-setup
shutdown: poweroff
7 changes: 5 additions & 2 deletions config.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/sh

# repository mirror
export MIRROR_ADDRESS="https://archive.ubuntu.com/ubuntu"

# netplan ethernet
export NET_IF_NAME="enp2s0"
export NET_IF_MACADDRESS="12:34:56:78:9a:9b"
Expand All @@ -14,7 +17,7 @@ export NET_WIFI_AUTH_PASS="Wifi-Password"
export NET_NTP_STATIC_SERVER="192.168.1.1"

# grub cmdline
export GRUB_KERNEL_CMDLINE="intel_iommu=igfx_off iommu.strict=1 i915.enable_dc=0 i915.modeset=1 i915.enable_psr=0 intel_idle.max_cstate=1"
export GRUB_KERNEL_CMDLINE="intel_iommu=igfx_off iommu.strict=1 i915.enable_dc=0 i915.enable_psr=0 intel_idle.max_cstate=1"

# nextdns
export NEXTDNS_ID="a1b2c3"
Expand All @@ -24,4 +27,4 @@ export NEXTDNS_STAMP="Base64Hash"
export KERNEL_DOMAIN_NAME="domain.name"

# sysusers (must exist in autoinstall.yaml)
export USER_IDS="admin user1"
export USER_IDS="administrator user1"
Loading