Why Zero Trust Matters on Linux

The traditional perimeter-based security model assumes that everything inside the network boundary can be trusted. This assumption has proven catastrophically wrong. The 2020 SolarWinds supply chain attack compromised dozens of federal agencies by backdooring legitimate software updates. The 2021 Colonial Pipeline ransomware attack — which forced a six-day shutdown of fuel supply to the U.S. East Coast — was traced by Mandiant investigators to a single compromised VPN credential on an inactive, unprotected account that lacked multi-factor authentication (Bloomberg, June 2021; U.S. Senate Judiciary testimony, Joseph Blount, June 2021). Once an attacker gains entry, the castle-and-moat approach provides little resistance to lateral movement, privilege escalation, or data exfiltration. Zero Trust fundamentally rejects this premise.

The Zero Trust model, formalized by NIST in Special Publication 800-207, operates on a deceptively simple principle: never trust, always verify. Every user, device, application, and network flow must be authenticated, authorized, and continuously validated regardless of where it originates. There is no implicit trust granted based on network location, IP address, or prior authentication.

Linux underpins a substantial portion of global infrastructure. Web servers, cloud workloads, containerized applications, IoT devices, and development pipelines all run predominantly on Linux. This ubiquity makes Linux hardening not just a best practice but a strategic necessity. Fortunately, Linux ships with a remarkably powerful set of built-in security primitives that align naturally with Zero Trust principles: mandatory access controls, namespace isolation, cryptographic authentication, fine-grained privilege separation, and extensive audit logging.

This guide walks through implementing Zero Trust architecture on Linux systems in a practical, hands-on manner. Each section addresses a specific pillar of Zero Trust and translates abstract policy into concrete commands, configurations, and verification steps. The goal is not theoretical completeness but operational readiness.

Prerequisites

This guide assumes familiarity with Linux administration, basic networking concepts, and comfort working in the terminal. Commands are shown for both Debian/Ubuntu and RHEL/CentOS/Fedora families where distributions differ significantly.

Zero Trust Principles and the Linux Security Model

Zero Trust Tenets and Pillars: Distinguishing NIST from CISA

A common source of confusion in Zero Trust implementation is the difference between NIST SP 800-207 and the CISA Zero Trust Maturity Model. They are related but distinct frameworks.

NIST SP 800-207 (August 2020) defines seven tenets of Zero Trust architecture. As the publication states: (1) all data sources and computing services are considered resources; (2) all communication is secured regardless of network location; (3) access to individual enterprise resources is granted on a per-session basis; (4) access to resources is determined by dynamic policy; (5) the enterprise monitors and measures the integrity and security posture of all owned and associated assets; (6) all resource authentication and authorization are dynamic and strictly enforced before access is allowed; and (7) the enterprise collects as much information as possible about assets, network infrastructure, and communications to improve its security posture. (Source: NIST SP 800-207, Section 2.1)

The five-pillar model (Identity, Devices, Networks, Applications and Workloads, Data) comes from CISA’s Zero Trust Maturity Model (ZTMM), version 2.0, April 2023. As CISA states: “The maturity model, which includes five pillars and three cross-cutting capabilities, is based on the foundations of zero trust.” (Source: CISA, Zero Trust Maturity Model v2.0, cisa.gov) The CISA five-pillar framework is widely used in industry and is excellent for implementation planning, but it should not be attributed to NIST SP 800-207 directly.

The table below uses the CISA five-pillar framework because it maps cleanly to Linux implementation domains. Each pillar is grounded in NIST principles but organized for operational use.

ZT Pillar Core Principle Linux Implementation
Identity Authenticate all users and services PAM, SSH keys, certificates, SSSD
Devices Validate device health before granting access SELinux/AppArmor, secure boot, TPM
Networks Micro-segment and encrypt all traffic iptables/nftables, WireGuard, VLANs
Applications Least-privilege access to workloads capabilities, seccomp, namespaces
Data Classify and protect data at rest/transit LUKS, TLS, filesystem permissions

Linux Security Architecture Overview

Linux implements security through multiple independent layers that work together. The kernel enforces Discretionary Access Control (DAC) through traditional Unix permissions and Mandatory Access Control (MAC) through frameworks like SELinux and AppArmor. Above the kernel, PAM (Pluggable Authentication Modules) provides flexible authentication pipelines, while audit subsystems record security-relevant events.

