---
gitea: none
include_toc: true
---
[![Static Badge](https://badges.coresecret.dev/badge/Release-V9.14.018.2026.06.07-white?style=plastic&logo=linux&logoColor=white&logoSize=auto&label=Release&color=%23FCC624)](https://git.coresecret.dev/msw/CISS.debian.live.builder)
&nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/Licence-EUPL1.2-white?style=plastic&logo=europeanunion&logoColor=white&logoSize=auto&label=Licence&color=%23003399)](https://eupl.eu/1.2/en/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/opensourceinitiative-Compliant-white?style=plastic&logo=opensourceinitiative&logoColor=white&logoSize=auto&label=OSI&color=%233DA639)](https://opensource.org/license/eupl-1-2) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/Bash-V5.2.37-white?style=plastic&logo=gnubash&logoColor=white&logoSize=auto&label=Bash&color=%234EAA25)](https://www.gnu.org/software/bash/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/shellcheck-passed-white?style=plastic&logo=gnubash&logoColor=white&logoSize=auto&label=shellcheck&color=%234EAA25)](https://shellcheck.net/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/shellformat-passed-white?style=plastic&logo=google&logoColor=white&logoSize=auto&label=shellformat&color=%234285F4)](https://github.com/mvdan/sh) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/Shellstyle-Google-white?style=plastic&logo=google&logoColor=white&logoSize=auto&label=Shellstyle&color=%234285F4)](https://google.github.io/styleguide/shellguide.html)
&nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/Gitea-1.26.1-white?style=plastic&logo=gitea&logoColor=white&logoSize=auto&label=gitea&color=%23609926)](https://docs.gitea.com/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/Runner-1.0.3-white?style=plastic&logo=gitea&logoColor=white&logoSize=auto&label=runner&color=%23609926)](https://docs.gitea.com/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/IntelliJ-2026.1.1-white?style=plastic&logo=intellijidea&logoColor=white&logoSize=auto&label=IntelliJ&color=%23000000)](https://www.jetbrains.com/store/?section=personal&billing=yearly) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/keepassxc-2.7.11-white?style=plastic&logo=keepassxc&logoColor=white&logoSize=auto&label=KeePassXC&color=%236CAC4D)](https://keepassxc.org/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/netcup-Netcup-white?style=plastic&logo=netcup&logoColor=white&logoSize=auto&label=powered&color=%23056473)](https://www.netcup.com/de) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/powered-Centurion-white?style=plastic&logo=europeanunion&logoColor=white&logoSize=auto&label=powered&color=%230F243E)](https://coresecret.eu/) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/SocialMedia-@coresecret_eu-white?style=plastic&logo=x&logoColor=white&logoSize=auto&label=SocialMedia&color=%23000000)](https://x.com/coresecret_eu) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/Donation-Donation-white?style=plastic&logo=sepa&logoColor=white&logoSize=auto&label=&color=%230F243E)](https://coresecret.eu/spenden/#sepa) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/bitcoin-Bitcoin-white?style=plastic&logo=bitcoin&logoColor=white&logoSize=auto&label=Donation&color=%23F7931A)](https://coresecret.eu/spenden/#bitcoin) &nbsp;
[![Static Badge](https://badges.coresecret.dev/badge/simplex-Simplex-white?style=plastic&logo=simplex&logoColor=white&logoSize=auto&label=Contact&color=%23000000)](https://coresecret.eu/contact/#simplex) &nbsp;

# 1. CISS.debian.live.builder

**Centurion Intelligence Consulting Agency Information Security Standard**<br>
*Debian Live Build Generator for hardened live environment and CISS Debian Installer*<br>
**Master Version**: 9.14<br>
**Build**: V9.14.018.2026.06.07<br>

**CISS.debian.live.builder — First of its own.**<br>
**World-class CIA: Designed, handcrafted, and powered by Centurion Intelligence Consulting Agency.**

Developed and maintained as a one-man, security-driven engineering effort since 2024, **CISS.debian.live.builder** is designed 
to serve as a reference implementation for hardened, image-based Debian deployments.

This shell wrapper automates the creation of a Debian Trixie live ISO hardened according to the latest best practices in server
and service security. It integrates into your build pipeline to deliver an isolated, robust environment suitable for cloud
deployment or unattended installations via the forthcoming `CISS.debian.installer`. Additionally, automated CI workflows based
on Gitea Actions are provided, enabling reproducible ISO generation. A generic ISO is automatically built upon significant
changes and made publicly available for download. The latest generic ISO is available at:
**[PUBLIC CISS.debian.live.ISO](/docs/DL_PUB_ISO.md)**

Beyond a conventional live system, **CISS.debian.live.builder** assembles a **fully encrypted, integrity-protected live medium**
in a single, deterministic build step: a LUKS2 container backed by `dm-integrity` hosting the SquashFS root filesystem, combined
with a hardened initramfs chain including a dedicated Dropbear build pipeline for remote LUKS unlock. The resulting ISO ships 
with a hardened kernel configuration, strict sysctl and network tuning, pre-configured SSH hardening and fail2ban, and a 
customised `verify-checksums` path providing both ISO-edge verification and runtime attestation of the live root. All components
are aligned with the `CISS.debian.installer` baseline, ensuring a unified cryptographic and security posture from first boot to 
an installed system. For an overview of the entire build process, see:
**[MAN_CISS_ISO_BOOT_CHAIN.md](docs/MAN_CISS_ISO_BOOT_CHAIN.md)**

When built with the ``--dhcp-centurion`` profile, the live system ships with a strict network and resolver policy: 
``systemd-networkd`` and ``systemd-resolved`` are pre-configured to use ``DNS-over-TLS (DoT)`` exclusively against the 
**CenturionDNS** resolver infrastructure; plain DNS is not used and connectivity failures are treated as hard errors. DNSSEC 
validation is enforced in a fail-closed manner: zones with invalid or broken signatures result in ``SERVFAIL`` and are not 
silently downgraded. Multicast name resolution via ``mDNS`` and ``LLMNR`` is disabled globally to avoid unintended name leakage
and spoofing surfaces.

Internally, the builder employs a dedicated secret-handling pipeline backed by a tmpfs-only secrets directory
(`/dev/shm/cdlb_secrets`). Sensitive material such as root passwords, SSH keys, and signing keys never appears on the command
line, is guarded by strict `0400 root:root` permissions, and any symlink inside the secret path is treated as a hard failure
that aborts the run. Critical code paths temporarily disable Bash xtrace so that credentials never leak into debug logs, and
transient secret files are shredded (`shred -fzu`) as soon as they are no longer needed. GNUPG homes used for signing are
wiped, unencrypted chroot artifacts and includes are removed after `lb build`, and the final artifact is reduced to the
encrypted SquashFS inside the LUKS2 container. At runtime, LUKS passphrases in the live ISO and installer are transported via
named pipes inside the initramfs instead of process arguments, further minimizing exposure in process listings.

Check out more leading world-class services powered by Centurion Intelligence Consulting Agency:
* [CenturionDNS Resolver](https://eddns.eu/)
* [CenturionDNS Blocklist](https://dns.eddns.eu/blocklists/centurion_titanium_ultimate.txt) 
* [CenturionMeet](https://talk.e2ee.li/)
* [CenturionNet Services](https://coresecret.eu/cnet/)
* [CenturionNet Status](https://uptime.coresecret.eu/) 

**Contact the author:**
* [Contact the author](https://coresecret.eu/contact/)

**Legal Disclaimer:**
* This project is not affiliated with, authorized, maintained, sponsored, or endorsed by the [Debian Project](https://www.debian.org/) 
* [Licensing & Compliance](#6-licensing--compliance)
* [Disclaimer](#7-disclaimer)
* [Centurion Imprint & Legal Notice](https://coresecret.eu/imprint/)
* [Centurion Privacy Policy](https://coresecret.eu/privacy/)

## 1.1. Preliminary Remarks

### 1.1.1. HSM

Please note that all my signing keys are stored in an HSM and that the signing environment is air-gapped. The next step is to 
move to a room-gapped environment. ^^

### 1.1.2. DNSSEC, HSTS, TLS

Please note that `coresecret.dev` is included in the [(HSTS Preload List)](https://hstspreload.org/) and always serves the headers:
````nginx configuration pro
add_header Expect-CT                 "max-age=86400, enforce"                       always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
````

* The zones behind this project are dual-signed with **DNSSEC**. The current validation state is documented in the **[DNSSEC Audit Report](/docs/AUDIT_DNSSEC.md)**
* The TLS surface of **``git.coresecret.dev``** is independently audited, and the findings are held in the **[TLS Audit Report](/docs/AUDIT_TLS.md)**
* The topology of the underlying **`CISS.debian.live.builder`** building infrastructure is described in **[Centurion Net](/docs/CNET.md)**

### 1.1.3. Gitea Action Runner Hardening

The CI runners live on a host in a separate autonomous system, and that host has exactly one purpose: run Gitea Actions runners. 
Each runner receives its own service account without a login shell, is bound to a separate directory tree, and inherits a 
hardened systemd unit with ``DynamicUser``, reduced capabilities, and restrictive sandboxing. A ``systemd-analyze security`` score 
of around **``2.6``** is the baseline, not an aspiration. Traffic from those runners traverses both a software firewall (UFW) 
and dedicated hardware firewall appliances. Docker, where used, runs unprivileged.

## 1.2. Match Host and Target Versions

I always build a Debian Trixie live image on a Debian Trixie host. The toolchain and all boot components that matter to 
reproducibility are release-specific: ``live-build``, ``live-boot``, ``live-config``, ``debootstrap``, ``mksquashfs``, ``grub``, 
the ``kernel``, ``initramfs`` tooling, and even ``dpkg`` and ``apt`` defaults evolve from one release to the next. Mixing 
generations produces fragile or outright broken ISOs, sometimes subtly, sometimes catastrophically. Keeping host and target in 
lockstep avoids those mismatches and gives me predictable artifacts across builds.

## 1.3. Immutable Source-of-Truth System and Encrypted Live Root

The live ISO acts as a sealed, immutable execution environment. All relevant configuration, all installation logic, and all 
security decisions are rendered into the image at build time and treated as read-only at runtime. On top of that logical 
 immutability, I now layer cryptographic protection of the live root file system itself. The live image contains a LUKS2 container
file with dm-integrity that wraps the SquashFS payload. The initramfs knows how to locate this container, unlock it, verify its 
integrity, and then present the decrypted SquashFS as the root component of an OverlayFS stack. The detailed boot and 
verification chain is documented separately in **[CISS ISO Boot Chain](docs/MAN_CISS_ISO_BOOT_CHAIN.md)**<br>

In compact form, my expectations for the system are:<br>

* Every bit that matters for boot and provisioning is covered by checksums that I control and that are signed with keys under my solely authoritative HSM.
* The live root runs out of a LUKS2 dm-integrity container so that a tampered or bit-rotted SquashFS never becomes a trusted root.
* Verification steps are not advisory. Any anomaly causes a hard abort during boot.
* After the live environment has reached a stable, verified state, it can hand off to ``CISS.debian.installer``. The installer operates from the same image, does not pull random payloads from the internet, and keeps the target system behind a hardened firewall until the entire provisioning process has completed.
* For unattended, headless scenarios I also support builds where the target system is installed without ever exposing a shell over the console. After installation and reboot, the machine waits for a decryption passphrase via an embedded Dropbear SSH instance in the initramfs, limited to public key authentication and guarded by strict cryptographic policies. In such variants even ``/boot`` can be encrypted, with GRUB taking care of unlocking the boot partition.

These combinations give me a provisioning chain that is auditable, reproducible, and robust against both casual and targeted tampering.<br>

Once the system is up, I can trigger a set of audits from within the live environment:

* **Lynis Audit Report**: Outputs a detailed security score and recommendations, confirming a 93%+ hardening baseline.
  Type `lsadt` at the prompt. See example report: **[Lynis Audit Report](/docs/AUDIT_LYNIS.md)**
* **SSH Audit Report**: Verifies SSH daemon configuration against the latest best-practice cipher, KEX, and MAC recommendations.
  Type `ssh-audit <IP>:<PORT>`. See example report: **[SSH Audit Report](/docs/AUDIT_SSH.md)**

## 1.4. Preview

![CISS.debian.live.builder](/docs/screenshots/CISS.debian.live.builder_preview.jpeg)

## 1.5. Caution. Debian Installer and Security Context
**The Debian Installer (d-i) will ALWAYS boot a new system.**<br>

The classical Debian Installer (d-i) always boots its own kernel and its own initramfs. That effect is independent of the way it
is launched: 

* from a GRUB entry on the live medium, 
* from within a running live session via a graphical shortcut, 
* through kexec, 
* or via helper packages such as debian-installer-launcher.

In all of these cases the running live system is discarded. The memory contents of the hardened live environment vanish, the 
firewall disappears, the hardened SSH daemon is terminated, and the hardened kernel is replaced by the installer kernel. The 
installer brings its own minimal root file system, usually BusyBox plus a limited set of udeb packages, and it does not 
implement my firewall, my AppArmor profiles, my logging configuration, or my remote access policies, unless I explicitly 
reintroduce those elements via preseed.

In that phase the security properties are therefore those of d-i, not those of CISS.debian.live.builder. This is not a defect in
Debian, it is a property of how any installer that boots its own kernel behaves. It is important to keep this distinction in 
mind when deciding whether a workflow must stay inside the hardened live context or may trade that environment for the standard 
installer toolchain.

## 1.6. Versioning Schema

This project adheres strictly to a structured versioning scheme following the pattern x.y.z-Date.

Example: `V9.14.018.2026.06.07`

`x.y.z` represents major (x), minor (y), and patch (z) version increments.

Date (YYYY.MM.DD) denotes the build or release date, facilitating clear tracking of incremental changes and ensuring 
reproducibility and traceability.

## 1.7. Keywords

The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
"MAY", and "OPTIONAL" in this Repo are to be interpreted as described in [[BCP 14](https://www.rfc-editor.org/info/bcp14)], 
[[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)], [[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)] when,
and only when, they appear in all capitals, as shown here.

# 2. Features & Rationale

Below I walk through the major hardening components, with a focus on why I implemented them the way I did and how they interact.
I treat this builder as a reference implementation for my own infrastructure; **it is not a toy**.

## 2.1. Kernel Hardening

### 2.1.1. Unified Hardened Boot Parameters

Both the ``CISS.debian.live.builder`` LIVE ISO and the ``CISS.debian.installer`` rely on the same kernel command line. I consider
a diverging kernel baseline between installer and live system operationally dangerous, because it leads to two distinct sets of 
expectations about mitigations and attack surface. The boot parameters I apply are:

````bash
apparmor=1 security=apparmor audit_backlog_limit=262144 audit=1 debugfs=off \
efi=disable_early_pci_dma hardened_usercopy=1 ia32_emulation=0 \
init_on_alloc=1 init_on_free=1 \
iommu.passthrough=0 iommu.strict=1 iommu=force \
kfence.sample_interval=100 kvm.nx_huge_pages=force \
l1d_flush=on lockdown=integrity loglevel=0 \
mitigations=auto,nosmt mmio_stale_data=full,force nosmt=force \
oops=panic page_alloc.shuffle=1 page_poison=1 panic=0 pti=on \
random.trust_bootloader=off random.trust_cpu=off randomize_kstack_offset=on \
retbleed=auto,nosmt rodata=on slab_nomerge vdso32=0 vsyscall=none
````

The parameters fall into several categories.

* The AppArmor-related flags ``apparmor=1``, ``security=apparmor`` guarantee that AppArmor is not an afterthought but an integral part of the security architecture from the first instruction. I do not accept a boot sequence that comes up without LSM enforcement and then attempts to enable it later.
* The audit subsystem is configured to be always on ``audit=1`` and to tolerate heavy bursts without dropping events ``audit_backlog_limit=262144``. I treat the audit trail as an evidentiary artifact; truncation because of backlog limits is not acceptable in that model.
* The debug surface of the kernel is reduced aggressively. ``debugfs=off`` avoids a traditional footgun that exposes kernel internals in a way that is friendly to attackers and rarely necessary in production.
* Memory is hardened on several levels at allocation time and at free time. ``init_on_alloc=1`` and ``init_on_free=1`` provide deterministic zeroing, ``page_poison=1`` fills freed pages with a poison pattern, and ``page_alloc.shuffle=1`` shuffles the allocator so that a process can no longer rely on stable physical patterns. Together these measures raise the cost of use-after-free exploitation and other memory corruption attacks.
* The IOMMU is not optional. I force it on ``iommu=force``, disable passthrough, and require strict behavior ``iommu.strict=``1. Any environment that contains devices capable of DMA must have a correctly configured IOMMU, otherwise the trust model for the CPU and for the memory hierarchy collapses as soon as a hostile device is introduced.
* ``kfence.sample_interval=100`` activates KFENCE with a sampling interval that is still usable in production but sensitive enough to catch a meaningful subset of memory safety bugs under real workloads.
* Virtualization-specific knobs include ``kvm.nx_huge_pages=force``, to keep huge pages non-executable, and ``l1d_flush=on`` so that context switches flush the L1 data cache where needed.
* ``lockdown=integrity`` places the kernel into lockdown mode with an emphasis on integrity. In this project I consider the integrity of the system more critical than the ability to introspect a running kernel from userspace.
* Speculative execution and microarchitectural issues are covered by ``mitigations=auto,nosmt``,`` mmio_stale_data=full,force``, and ``retbleed=auto,nosmt``. I combine the automatic mitigation set provided by the kernel with a forced Single Thread mode where it is required because simultaneous multithreading is simply not worth the residual risk profile in many server contexts.
* ``nosmt=force`` acts as a guardrail here. It prevents a misconfiguration from quietly re-enabling SMT while the system operator assumes it is disabled.
* Fault handling is configured through ``oops=panic`` and ``panic=0``. An oops triggers a panic so that I do not continue to run a kernel in an undefined state. At the same time I instruct the system not to reboot automatically on panic, to preserve the state for post-mortem analysis rather than cutting the ground away under a debugging session.
* ``pti=on``, ``rodata=on``, and ``slab_nomerge`` are classical hardening parameters that I still consider essential. Page-table isolation, read-only data segments, and prohibiting slab merging collectively prevent a wide range of exploits, especially under pressure from speculative execution attacks.
* To avoid brittle side assumptions, I remove legacy or obsolete interfaces: ``vdso32=0`` and ``vsyscall=none`` shut down the remaining vestiges of 32-bit vDSO and vsyscall support on 64-bit systems. ``ia32_emulation=0`` it again narrows the attack surface by disabling full 32-bit compatibility on 64-bit kernels.
* Finally, I do not trust entropy claims either from the bootloader or the CPU itself. I opt out of both with ``random.trust_bootloader=off`` and ``random.trust_cpu=off`` and rely on my own entropy strategy described later.

All of these parameters are applied in exactly the same way for the live ISO and for the installer environment. That is a 
deliberate design decision.

### 2.1.2. CPU Vulnerability Mitigations

I build the kernels with the relevant mitigations for Specter, Meltdown, L1TF, MDS, TAA, Retbleed, and related families activated. 
The ``mitigations=auto,nosmt`` flag ensures that new mitigations integrated into the mainline kernel become effective as they 
are added, instead of requiring that I micromanage every single toggle. The residual performance cost is acceptable in the 
context I am targeting; stale mitigations can be revisited, but missing mitigations will not be.

### 2.1.3. Kernel Self-Protection

I enable the standard set of self-protection options, such as strict module page permissions, read-only data enforcement, and 
restrictions around kprobes and BPF. The builder is not a kernel configuration tool, but it carries the expectation that the 
kernels it runs with are compiled according to this hardening profile. I treat deviations from that profile as unsupported.

### 2.1.4. Local Kernel Hardening

The wrapper `sysp()`provides a function to apply and audit local kernel hardening rules from `/etc/sysctl.d/90-ciss-local.hardened`:
````bash
#######################################
# Wrapper for loading CISS hardened Kernel Parameters.
# Arguments:
#   None
#######################################
sysp() {
  sysctl -p /etc/sysctl.d/90-ciss-local.hardened
  # shellcheck disable=SC2312
  sysctl -a | grep -E 'kernel|vm|net' >| /var/log/sysctl_check"$(date +"%Y-%m-%d_%H:%M:%S")".log
}
````
* **Key measures loaded by this file include:**
  * Disabling module loading `kernel.modules_disabled=1`
  * Restricting kernel pointers & logs `kernel.kptr_restrict=2`, `kernel.dmesg_restrict=1`, `kernel.printk=3 3 3 3`
  * Disabling unprivileged BPF and userfaultfd
  * Disabling kexec and unprivileged user namespaces
  * Locking down ptrace scope `kernel.yama.ptrace_scope=2`
  * Protecting filesystem links and FIFOs `fs.protected_*`

**Warning**
Once applied, some hardening settings cannot be undone via `sysctl` without a reboot, and dynamic module loading remains disabled
until the next boot. Automatic enforcement at startup is therefore omitted by design—run `sysp()` manually and plan a reboot to 
apply or revert these controls.

In case you provide the ``--cdi`` option to the installer, the ``sysp()`` function is automatically applied at the boot process via:
[9999_cdi_starter.sh](scripts/usr/local/sbin/9999_cdi_starter.sh).

For further details see: **[90-ciss-local.hardened.md](docs/documentation/90-ciss-local.hardened.md)**

## 2.2. Module Blacklisting

* **Description**: Disables and blacklists non-essential or insecure kernel modules.
* **Rationale**: Minimizes attack surface by preventing loads of drivers or modules not required by the live environment.

For further details see: **[30-ciss-hardening.conf.md](docs/documentation/30-ciss-hardening.conf.md)**

## 2.3. Network Hardening

At the kernel level classical ``sysctl`` settings are applied that defend against spoofing and sloppy network behavior. Reverse path 
filtering is enabled, ARP handling is pinned down, and loose binding of addresses is discouraged. Where appropriate, IPv6 
receives the same level of attention as IPv4. The network stack is switched firmly to ``systemd-networkd`` and ``systemd-resolved``. 
The hook [0000_basic_chroot_setup.chroot](config/hooks/live/0000_basic_chroot_setup.chroot) removes ``ifupdown``, wires up 
``systemd-networkd`` and ``systemd-resolved`` via explicit WantedBy symlinks, and ensures that the stub resolver at ``127.0.0.53``
is the canonical ``resolv.conf`` target. The same hook writes dedicated configuration snippets:

``/etc/systemd/resolved.conf.d/10-ciss-dnssec.conf`` enforces opportunistic ``DNS-over-TLS`` and full ``DNSSEC`` validation 
while disabling ``LLMNR`` and ``MulticastDNS``.

This converges the system on a single, hardened DNS resolution path and avoids the common situation where multiple name 
resolution mechanisms step on each other. Where desired, this resolution chain can be plugged into **CenturionDNS**, a resolver
infrastructure that I control and that enforces DNSSEC validation, QNAME minimisation, and a curated blocklist. For sensitive 
deployments, this stack is used as the default.

For further details see: **[90-ciss-local.hardened.md](docs/documentation/90-ciss-local.hardened.md)**

## 2.4. Core Dump & Kernel Hardening

* **Description**: Limits core dump generation paths, enforces `Yama` restrictions, and configures `kernel.kptr_restrict`.
* **Rationale**: Prevents leakage of sensitive memory contents and reduces information disclosure from unintentional crash
  dumps.

## 2.5. Entropy Collection Improvements

* **Description**: Installs and configures `haveged`, seeds `/dev/random` early.
* **Rationale**: Cloud instances frequently suffer low entropy at the start; improving randomness ensures strong cryptographic key
  generation for SSH and other services.

## 2.6. Permissions & Authentication

* **Description**: Sets strict directory and file permissions, integrates with PAM modules (e.g., `pam_faillock`).
* **Rationale**: Enforces the principle of least privilege at file-system level and strengthens authentication policies.

## 2.7. High-Security Baseline (Lynis Audit)

* **Description**: Run a baseline audit via [Lynis](https://cisofy.com/lynis/) after build completion. 
  The generated live environment consistently achieves a 91%+ score in Lynis security audits.
* **Rationale**: Provides independent verification of security posture and flags any configuration drifts or missing
  hardening steps.

## 2.8. SSH Tunnel & Access Security

* **Description**: The SSH tunnel and access are secured through multiple layers of defense:
  * **Firewall Restriction**: ufw allows connections only from defined jump host or VPN exit node IPs.
  * **TCP Wrappers**: `/etc/hosts.allow` and `/etc/hosts.deny` enforce an `ALL: ALL` deny policy, permitting only specified hosts.
  * **One-Hit Ban**: A custom Fail2Ban rule `/etc/fail2ban/jail.d/ciss-default.conf` immediately bans any host 
    that touches closed ports. 
    * Additionally, the `fail2ban` service is hardened as well according to:
    [Arch Linux Wiki Fail2ban Hardening](https://wiki.archlinux.org/title/fail2ban#Service_hardening) 
  * **SSH Ultra-Hardening**: The `/etc/sshd_config` enforces strict cryptographic and connection controls with respect to 
    [SSH Audit Guide Debian 12](https://www.ssh-audit.com/hardening_guides.html#debian_12):
    * `RekeyLimit 1G 1h`
    * `HostKey /etc/ssh/ssh_host_ed25519_key`
    * `HostKey /etc/ssh/ssh_host_rsa_key (8192-bit RSA)`
    * `PubkeyAuthentication yes`
    * `PermitRootLogin prohibit-password`
    * `PasswordAuthentication no`
    * `PermitEmptyPasswords no`
    * `LoginGraceTime 2m`
    * `MaxAuthTries 3`
    * `MaxSessions 2`
    * `MaxStartups 08:64:16`
    * `PerSourceMaxStartups 4`
    * `RequiredRSASize 4096`
    * `Ciphers aes256-gcm@openssh.com`
    * `KexAlgorithms sntrup761x25519-sha512@openssh.com,sntrup761x25519-sha512,gss-curve25519-sha256-`
    * `MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com`
* **Rationale**: These measures ensure that only authorized hosts can establish SSH tunnels, with strict cryptographic and usage 
  policies enforced. Minimizes brute force, passive sniffing, and reduces credentials' exposure by limiting protocol features to
  vetted algorithms.

## 2.9. UFW Hardening

* **Description**: Defaults to `deny incoming` and (optionally) `deny outgoing`; automatically opens only whitelisted ports.
* **Rationale**: Implements a default-deny firewall, reducing lateral movement and data exfiltration risks immediately after
  deployment.

## 2.10. Fail2Ban Enhancements

* **Description**:
  * Bans any connection to a closed port for 24 hours
  * Automatically ignores designated bastion/jump host subnets
  * Hardened via `systemd` policy override to limit privileges of the Fail2Ban service itself
* **Rationale**: Provides proactive defense against port scans and brute-force attacks, while isolating the ban daemon in a
  minimal-privilege context.

## 2.11. NTPsec & Chrony

* **Description**: Installs `chrony`, selects PTB NTPsec servers by default.
* **Rationale**: Ensures tamper-resistant time synchronization, which is essential for log integrity, certificate validation,
  and forensic accuracy.

# 3. Script Features & Rationale

## 3.1. Input Validation & Security

* **Description**: All script arguments are validated using a robust input sanitizer.
* **Rationale**: Prevents injection attacks and ensures only expected data types and values are processed.

## 3.2. Debug Mode with Detailed Logging

* **Description**: A built-in debug mode outputs clear, timestamped logs including:

  * Script Name and Path of called Function,
  * Line Number,
  * Function Name,
  * Exit Code of the previous Command,
  * Executed Command.
* **Rationale**: Simplifies troubleshooting and provides precise error tracing.

## 3.3. Secure Debug Logging

* **Description**: No hardcoded plaintext password fragments or sensitive artifacts appear in debug logs.
* **Rationale**: Prevents accidental exposure of credentials during troubleshooting.

## 3.4. Secure Password Handling

* **Description**: Password files, if provided, are shredded immediately after being hashed.
* **Rationale**: Prevents password recovery from temporary files.

## 3.5. Variable Declaration & Validation

* **Description**: All variables are declared and validated before use.
* **Rationale**: Avoids unintended behavior from unset or improperly set variables.

## 3.6. Pure Bash Implementation

* **Description**: The entire wrapper and all its functions are written in pure Bash, without external dependencies.
* **Rationale**: Ensures maximum portability and compatibility with standard Debian environments.

## 3.7. Bash Error Handling

* **Description**: The implemented xtrace wrapper `set -x` enforces comprehensive Bash error handling to ensure
  * robust, 
  * predictable execution,
  * and early detection of failures.
  
  and delivers full information, which command failed to execute:
  * Script Name and Path of called Function,
  * Line Number,
  * Function Name,
  * Exit Code of the previous Command,
  * Executed Command,
  * Environment Settings,
  * Argument Counter passed to Script,
  * Argument String passed to Script.

* The following `set` options are applied at the beginning of the script (see 
  [Bash Manual, The Set Builtin](https://www.gnu.org/software/bash/manual/bash.html#The-Set-BuiltinGNU)):
```bash
set -o errexit   # Exit script when a command exits with non-zero status (same as "set -e").
set -o errtrace  # Inherit ERR traps in subshells (same as "set -E").
set -o functrace # Inherit DEBUG and RETURN traps in subshells (same as "set -T").
set -o ignoreeof # An interactive shell will not exit upon reading EOF.
set -o nounset   # Exit script on use of an undefined variable (same as "set -u").
set -o pipefail  # Return the exit status of the last failed command in a pipeline.
set -o noclobber # Prevent overwriting files via redirection (same as "set -C").
```

* The following `shopt` options are applied at the beginning of the script (see
  [Bash Manual, The Shopt Builtin](https://www.gnu.org/software/bash/manual/bash.html#The-Shopt-Builtin)):
````bash
shopt -s failglob        # If set, patterns that fail to match filenames during filename expansion result in an expansion error.
shopt -s inherit_errexit # If set, command substitution inherits the value of the errexit option instead of unsetting it in the
                         # subshell environment.
shopt -s lastpipe        # If set, and job control is not active, the shell runs the last command of a pipeline not executed in
                         # the background in the current shell environment.
shopt -u expand_aliases  # If set, aliases are expanded as described. This option is enabled by default for interactive shells.
shopt -u dotglob         # If set, Bash includes filenames beginning with a '.' in the results of filename expansion.
shopt -u extglob         # If set, enable the extended pattern matching features.
shopt -u nullglob        # If set, filename expansion patterns that match no files expand to nothing and are removed.
````

* **Rationale**: These options enforce strict error checking and handling, reducing silent failures and ensuring 
predictable script behavior.

# 4. Prerequisites

To use **``CISS.debian.live.builder``** as intended, the following baseline is expected:<br>

* The build host runs Debian 13 Trixie, fully updated. Building a Trixie image on an older or newer release is technically possible but explicitly not supported.
* The host has the standard live-build stack installed ``live-build``, ``live-boot``, ``live-config``, ``debootstrap`` and the cryptographic tooling required for ``LUKS2``, ``dm-integrity``, ``cryptsetup``, ``gpg``.
* Disk space must be sufficient to hold the chroot, the temporary build artifacts, and the final ISO with encrypted root. For comfortable work I assume around 30–40 gigabytes of free space.
* The user running the builder has root privileges and understands that the script is capable of creating, mounting, and manipulating block devices.

# 5. Installation & Usage

## 5.1. Interactive CLI / Dialog Wrapper

1. Clone the repository:
   ```bash
   git clone https://git.coresecret.dev/msw/CISS.debian.live.builder.git
   cd CISS.debian.live.builder
   ```
   
2. Preparation:
   1. Ensure you are root.
   2. Create the build directory `mkdir /opt/cdlb` and the tmpfs secrets directory `mkdir /dev/shm/cdlb_secrets`.
   3. Place your desired SSH public key in the `authorized_keys` file, for example, in the `/dev/shm/cdlb_secrets` directory.
   4. Place your desired Password in the `password.txt` file, for example, in the `/dev/shm/cdlb_secrets` directory.
   5. Make any other changes you need to.

3. Run the config builder script `./ciss_live_builder.sh` and the integrated `lb build` command (example):

   ````bash
   chmod 0700 ./ciss_live_builder.sh
   timestamp=$(date -u +%Y-%m-%dT%H:%M:%S%z)
   ./ciss_live_builder.sh \
     --architecture amd64 \
     --autobuild=6.16.3+deb13-amd64 \
     --build-directory /opt/cdlb \
     --cdi \
     --change-splash hexagon \
     --control "${timestamp}" \
     --debug \
     --dhcp-centurion \
     --jump-host 10.0.0.128 [c0de:4711:0815:4242::1] [2abc:4711:0815:4242::1]/64 \
     --key_age=keys.txt \
     --key_luks=luks.txt \
     --provider-netcup-ipv6 [c0de:4711:0815:4242::ffff] \
     --reionice-priority 1 2 \
     --renice-priority "-19" \
     --root-password-file /dev/shm/cdlb_secrets/password.txt \
     --secure-boot-profile debian-shim \
     --sops-version 3.13.0 \
     --signing_key_fpr=98089A472CCF4601CD51D7C7095D36535296EA14B8DE92198723C4DC606E8F76 \
     --signing_key_pass=signing_key_pass.txt \
     --signing_key=signing_key.asc \
     --ssh-port 4242 \
     --ssh-pubkey /dev/shm/cdlb_secrets \
     --sshfp \
     --trixie
   ````

   `--sops-version` selects the upstream SOPS release installed into the live system. If omitted, the builder uses
   `VAR_SOPS_VERSION` from `var/global.var.sh`. The SOPS hook verifies the upstream checksums file with Cosign and supports
   both the newer Sigstore bundle asset and the legacy split certificate/signature assets before checking the downloaded
   SOPS binary with `sha256sum -c --ignore-missing`.

4. Locate your ISO in the `--build-directory`.
5. Boot from the ISO and login to the live image via the console, or the multi-layer secured **coresecret** SSH tunnel.
6. Type `sysp` for the final kernel hardening features.
7. Check the boot log with `jboot` and via `ssf` that all services are up.
8. Finally, audit your environment with `lsadt` for a comprehensive Lynis audit.
9. Type `celp` for some shortcuts.

## 5.2. Make Wrapper, Quick Usage

This repo ships a thin make wrapper around ``./ciss_live_builder.sh``, so you can compose a correctly quoted command and either 
preview it or run it.

1. Clone the repository:

   ```bash
   git clone https://git.coresecret.dev/msw/CISS.debian.live.builder.git
   cd CISS.debian.live.builder
   ```

2. Preparation:
   1. Ensure you are root.
   2. Create the build directory `mkdir /opt/cdlb` and the tmpfs secrets directory `mkdir /dev/shm/cdlb_secrets`.
   3. Place your desired SSH public key in the `authorized_keys` file, for example, in the `/dev/shm/cdlb_secrets` directory.
   4. Place your desired Password in the `password.txt` file, for example, in the `/dev/shm/cdlb_secrets` directory.
   5. Copy and edit the sample and set your options (no spaces around commas in lists): 

    ````bash
    cp config.mk.sample config.mk
    ````

    ````bash
    BUILD_DIR=/opt/cdlb
    ROOT_PASSWORD_FILE=/dev/shm/cdlb_secrets/password.txt
    SECURE_BOOT_PROFILE=debian-shim
    SOPS_VERSION=3.13.0
    SSH_PORT=4242
    SSH_PUBKEY=/dev/shm/cdlb_secrets

    # Optional
    PROVIDER_NETCUP_IPV6=2001:cdb::1
    # comma-separated; IPv6 in [] is fine
    JUMP_HOSTS=[2001:db8::1],[2001:db8::2]     
    ````

3. Dry-run first (prints the exact command): ````make dry-run````

4. Execute the build: ````make live````

## 5.3. Secure Boot Profiles

The default build profile is ``--secure-boot-profile debian-shim``. It keeps the ISO broadly portable: ``lb config`` uses an
``iso-hybrid`` image with both ``grub-pc`` and ``grub-efi`` bootloaders, and UEFI Secure Boot remains delegated to live-build's
standard Microsoft-signed Debian shim plus Debian-signed GRUB path.

The custom profile is ``--secure-boot-profile ciss-uki``. It is intended for amd64 systems whose firmware trusts the CISS Secure
Boot key material through the platform Secure Boot database, or a custom PK/KEK/db model. In this profile a late binary hook
builds a Unified Kernel Image from the final ``binary/live/vmlinuz-*`` and ``binary/live/initrd.img-*`` artifacts, signs it with
``ciss.secureboot/private/ciss-efi-image.key`` and ``ciss.secureboot/public/ciss-efi-image.crt``, rebuilds
``binary/boot/grub/efi.img``, installs the signed UKI as ``EFI/BOOT/BOOTX64.EFI``, and mirrors it into the ISO EFI tree when
live-build created one.

Required files for ``ciss-uki``:

````text
ciss.secureboot/private/ciss-efi-image.key
ciss.secureboot/public/ciss-efi-image.crt
````

The private directory is ignored by Git. The hooks fail if the CISS EFI image signing key or module signing key appears below
``binary/``, ``chroot/`` or ``config/includes.*``. Build-time UKI manifests are written below the build directory in
``ciss.secureboot/manifests`` and can be checked with ``ukify inspect`` and ``sbverify``.

## 5.4. CI/CD Gitea Runner Workflow Example

1. Clone the repository:

   ```bash
   git clone https://git.coresecret.dev/msw/CISS.debian.live.builder.git
   cd CISS.debian.live.builder
   ```
2. Edit the `.gitea/workflows/generate-iso.yaml` file according to your requirements. Ensure that the trigger file
   `.gitea/trigger/t_generate.iso.yaml` and the counter are updated. Change all the necessary `{{ secrets.VAR }}`.
   Push your commits to trigger the workflow. Then download your final ISO from the specified Location.

  ```yaml
  #...
      steps:
        - name: Preparing SSH Setup, SSH Deploy Key, Known Hosts, .config.
          run: |
            rm -rf ~/.ssh && mkdir -m700 ~/.ssh

            ### Private Key
            echo "${{ secrets.CHANGE_ME }}" >| ~/.ssh/id_ed25519
            chmod 0600 ~/.ssh/id_ed25519
  #...
        ### https://github.com/actions/checkout/issues/1843
        - name: Using manual clone via SSH to circumvent Gitea SHA-256 object issues.
          run: |
            git clone --branch "${GITHUB_REF_NAME}" ssh://git@CHANGE_ME .
  #...
        - name: Importing the 'CI PGP DEPLOY ONLY' key.
          run: |
            ### GPG-Home relative to the Runner Workspace to avoid changing global files.
            export GNUPGHOME="$(pwd)/.gnupg"
            mkdir -m700 "${GNUPGHOME}"
            echo "${{ secrets.CHANGE_ME }}" >| ci-bot.sec.asc
  #...
        - name: Configuring Git for signed CI/DEPLOY commits.
          run: |
            export GNUPGHOME="$(pwd)/.gnupg"
            git config user.name "CHANGE_ME"
            git config user.email "CHANGE_ME"
  #...
        - name: Preparing the build environment.
          run: |
            mkdir -p /opt/config
            mkdir -p /opt/livebuild
            echo "${{ secrets.CHANGE_ME }}" >| /opt/config/password.txt
            echo "${{ secrets.CHANGE_ME }}" >| /opt/config/authorized_keys
  #...
        - name: Starting CISS.debian.live.builder. This may take a while ...
          run: |
            chmod 0700 ciss_live_builder.sh && chown root:root ciss_live_builder.sh
            timestamp=$(date -u +"%Y_%m_%d_%H_%M_Z")
            ### Change "--autobuild=" to the specific kernel version you need: '6.12.22+bpo-amd64'.
            ./ciss_live_builder.sh \
              --autobuild=CHANGE_ME \
              --architecture CHANGE_ME \
              --build-directory /opt/livebuild \
              --control "${timestamp}" \
              --jump-host "${{ secrets.CHANGE_ME }}" \
              --root-password-file /opt/config/password.txt \
              --ssh-port CHANGE_ME \
              --ssh-pubkey /opt/config
  #...
        ### SKIP OR CHANGE ALL REMAINING STEPS
  ```

# 6. Licensing & Compliance

Unless stated otherwise in individual files via SPDX headers, this project is licensed under the European Union Public License (EUPL 1.2).
That license is OSI-approved and compatible with internal use in both public sector and private environments. Several files carry
dual or multi-license statements, for example **``LicenseRef-CNCL-1.1``** and / or **``LicenseRef-CCLA-1.1``**, where I offer a 
non-commercial license for community use and a commercial license for professional integration. The SPDX headers in each file 
are authoritative. If you plan to integrate **``CISS.debian.live.builder``** into a commercial product or a managed service 
offering, you should treat these license markers as binding and reach out for a proper agreement where required.

# 7. Disclaimer

This repository is designed for well-experienced administrators and security professionals who are comfortable with low-level 
Linux tooling, cryptography, and automation. It can and will create, format, and encrypt devices. It is entirely possible to 
destroy data if you use it carelessly. I publish this work in good faith and with a strong focus on correctness and robustness. 
Nevertheless, there is no warranty of any kind. You are responsible for understanding what you are doing, for validating your 
own threat model, and for ensuring that this tool fits your regulatory and operational environment. If you treat the builder, and 
the resulting images with the same discipline with which they were created, you will obtain a hardened, reproducible, and 
auditable base for serious systems. If you treat them casually, they will not save you from yourself.

---
**[no tracking | no logging | no advertising | no profiling | no bullshit](https://coresecret.eu/)**
<!-- vim: set number et ts=2 sw=2 sts=2 ai tw=128 ft=markdown -->