A key insight for Zero Trust implementation: Linux security primitives were not designed as a unified system. They evolved organically over decades. Implementing Zero Trust on Linux means understanding each mechanism individually and then composing them thoughtfully. No single tool accomplishes the goal. Defense in depth is not just a principle here; it is an architectural reality.

Identity and Authentication Hardening

SSH Hardening

SSH is the primary administrative entry point for Linux systems and therefore the most critical authentication surface to harden. The default SSH configuration on many distributions is permissive. A Zero Trust posture requires explicit restriction.

Begin by editing the SSH daemon configuration file at /etc/ssh/sshd_config. The following settings represent a hardened baseline:

/etc/ssh/sshd_config
# Zero Trust Hardened Configuration

# Explicitly enable public key authentication (default yes, but make it explicit)
PubkeyAuthentication yes

# Disable password authentication entirely
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no

# Disable root login
PermitRootLogin no

# Restrict to specific users or groups
AllowGroups sshusers admins

# Use only strong key exchange algorithms
KexAlgorithms curve25519-sha256,[email protected]
# NOTE: rsa-sha1 (SHA-1 based RSA signatures) must never be enabled.
# SHA-1 is cryptographically broken. The algorithms above restrict
# RSA to SHA-2 variants only (rsa-sha2-256, rsa-sha2-512).
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
Ciphers [email protected],[email protected]
MACs [email protected],[email protected]

# Reduce attack surface
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2

# Disable forwarding unless needed
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no

# Enable detailed logging
LogLevel VERBOSE

# NOTE: If adding PAM-based MFA (see below), set this to yes
# and configure AuthenticationMethods accordingly.
# For key-only environments without PAM MFA, no is correct.

After editing the configuration, validate it before restarting the daemon:

$ sudo sshd -t && sudo systemctl restart sshd

SSH Certificate Authority

Individual SSH key management does not scale. As infrastructure grows, managing authorized_keys files across many servers becomes unmanageable and error-prone. SSH Certificate Authorities provide a scalable alternative where a central CA signs user and host keys, and servers trust certificates signed by that CA rather than individual keys.

SSH CA setup
# 1. Generate the CA key pair on a secure, offline system
$ ssh-keygen -t ed25519 -f /etc/ssh/ssh_ca -C 'SSH Certificate Authority'

# 2. Configure servers to trust the CA
# Add to /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ssh_ca.pub

# 3. Sign user certificates with expiration (least privilege in time)
$ ssh-keygen -s /etc/ssh/ssh_ca -I '[email protected]' \
  -n alice -V +8h -z 1 /home/alice/.ssh/id_ed25519.pub
Pro Tip

Certificate-based SSH is a foundational Zero Trust control. Short-lived certificates (hours, not years) enforce continuous re-verification of identity, aligning with the 'always verify' principle. Compromised certificates expire quickly without requiring key revocation infrastructure.

Multi-Factor Authentication with PAM

Even with certificate-based SSH, adding a second factor to privileged access provides defense in depth. The Google Authenticator PAM module adds TOTP-based MFA to SSH and local console logins.

Configuration Conflict Warning

The SSH hardening baseline above sets ChallengeResponseAuthentication no, which disables PAM challenge-response. If you enable PAM-based MFA, you must change this to ChallengeResponseAuthentication yes and add AuthenticationMethods publickey,keyboard-interactive. These two directives override the baseline setting. The AuthenticationMethods directive requires OpenSSH 6.2 or later. Always test PAM configuration in a separate terminal session before closing your active session, as a misconfiguration will lock you out. Use sshd -t to validate config syntax before restarting.

MFA setup
# Debian/Ubuntu
$ sudo apt install libpam-google-authenticator

# RHEL/CentOS/Fedora
$ sudo dnf install google-authenticator-libpam

# Configure PAM for SSH in /etc/pam.d/sshd
auth required pam_google_authenticator.so

# Enable in sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

Privileged Access Management

Zero Trust requires that even authenticated administrators receive only the access necessary for the task at hand. The sudo facility provides fine-grained privilege delegation, but its default configuration is often too permissive.

Key sudo hardening principles:

/etc/sudoers.d/webadmin
Defaults:webadmin timestamp_timeout=0
Defaults:webadmin log_output

# Web admin can restart nginx only
webadmin ALL=(root) /usr/bin/systemctl restart nginx, \
                     /usr/bin/systemctl reload nginx, \
                     /usr/bin/systemctl status nginx
Safety Note: Editing Sudoers

Always edit /etc/sudoers and files in /etc/sudoers.d/ using visudo or visudo -f /etc/sudoers.d/filename, never a plain text editor. visudo validates syntax before saving and prevents locking yourself out due to a syntax error. A broken sudoers file can make it impossible to regain root access without a rescue boot.

Mandatory Access Control with SELinux and AppArmor

SELinux Fundamentals

Security-Enhanced Linux (SELinux) is a Mandatory Access Control framework originally developed by the NSA and released to the open source community under the GNU GPL on December 22, 2000. It was merged into the mainline Linux kernel in 2003. As noted by Phoronix (2023), with the Linux 6.6 kernel, NSA branding was removed from the codebase entirely: “SELinux has long since transitioned to a wide community of developers and maintainers” including Red Hat, Trusted Computer Solutions, and the broader open source community. (Sources: SELinux Wikipedia; NSA SELinux initial public release documentation; Phoronix, 2023) It enforces policies that restrict what processes can access, regardless of traditional Unix permissions. Even if an attacker compromises a process, SELinux confines the damage to only what that process's policy explicitly permits.

SELinux operates in three modes: Enforcing (violations blocked and logged), Permissive (violations logged but not blocked, useful for policy development), and Disabled (completely inactive — never acceptable in production).

SELinux also supports two major policy types. Targeted policy is the default on RHEL, CentOS, and Fedora: it confines a defined set of high-risk daemons (web servers, DNS, mail, etc.) while leaving other processes largely unconfined. This is the right starting point for most organizations. Multi-Level Security (MLS) policy implements lattice-based access controls with sensitivity labels (Unclassified through Top Secret) and is typically used only in government and defense contexts where formal information flow control is required. The SELINUXTYPE=targeted line in /etc/selinux/config controls which policy is loaded. For most Linux environments, targeted policy provides substantial protection with manageable operational overhead.

SELinux management
# Check current mode and set to enforcing
$ getenforce
$ setenforce 1

# Make enforcing persistent across reboots
# Edit /etc/selinux/config
SELINUX=enforcing
SELINUXTYPE=targeted

# View recent denials
$ ausearch -m avc -ts recent

# Generate human-readable explanation and suggested fix
$ audit2why < /var/log/audit/audit.log

# Generate a custom policy module to allow specific action
$ audit2allow -M mypolicy < /var/log/audit/audit.log
$ semodule -i mypolicy.pp
Caution

Never disable SELinux to fix a problem. When you encounter an SELinux denial, use audit2why to understand what is being blocked and why, then either fix the underlying configuration (preferred) or create a targeted policy module.

AppArmor Fundamentals

AppArmor is the MAC framework used by default on Debian, Ubuntu, and SUSE. It takes a path-based approach to access control, restricting programs to a defined set of files, capabilities, and network access. AppArmor profiles are generally considered more approachable than SELinux policy.

AppArmor management
# Check status
$ sudo apparmor_status

# Put a profile in complain mode for testing
$ sudo aa-complain /etc/apparmor.d/usr.sbin.nginx

# Generate a new profile based on program behavior
$ sudo aa-genprof /usr/sbin/myapp

# Enforce a profile
$ sudo aa-enforce /etc/apparmor.d/myapp

Linux Capabilities

Traditional Unix security has two privilege levels: root (all privileges) and non-root (restricted). Linux capabilities divide root's omnipotence into discrete units that can be granted or removed independently. A Zero Trust approach grants processes only the specific capabilities they require.

Capability What It Allows Common Use Case
CAP_NET_BIND_SERVICE Bind to ports below 1024 Web servers, DNS
CAP_NET_RAW Use raw sockets ping, network tools
CAP_SYS_PTRACE Trace arbitrary processes Debuggers (strace, gdb)
CAP_DAC_OVERRIDE Bypass file permission checks Avoid granting to any process
CAP_SYS_ADMIN Wide range of admin operations High risk, minimize use
terminal
# Allow nginx to bind port 80 without root
$ sudo setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx

# Verify capabilities
$ getcap /usr/sbin/nginx

# Remove all capabilities
$ sudo setcap -r /usr/sbin/nginx

Network Microsegmentation with nftables

From iptables to nftables

nftables is the modern Linux firewall framework that replaces iptables, ip6tables, arptables, and ebtables with a unified, more performant interface. On contemporary Linux distributions, nftables is the recommended tool for implementing network security policy.

A practical note on distribution state: many distros ship an iptables-nft compatibility layer, where the iptables command is a frontend that writes rules into the nftables kernel subsystem behind the scenes. This means legacy iptables commands may work but you are still operating through nftables. You can verify which backend is active with iptables -V — output containing "nf_tables" confirms the nftables backend is in use. Writing rules directly in native nftables syntax (as shown below) is preferred: it avoids translation overhead, provides cleaner rule inspection via nft list ruleset, and prevents conflicts between rules written through both interfaces.

Key nftables concepts for Zero Trust implementation:

Zero Trust Network Policy with nftables

A Zero Trust network policy for a Linux server starts with a default-deny posture and explicitly permits only required traffic. The following example implements a policy for a web server that also runs a local monitoring agent:

/etc/nftables.conf
#!/usr/sbin/nft -f
# Zero Trust nftables policy

table inet filter {

  # Define trusted management networks
  set mgmt_nets {
    type ipv4_addr
    flags interval
    elements = { 10.10.1.0/24, 10.10.2.0/24 }
  }

  # Define allowed services
  set allowed_tcp_in {
    type inet_service
    elements = { 80, 443 }
  }

  chain input {
    type filter hook input priority 0; policy drop;

    # Allow loopback
    iif lo accept

    # Allow established/related connections
    ct state established,related accept

    # Drop invalid connections
    ct state invalid drop

    # Allow ICMP (type-limited)
    icmp type { echo-request, echo-reply } limit rate 5/second accept

    # Allow SSH only from management networks
    tcp dport 22 ip saddr @mgmt_nets ct state new accept

    # Allow web traffic
    tcp dport @allowed_tcp_in ct state new accept

    # Log and drop everything else
    log prefix "nftables-drop: " flags all
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}
$ sudo nft -f /etc/nftables.conf && sudo systemctl enable nftables
Egress Filtering and Zero Trust

The output chain above uses policy accept, which is the default for many servers and avoids breaking outbound connections. A strict Zero Trust posture should consider default-deny egress as well. Unrestricted outbound traffic enables attackers to exfiltrate data and establish command-and-control callbacks even after a successful compromise. For high-security environments, define an explicit allowlist for outbound connections (DNS, NTP, package repositories, monitoring endpoints) and drop everything else. Start in logging mode to identify legitimate traffic before enforcing the egress policy.

WireGuard for Zero Trust Network Access

WireGuard is a modern, high-performance VPN protocol built into the Linux kernel since version 5.6. Its simplicity, speed, and cryptographic soundness make it an excellent foundation for Zero Trust network access between services and for securing administrative access.

/etc/wireguard/wg0.conf
# Install WireGuard
$ sudo apt install wireguard       # Debian/Ubuntu
$ sudo dnf install wireguard-tools  # RHEL/Fedora

# Generate key pair
$ wg genkey | tee privatekey | wg pubkey > publickey

# Server configuration
[Interface]
PrivateKey = <server_private_key>
Address = 10.200.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.200.0.2/32

Container and Process Isolation

Linux Namespaces

Linux namespaces provide process-level isolation for various system resources. Containers like Docker and Podman are built on namespaces. Understanding namespaces directly helps implement Zero Trust at the process level even without a container runtime.

Namespace Isolates Zero Trust Value
PID Process ID space Processes cannot see or signal host processes
Network Network interfaces, routes Separate network stack per workload
Mount Filesystem mount points Restrict visible filesystem
UTS Hostname and domain Separate identity per workload
User User and group IDs User namespace root != host root
Cgroup Cgroup root directory Resource isolation visibility

seccomp Filtering

seccomp (secure computing mode) allows processes to restrict the system calls they can make. This is a powerful Zero Trust control: a compromised process cannot exploit system calls it has never been allowed to invoke.

seccomp usage
# Check if a process uses seccomp
$ grep Seccomp /proc/<pid>/status
# 0 = disabled, 1 = strict, 2 = filter mode

# Apply a custom seccomp profile to a container
$ docker run --security-opt seccomp=/etc/seccomp/myapp.json myapp

# Run with no-new-privileges flag (prevents setuid/setgid escalation)
$ docker run --security-opt no-new-privileges myapp

Container Security: Rootless and Read-Only

Running containers as root is unnecessary and violates the principle of least privilege. Podman's rootless mode runs containers entirely as an unprivileged user, significantly limiting the blast radius of a container escape.

Additional container hardening controls:

hardened container run
$ podman run \
  --read-only \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  --security-opt seccomp=/etc/seccomp/webapp.json \
  --tmpfs /tmp:rw,noexec,nosuid \
  -v /data/webapp:/app/data:ro \
  --user 1000:1000 \
  mywebapp:latest

Systemd Service Hardening

Sandboxing with Systemd Unit Directives

Systemd, the init system and service manager used on nearly all modern Linux distributions, includes a rich set of security sandboxing directives that apply directly to service unit files. These directives are frequently overlooked but represent some of the highest-value, lowest-friction Zero Trust controls available for Linux services. According to the Fedora Project's systemd hardening documentation: "systemd provides a number of settings that can harden security for services" including filesystem isolation, privilege restriction, and system call filtering. (Source: Fedora Project Wiki, Changes/SystemdSecurityHardening)

Systemd includes a built-in assessment tool: systemd-analyze security <service> returns a numeric exposure score from 0.0 (fully hardened) to 10.0 (UNSAFE). Rocky Linux's hardening guide documents that a default Apache httpd unit scores 9.2 UNSAFE out of the box; applying hardening directives can bring it to 4.9 OK. (Source: Rocky Linux Documentation, Systemd Units Hardening)

systemctl edit webapp.service (drop-in override)
# Create with: sudo systemctl edit webapp.service
# Saves to /etc/systemd/system/webapp.service.d/override.conf
[Service]
# Run as unprivileged dedicated user
User=webapp
Group=webapp

# Privilege isolation (highest impact, lowest breakage risk)
NoNewPrivileges=yes
PrivateTmp=yes

# Filesystem isolation
ProtectSystem=strict
ProtectHome=yes
PrivateDevices=yes
ReadWritePaths=/var/lib/webapp /var/log/webapp

# Kernel and control group protection
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes

# Network surface reduction
RestrictAddressFamilies=AF_INET AF_INET6

# Capability restrictions
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

# System call filtering
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources

# Misc sandboxing
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
$ systemd-analyze security webapp.service
Pro Tip: Audit All Running Services

Run systemd-analyze security without a service name to get exposure scores for every running unit. Services rated UNSAFE (7.0 or above) are candidates for immediate hardening. Apply directives incrementally using sudo systemctl edit <service>, which creates a drop-in override and never modifies vendor unit files. Start with NoNewPrivileges=yes and PrivateTmp=yes — these rarely cause breakage. Add other directives one at a time and test after each. (Sources: Linux Journal, "Systemd Service Hardening"; Fedora Project Wiki, SystemdSecurityHardening; Rocky Linux Documentation)

Kernel Hardening via sysctl

Security-Critical sysctl Parameters

The Linux kernel exposes runtime configuration through the sysctl interface. Many defaults prioritize compatibility over security. Hardening these parameters reduces the kernel's attack surface and limits information useful to attackers during exploit development. Settings are applied persistently by placing files in /etc/sysctl.d/. All parameters below are documented in the official Linux kernel documentation (kernel.org) or the cited sources.

/etc/sysctl.d/99-zerotrust.conf
# ── KERNEL SELF-PROTECTION ──

# Hide kernel pointer values from /proc and interfaces.
# Per kernel.org docs: kptr_restrict=2 replaces all kernel pointer
# values with 0s regardless of privilege, defeating exploit
# techniques that rely on kernel address knowledge.
# Source: kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html
kernel.kptr_restrict = 2

# Restrict dmesg to root only.
# Prevents unprivileged users from reading kernel log output
# which may contain pointer values and hardware information.
kernel.dmesg_restrict = 1

# Enable ASLR at full strength.
# Randomizes process memory layout to defeat address prediction.
kernel.randomize_va_space = 2

# Restrict eBPF to privileged users.
# Unprivileged eBPF has enabled numerous kernel privilege escalations.
kernel.unprivileged_bpf_disabled = 1

# Harden BPF JIT against heap spraying attacks.
net.core.bpf_jit_harden = 2

# Restrict ptrace to root (yama.ptrace_scope=2).
# Prevents user-space process inspection and injection.
# Source: obscurix.github.io/security/kernel-hardening.html
kernel.yama.ptrace_scope = 2

# Prevent live kernel replacement via kexec.
# kexec can bypass secure boot by loading a malicious kernel image.
kernel.kexec_load_disabled = 1

# Prevent setuid processes from creating core dumps.
# Core dumps may contain cleartext credentials and key material.
fs.suid_dumpable = 0

# ── NETWORK STACK HARDENING ──

# Reverse Path Filtering: block packets arriving on wrong interface.
# Prevents certain IP source address spoofing methods.
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable ICMP redirect acceptance.
# ICMP redirects can be used to manipulate routing tables.
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Disable sending ICMP redirects.
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Enable TCP SYN cookies to resist SYN flood DoS attacks.
net.ipv4.tcp_syncookies = 1

# Log packets with impossible source addresses (martians).
net.ipv4.conf.all.log_martians = 1
$ sudo sysctl -p /etc/sysctl.d/99-zerotrust.conf
User Namespace Restrictions: Trade-offs

A commonly recommended hardening measure is restricting unprivileged user namespaces. As the Linux Hardening Guide notes, user namespaces "expose significant kernel attack surface for privilege escalation." The sysctl kernel.unprivileged_userns_clone=0 disables them for unprivileged users but requires a kernel patch not available on all distributions. Alternatively, user.max_user_namespaces=0 disables them entirely, but this breaks Podman rootless containers, Flatpak, and bubblewrap. Evaluate against your workloads before enforcing. The settings above for kexec, ptrace, and BPF provide significant protection without these compatibility risks. (Sources: Linux Hardening Guide, madaidans-insecurities.github.io; kernel.org sysctl documentation)

Audit Logging and Continuous Monitoring

Linux Audit Framework

Zero Trust requires visibility. The Linux audit framework (auditd) provides comprehensive, tamper-resistant logging of security-relevant events. It operates at the kernel level, making it difficult for attackers to evade even after gaining user-space access.

auditd setup
# Install and enable
$ sudo apt install auditd audispd-plugins   # Debian/Ubuntu
$ sudo dnf install audit                    # RHEL/Fedora
$ sudo systemctl enable --now auditd

A Zero Trust audit configuration monitors identity changes, privilege use, sensitive file access, and network configuration changes. Add rules to /etc/audit/rules.d/zerotrust.rules:

/etc/audit/rules.d/zerotrust.rules
# Delete existing rules and set buffer size
-D
-b 8192

# Monitor authentication events
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k identity
-w /etc/sudoers.d/ -p wa -k identity

# Monitor SSH configuration
-w /etc/ssh/sshd_config -p wa -k sshd

# Monitor privilege escalation
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid!=0 -k privilege_esc

# Monitor network configuration changes
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k network_mods
-w /etc/network -p wa -k network_mods
-w /etc/hosts -p wa -k network_mods

# Monitor use of ptrace (indicator of process injection)
-a always,exit -F arch=b64 -S ptrace -k ptrace

# Lock rules (prevents modification without reboot)
-e 2

Log Forwarding and Centralization

Local logs are vulnerable to tampering by an attacker with sufficient access. Zero Trust requires that security logs be shipped to a remote, append-only log storage system in real time. rsyslog and journald both support secure log forwarding.

/etc/rsyslog.d/51-remote.conf
# Load TLS module
$DefaultNetstreamDriver gtls
$ActionSendStreamDriverAuthMode x509/name
$ActionSendStreamDriverPermittedPeer logs.company.internal
$ActionSendStreamDriverMode 1

# Forward all logs to SIEM
*.* @@(o)logs.company.internal:6514

File Integrity Monitoring

AIDE (Advanced Intrusion Detection Environment) creates a database of file checksums and attributes, then alerts when files are modified. This detects persistence mechanisms, backdoor installation, and configuration tampering.

AIDE setup
# Install AIDE
$ sudo apt install aide    # Debian/Ubuntu
$ sudo dnf install aide    # RHEL/Fedora

# Initialize the database
$ sudo aide --init
$ sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# Run a check
$ sudo aide --check

# Automate daily checks via cron
$ echo '0 3 * * * root aide --check | mail -s "AIDE Report" [email protected]' \
  >> /etc/crontab

Encryption at Rest and in Transit

Full Disk Encryption with LUKS

LUKS (Linux Unified Key Setup) is the standard for full disk encryption on Linux. It operates at the block device level, encrypting all data on the device transparently. For Zero Trust, LUKS ensures that physical access to hardware does not compromise data confidentiality.

LUKS encryption
# Encrypt a partition (destructive - back up data first)
$ sudo cryptsetup luksFormat /dev/sdb1

# Open the encrypted volume
$ sudo cryptsetup luksOpen /dev/sdb1 encrypted_data

# Create and mount a filesystem on the mapped device
$ sudo mkfs.ext4 /dev/mapper/encrypted_data
$ sudo mount /dev/mapper/encrypted_data /mnt/secure

# Add a key file for automated unlocking (store securely)
$ dd if=/dev/urandom bs=32 count=1 of=/etc/luks/keyfile
$ chmod 400 /etc/luks/keyfile
$ cryptsetup luksAddKey /dev/sdb1 /etc/luks/keyfile

TLS Everywhere

All inter-service communication must be encrypted. The days of unencrypted internal traffic are incompatible with Zero Trust. Even connections between services that trust each other must be encrypted because the network itself cannot be trusted.

Key TLS hardening principles:

TLS verification
# Test TLS connection and view certificate chain
$ openssl s_client -connect service.internal:443 -showcerts

# Check supported cipher suites
$ nmap --script ssl-enum-ciphers -p 443 service.internal

# Verify certificate expiration
$ openssl x509 -noout -dates -in /etc/ssl/certs/service.crt

Implementation Checklist

Implementing Zero Trust is a journey, not a destination. The following checklist provides a prioritized implementation roadmap organized by impact and complexity.

Phase 1: Foundation (Weeks 1-2)

Control Priority
[ ] Disable SSH password authentication, enable key-based auth only Critical
[ ] Enable SELinux/AppArmor in enforcing mode Critical
[ ] Implement default-deny nftables firewall policy Critical
[ ] Enable and configure auditd with Zero Trust ruleset Critical
[ ] Disable and remove unnecessary services High
[ ] Apply CIS Benchmark baseline configuration High
[ ] Implement full disk encryption on all endpoints High

Phase 2: Identity (Weeks 3-4)

Control Priority
[ ] Deploy SSH Certificate Authority for user authentication High
[ ] Implement MFA for all privileged access High
[ ] Restrict sudo to specific commands per user/role High
[ ] Remove unused local accounts and review group memberships High
[ ] Integrate with centralized identity provider (LDAP/SSSD) Medium

Phase 3: Monitoring and Response (Weeks 5-6)

Control Priority
[ ] Configure centralized log forwarding with TLS High
[ ] Deploy file integrity monitoring with AIDE High
[ ] Configure SIEM alerts for critical audit events High
[ ] Establish vulnerability scanning schedule Medium
[ ] Create incident response runbooks for Linux-specific scenarios Medium
[ ] Conduct purple team exercise to validate detection coverage Medium

Phase 4: Service and Kernel Hardening (Weeks 7-8)

Control Priority
[ ] Run systemd-analyze security on all services; harden units scoring UNSAFE (7.0+) High
[ ] Apply sysctl kernel hardening parameters (kptr_restrict, dmesg_restrict, rp_filter, etc.) High
[ ] Configure egress filtering via nftables output chain default-deny policy Medium
[ ] Verify package integrity with distribution signing keys; audit third-party repositories Medium
[ ] Evaluate and document user namespace restrictions based on workload requirements Medium

Conclusion

Zero Trust is not a product you can purchase and deploy. It is an architectural philosophy that must be systematically instantiated across every layer of your Linux environment. The primitives are available in the kernel and standard tools: mandatory access control, capability-based privilege separation, namespace isolation, cryptographic authentication, and comprehensive audit logging.

The implementations described in this guide represent battle-tested approaches to eliminating implicit trust from Linux infrastructure. Some of these controls, particularly SELinux and seccomp, require patience and careful policy development. Others, like SSH hardening and nftables firewall rules, can be implemented in hours with immediate security benefit.

The adversary does not rest. Nation-state threat actors, ransomware groups, and opportunistic attackers continuously probe Linux infrastructure. Zero Trust does not make your systems invulnerable, but it dramatically raises the cost of successful attack, limits the blast radius of compromise, and provides the visibility needed to detect and respond quickly.

Begin with Phase 1. Measure before and after. Build the feedback loop of continuous verification that Zero Trust demands. The journey is worth taking.

References and Further Reading